I am an employee of a sanatorium in the world-famous resort area of the Caucasus Mineral Waters, Russia. Health resorts in the post-pandemic period are subject to increased requirements for the safety of holidaymakers. It is mandatory to treat rooms for disinfection from microbes (including COVID) using UV lamps. These works should be carried out in a way that does not allow people to be exposed to radiation. We are going to use this robot, which will be controlled by the operator remotely and disinfect the room with UV lamps without irradiating employees.
The robot has 2 modes:
1) control from a remote computer via a web interface
controlling the movement of the platform and web-camera
2) control using a wireless joystick
As a robot, we used the design for Turtlebot 1 on the iRobot create moving platform.
Turtlebot 1 is not currently supported by the manufacturer, so we will build the software again. At robot and at the operator's workplace, we will use laptops with OS Ubuntu 16.04 (Ubuntu) operating system. Install the ROS Kinetic framework on it (http://wiki.ros.org/kinetic/Installation/Ubuntu). Robot Operating System (ROS) is a framework widely used in robotics. The ROS philosophy is to create software that works with various robots, with only minor changes in the code. This idea allows you to create functionality that can be transferred effortlessly for use by various robots.
Step 1. Install the ROS framework on your computer and the remote operatorInstallation is performed on 2 laptops.
Due to the fact that installing the Manual on the official ROS website leads to errors, install according to the instructions below.
update source
sudo apt-get update
Configure ros source
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo sh -c '. /etc/lsb-release && echo "deb [arch=amd64] http://mirrors.ustc.edu.cn/ros/ubuntu/ $DISTRIB_CODENAME main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
Install ros
ROS, rqt, rviz, robot-generic libraries, 2D/3D simulators, navigation and 2D/3D perception
sudo apt-get update
sudo apt-get install ros-kinetic-desktop-full
Initialize rosdep
Before you can use ROS, you will need to initialize rosdep. rosdep enables you to easily install system dependencies for source you want to compile and is required to run some core components in ROS.
sudo rosdep init
rosdep update
Environment setup
echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
source ~/.bashrc
Dependencies for building packages
sudo apt-get install python-rosinstall python-rosinstall-generator python-wstool build-essential
Before you can use many ROS tools, you will need to initialize rosdep. rosdep enables you to easily install system dependencies for source you want to compile and is required to run some core components in ROS. If you have not yet installed rosdep, do so as follows.
sudo apt install python-rosdep
With the following, you can initialize rosdep.
sudo rosdep init
rosdep update
Test install
roscore
At work (ip 192.168.2.111), enter the following data at the end of the ~/.bashrc file:
source /opt/ros/kinetic/setup.bash
export ROS_HOSTNAME="192.168.2.111"
export ROS_MASTER_URI="http://192.168.2.111:11311"
At operator position ((ip 192.168.2.112)):
source /opt/ros/kinetic/setup.bash
export ROS_HOSTNAME="192.168.2.112"
export ROS_MASTER_URI="http://192.168.2.111:11311"
Step 2. Creating a catkin workspace.Creating a catkin workspace. Catkin is enabled by default when installing ROS.
mkdir -p ~ /catkin_ws/src
cd ~/satlink_ws/
catkin_make
Step 3. Installing the ROS driver for managing the iRobot Create moving platformTo control the moving iRobot Create platform from ROS you need to install the driver (https://github.com/AutonomyLab/create_autonomy)
Clone this repo
cd ~/create_ws/src
git clone https://github.com/AutonomyLab/create_autonomy.git
Install dependencies
cd ~/create_ws
rosdep update
rosdep install --from-paths src -i
Build
cd ~/create_ws
catkin build
In order to connect to Create over USB, ensure your user is in the dialout group
sudo usermod -a -G dialout $USER
Logout and login for permission to take effect
Running the driver
source ~/create_ws/devel/setup.bash
Connect computer to Create 1 DB-25 port
Launch file
roslaunch ca_driver create_1.launch
Step 4. Creating your own project in catkinCreating your own project in catkin
cd ~/catkin_ws/src
In this case, we specify the dependencies-std_msgs rospy roscpp
catkin_create_pkg tod_robot1 std_msgs rospy roscpp
You can add dependencies later
Then compile
cd ~/catkin_ws
catkin_make
Step 5. Control the robot using a wireless joystickTo support the joystick in ROS you must install the joy and joy_teleop packages.
ROS package joy-the joystick driver is already installed in the system. By default, the joy package uses the /dev/input/js0 device. If your joystick has a different name (for example, /dev/input/js 1), you must install the joy_node/dev parameter on the parameter server before running the package:
rosparam set joy_node/dev "/dev/input/js 1"
After installing the packages, we can control the robot's movement using a joystick
Create the main 21.launch command file on your computer
<launch>
<!-- iRobot create -->
<arg name="config" default="$(find ca_driver)/config/default.yaml" />
<arg name="desc" default="true" />
<node name="ca_driver" pkg="ca_driver" type="ca_driver" output="screen">
<rosparam command="load" file="$(arg config)" />
<param name="robot_model" value="CREATE_1" />
</node>
<include if="$(arg desc)" file="$(find ca_description)/launch/create_1.launch" />
<!-- joystick -->
<arg name="joy_dev" default="/dev/input/js0" />
<arg name="joy_config" default="xbox360" />
<arg name="teleop_config" default="$(find ca_tools)/config/$(arg joy_config).yaml" />
<rosparam file="$(arg teleop_config)" command="load" />
<node pkg="joy" type="joy_node" name="joy_node">
<param name="dev" value="$(arg joy_dev)" />
<param name="deadzone" value="0.2" />
<param name="autorepeat_rate" value="20" />
</node>
<node pkg="joy_teleop" type="joy_teleop.py" name="joy_teleop">
</node>
</launch>
Remotely via ssh or on the robot's computer, run 2 terminals:
1)
roscore
2)
cd catkin_ws
source devel/setup.bash
roslaunch td_robot1 main21.launch
And control the robot using a wireless joystick
Step 6. Connecting web camerasInstall support for usb cameras in ROS.
Looking at cameras in the system
lsusb
ls /dev | grep video*
Install the ROS usb_cam node with the necessary dependencies:
sudo apt-get update
sudo apt-get install rus-kinetic-usb-ca
the usb_cam node already has a startup test file:
cat /opt/ros/kinetic/share/usb_com/launch/usb_cam-test.launch
Before running this file, let's run the ROS
roscore
and now run the usb_cam node on the slave:
roslaunch usb_cam usb_cam-test.launch
To see themes in the terminal:
rostopic list
reading the data of the camera using image_view:
rosrun image_view image_view image:=/usb_cam/image_raw
streaming to the web
Installing the ROS web video server node:
sudo apt-get install ros-kinetic-web-video-server
Step 7. Installing a web server at robotInstall a web server on your robot laptop to control the robot from the remote operator's workplace. Installing Apache in Ubuntu:
sudo apt-get install apache2
After installation, add the program to auto-upload:
sudo systemctl enable apache2
And launch the web server:
sudo systemctl start apache2
Without the php programming language, installing and configuring LAMP in Ubuntu will not be complete. PHP is the most popular programming language in the web. Install PHP 7 in Ubuntu 16.04 with the following command:
sudo apt-get install php 7.0-mysql php 7.0-curl php7. 0-json php 7.0-cgi php 7.0 libapache2-mod-php 7.0
If you want to install all available PHP modules so that there are no problems in the future, you can run the command:
sudo apt-get install php*
Step 8. Installing the rockbridge ROS packageRosbridge provides a JSON API to ROS functionality for non-ROS programs. There are a variety of front ends that interface with rosbridge, including a WebSocket server for web browsers to interact with. Rosbridge_suite is a meta-package containing rosbridge, various front end packages for rosbridge like a WebSocket package, and helper packages.
There's two parts to rosbridge: the protocol and the implementation.
The rosbridge protocol a specification for sending JSON based commands to ROS (and in theory, any other robot middleware). An example of the protocol for subscribing to a topic:
{ "op": "subscribe",
"topic": "/cmd_vel",
"type": "geometry_msgs/Twist"
}
The specification is programming language and transport agnostic. The idea is that any language or transport that can send JSON can talk the rosbridge protocol and interact with ROS. The protocol covers subscribing and publishing topics, service calls, getting and setting params, and even compressing messages and more.
The rosbridge_suite package is a collection of packages that implement the rosbridge protocol and provides a WebSocket transport layer.
Installing Rosbridge
Rosbridge depends on a basic installation of ROS. After ROS is installed, you can install Rosbridge from a.deb package:
sudo apt-get install ros-<rosdistro>-rosbridge-suite
This will install the suite of rosbridge packages needed to get started.
Running Rosbridge
After installing ROS and rosbridge, you need to make sure your system is aware of the packages. To set up your environment for ROS and rosbridge:
source /opt/ros/kinetic/setup.bash
All that's left is to run rosbridge. To launch rosbridge and its packages like rosbridge_server and rosapi, a launch file is included in the install. To launch the file, run:
roslaunch rosbridge_server rosbridge_websocket.launch
This will run rosbridge and create a WebSocket on port 9090 by default.
Step 9. Creating a page for rossbridge (controlling the movement of the platform and web-camera)Creating a page index13.html
In the /var/www/html folder
On the page, the nipplejs virtual joystick for sending messages to the subject /cmd_vel (robot movement control), as well as streaming images from camera
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="js/roslib.min.js"></script>
<script type="text/javascript" src="js/nipplejs.js"></script>
<script type="text/javascript" type="text/javascript">
var ip="192.168.2.111";
var ros = new ROSLIB.Ros({
url : 'ws://'+ip+':9090'
});
ros.on('connection', function() {
document.getElementById("status").innerHTML = "Connected";
});
ros.on('error', function(error) {
document.getElementById("status").innerHTML = "Error";
});
ros.on('close', function() {
document.getElementById("status").innerHTML = "Closed";
});
var txt_listener = new ROSLIB.Topic({
ros : ros,
name : '/txt_msg',
messageType : 'std_msgs/String'
});
txt_listener.subscribe(function(m) {
document.getElementById("msg").innerHTML = m.data;
});
cmd_vel_listener = new ROSLIB.Topic({
ros : ros,
name : "/cmd_vel",
messageType : 'geometry_msgs/Twist'
});
move = function (linear, angular) {
var twist = new ROSLIB.Message({
linear: {
x: linear,
y: 0,
z: 0
},
angular: {
x: 0,
y: 0,
z: angular
}
});
cmd_vel_listener.publish(twist);
}
createJoystick = function () {
var options = {
zone: document.getElementById('zone_joystick'),
threshold: 0.1,
position: { left: 50 + '%' },
mode: 'static',
size: 150,
color: '#000000',
};
manager = nipplejs.create(options);
linear_speed = 0;
angular_speed = 0;
manager.on('start', function (event, nipple) {
timer = setInterval(function () {
move(linear_speed, angular_speed);
}, 25);
});
manager.on('move', function (event, nipple) {
max_linear = 1.0; // m/s
max_angular = 1.0; // rad/s
max_distance = 75.0; // pixels;
linear_speed = Math.sin(nipple.angle.radian) * max_linear * nipple.distance/max_distance;
angular_speed = -Math.cos(nipple.angle.radian) * max_angular * nipple.distance/max_distance;
});
manager.on('end', function () {
if (timer) {
clearInterval(timer);
}
self.move(0, 0);
});
}
window.onload = function () {
//createJoystick();
}
function set_ip()
{
ip=document.getElementById("ip").value;
ros.close();
ros = new ROSLIB.Ros({
url : 'ws://'+ip+':9090'
});
alert("new ip - "+ip);
if(ros.isConnected === true)
{document.getElementById("status").innerHTML = "Connected";}
else
{document.getElementById("status").innerHTML = "Closed";}
var obj=document.getElementById("choice_camera");
//alert(obj.value);
new_camera(obj.value);
}
function new_camera(topic)
{
alert(topic);
document.getElementById("camera_robot").src="http://"+ip+":8080/stream?topic="+topic;
}
</script>
</script>
</head>
<body onload='createJoystick();new_camera(document.getElementById("choice_camera").value);'>
<h1>Simple ROS User Interface</h1>
<p>Connection status: <span id="status"></span></p>
<p>Last /txt_msg received: <span id="msg"></span></p>
<div id="zone_joystick" style="position: relative;"></div>
<form id=formoptions name=formoptions action="javascript:void();" onsubmit="return false;">
<select name=choice_camera id=choice_camera onchange='new_camera(this.value)'>
<option value="/usb_cam1/image_raw"> /usb_cam1/image_raw
<option value="/usb_cam0/image_raw"> /usb_cam0/image_raw
</select>
<input type='text' name='ip' id='ip' value='192.168.2.111' onchange='set_ip();'>
</form>
<img id=camera_robot src="">
</body>
</html>
Create the main 22.launch command file on your computer
<launch>
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch"/>
<!-- iRobot create -->
<arg name="config" default="$(find ca_driver)/config/default.yaml" />
<arg name="desc" default="true" />
<node name="ca_driver" pkg="ca_driver" type="ca_driver" output="screen">
<rosparam command="load" file="$(arg config)" />
<param name="robot_model" value="CREATE_1" />
</node>
<include if="$(arg desc)" file="$(find ca_description)/launch/create_1.launch" />
<!-- camera -->
<node name="web_video_server1" pkg="web_video_server" type="web_video_server">
</node>
<node name="usb_cam0" pkg="usb_cam" type="usb_cam_node" output="screen" >
<param name="video_device" value="/dev/video0"></param>
<param name="image_width" value="320"></param>
<param name="image_height" value="240"></param>
<param name="pixel_format" value="yuyv"></param>
<param name="camera_frame_id" value="usb_cam"></param>
<param name="io_method" value="mmap"></param>
</node>
</launch>
Remotely via ssh or on the robot's computer, run 2 terminals:
1)
roscore
2)
cd catkin_ws
source devel/setup.bash
roslaunch td_robot1 main22.launch
And control the movement of the platform and web-camera from a remote computer via a web interface
We will control the UV lamp from the Arduino controller via a relay.
To connect Arduino to ROS (to receive and send messages in ROS), you must install the rosserial_arduino package.
$ sudo apt-get install ros-kinetic-rosserial-arduino
$ sudo apt-get install ros-kinetic-rosserial
To launch the package, define the connection port of the Arduino Board
The start-up of package arduino-rus serial
rosrun rosserial_python serial_node.py /dev/ttyACM0
To write a sketch on Arduino (get a message from the ROS topic and turn on / off the UV lamp via a relay), you need to install the rosserial library in the Arduino IDE.
Sketch of getting a message from the topic /setUF for turning on / off the UV lamp
// rosserial
#include <ros.h>
#include <std_msgs/Int32.h>
ros::NodeHandle nh;
void messageCb( const std_msgs::Int8& toggle_msg) {
if(toggle_msg.data==1) {
digitalWrite(8,HIGH);
}
else {
digitalWrite(8,LOWH);
}
}
ros::Subscriber<std_msgs::Float32> sub("setUF", &messageCb );
void setup() {
pinMode(18, OUTPUT);
digitalWrite(8,LOW);
nh.initNode();
nh.subscribe(sub);
}
void loop() {
nh.spinOnce();
delay(1000);
}
Step 11. Starting the robota page for rossbridge
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="js/roslib.min.js"></script>
<script type="text/javascript" src="js/nipplejs.js"></script>
<script type="text/javascript" type="text/javascript">
var uf=0;
var ip="192.168.2.111";
var ros = new ROSLIB.Ros({
url : 'ws://'+ip+':9090'
});
ros.on('connection', function() {
document.getElementById("status").innerHTML = "Connected";
});
ros.on('error', function(error) {
document.getElementById("status").innerHTML = "Error";
});
ros.on('close', function() {
document.getElementById("status").innerHTML = "Closed";
});
var UF = new ROSLIB.Topic({
ros : ros,
name : '/setUF',
messageType : 'std_msgs/Int8'
});
cmd_vel_listener = new ROSLIB.Topic({
ros : ros,
name : "/cmd_vel",
messageType : 'geometry_msgs/Twist'
});
move = function (linear, angular) {
var twist = new ROSLIB.Message({
linear: {
x: linear,
y: 0,
z: 0
},
angular: {
x: 0,
y: 0,
z: angular
}
});
cmd_vel_listener.publish(twist);
}
var UF = new ROSLIB.Topic({
ros : ros,
name : '/setUF',
messageType : 'std_msgs/Int8t'
});
createJoystick = function () {
var options = {
zone: document.getElementById('zone_joystick'),
threshold: 0.1,
position: { left: 50 + '%' },
mode: 'static',
size: 150,
color: '#000000',
};
manager = nipplejs.create(options);
linear_speed = 0;
angular_speed = 0;
manager.on('start', function (event, nipple) {
timer = setInterval(function () {
move(linear_speed, angular_speed);
}, 25);
});
manager.on('move', function (event, nipple) {
max_linear = 1.0; // m/s
max_angular = 1.0; // rad/s
max_distance = 75.0; // pixels;
linear_speed = Math.sin(nipple.angle.radian) * max_linear * nipple.distance/max_distance;
angular_speed = -Math.cos(nipple.angle.radian) * max_angular * nipple.distance/max_distance;
});
manager.on('end', function () {
if (timer) {
clearInterval(timer);
}
self.move(0, 0);
});
}
window.onload = function () {
//createJoystick();
}
function set_ip()
{
ip=document.getElementById("ip").value;
ros.close();
ros = new ROSLIB.Ros({
url : 'ws://'+ip+':9090'
});
alert("new ip - "+ip);
if(ros.isConnected === true)
{document.getElementById("status").innerHTML = "Connected";}
else
{document.getElementById("status").innerHTML = "Closed";}
var obj=document.getElementById("choice_camera");
//alert(obj.value);
new_camera(obj.value);
}
function new_camera(topic)
{
alert(topic);
document.getElementById("camera_robot").src="http://"+ip+":8080/stream?topic="+topic;
}
function change_UF()
{
uf=1-uf;
alert(uf);
if(uf===1)
{document.getElementById("button_uf").style.background="blue";
document.getElementById("button_uf").innerText="UF ON";
UF.publish({'data':1});
}
else
{document.getElementById("button_uf").style.background="transparent";
document.getElementById("button_uf").innerText="UF OFF";
UF.publish({'data':0});
}
}
</script>
</script>
</head>
<body onload='createJoystick();new_camera(document.getElementById("choice_camera").value);'>
<h1>Simple ROS User Interface</h1>
<p>Connection status: <span id="status"></span></p>
<p>Last /txt_msg received: <span id="msg"></span></p>
<div><button id="button_uf" onclick="change_UF();">UF OFF</div>
<div id="zone_joystick" style="position: relative;"></div>
<form id=formoptions name=formoptions action="javascript:void();" onsubmit="return false;">
<select name=choice_camera id=choice_camera onchange='new_camera(this.value)'>
<option value="/usb_cam1/image_raw"> /usb_cam1/image_raw
<option value="/usb_cam0/image_raw"> /usb_cam0/image_raw
</select>
<input type='text' name='ip' id='ip' value='192.168.2.111' onchange='set_ip();'>
</form>
<img id=camera_robot src="">
</body>
</html>
Create the main23.launch command file on your computer
<launch>
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch"/>
<!-- iRobot create -->
<arg name="config" default="$(find ca_driver)/config/default.yaml" />
<arg name="desc" default="true" />
<node name="ca_driver" pkg="ca_driver" type="ca_driver" output="screen">
<rosparam command="load" file="$(arg config)" />
<param name="robot_model" value="CREATE_1" />
</node>
<include if="$(arg desc)" file="$(find ca_description)/launch/create_1.launch" />
<!-- camera -->
<node name="web_video_server1" pkg="web_video_server" type="web_video_server">
</node>
<node name="usb_cam0" pkg="usb_cam" type="usb_cam_node" output="screen" >
<param name="video_device" value="/dev/video0"></param>
<param name="image_width" value="320"></param>
<param name="image_height" value="240"></param>
<param name="pixel_format" value="yuyv"></param>
<param name="camera_frame_id" value="usb_cam"></param>
<param name="io_method" value="mmap"></param>
</node>
// arduino
<node name="serial_node" pkg="rosserial_python" type="serial_node.py">
<param name="port" value="/dev/ttyACM0"/>
<param name="baud" value="57600" />
</node>
</launch>
Remotely via ssh or on the robot's computer, run 2 terminals:
1)
roscore
2)
cd catkin_ws
source devel/setup.bash
roslaunch tod_robot1 main23.launch
And control the robot
Comments