Machine Vision
Versions to run the exercise
Currently, there are 2 versions for running this exercise:
- ROSNode Templates
- Web Templates(In Development)
The instructions for both of them are provided as follows.
Goal
The goal of this exercise is to learn how to use vision to assist industrial robot by detecting known objects and unknown obstacles. You will need to complete pick and place task using a robot arm and vacuum gripper. Two kinect camera, one fixed to the world and another one fixed to the robot end effector, will be provided. The shape, size and color of the objects are known, but the pose of them and the situation of obstacles in surrounding environment need to be found using two cameras.
Instructions
This is the preferred way for running the exercise once it is finished.
Installation
-
Download Docker. Windows users should choose WSL 2 backend Docker installation if possible, as it has better performance than Hyper-V.
-
Pull the current distribution of RoboticsBackend
docker pull jderobot/robotics-backend:2.4.2
-
In order to obtain optimal performance, Docker should be using multiple CPU cores. In case of Docker for Mac or Docker for Windows, the VM should be assigned a greater number of cores.
Enable GPU Acceleration
- For Linux machines with NVIDIA GPUs, acceleration can be enabled by using NVIDIA proprietary drivers, installing VirtualGL and executing the following docker run command:
docker run --rm -it --device /dev/dri -p 7164:7164 -p 2303:2303 -p 1905:1905 -p 8765:8765 -p 6080:6080 -p 1108:1108 jderobot/robotics-backend:2.4.2 ./start.sh
- For Windows machines, GPU acceleration to Docker is an experimental approach and can be implemented as per instructions given here
How to perform the exercise?
-
Start a new docker container of the image and keep it running in the background (hardware accelerated version)
docker run --rm -it -p 7164:7164 -p 2303:2303 -p 1905:1905 -p 8765:8765 -p 6080:6080 -p 1108:1108 jderobot/robotics-backend:2.4.2 ./start.sh
-
On the local machine navigate to 127.0.0.1:7164/ in the browser and choose the desired exercise.
-
Click the connect button and wait for some time until an alert appears with the message
Connection Established
and button displays connected. -
The exercise can be used after the alert.
Where to insert the code?
In the launched webpage, type your code in the text editor,
from GUI import GUI
from HAL import HAL
# Enter sequential code!
while True:
# Enter iterative code!
Using the Interface
-
Control Buttons: The control buttons enable the control of the interface. Play button sends the code written by User to the Robot. Stop button stops the code that is currently running on the Robot. Save button saves the code on the local machine. Load button loads the code from the local machine. Reset button resets the simulation(primarily, the position of the robot).
-
Brain and GUI Frequency: This input shows the running frequency of the iterative part of the code (under the
while True:
). A smaller value implies the code runs less number of times. A higher value implies the code runs a large number of times. The numerator is the one set as the Measured Frequency who is the one measured by the computer (a frequency of execution the computer is able to maintain despite the commanded one) and the input (denominator) is the Target Frequency which is the desired frequency by the student. The student should adjust the Target Frequency according to the Measured Frequency. -
RTF (Real Time Factor): The RTF defines how much real time passes with each step of simulation time. A RTF of 1 implies that simulation time is passing at the same speed as recal time. The lower the value the slower the simulation will run, which will vary depending on the computer.
-
Pseudo Console: This shows the error messages related to the student’s code that is sent. In order to print certain debugging information on this console. The student can use the
print()
command in the Editor.
Robot API
from HAL import HAL
- to import the HAL(Hardware Abstraction Layer) library class. This class contains the functions that sends and receives information to and from the Hardware(Gazebo).from GUI import GUI
- to import the GUI(Graphical User Interface) library class. This class contains the functions used to view the debugging information, like image widgets.HAL.back_to_home()
- Command the robot arm and gripper to move back to the home pose.HAL.pickup()
- to set the linear speedHAL.place()
- to set the angular velocityHAL.move_pose_arm(pose_goal)
- Command the robot with Pose message to make its end effector frame move to the desired pose with inverse kinematics.HAL.move_joint_hand(joint_value)
- Command the gripper joint to move to desired joint value.HAL.start_color_filter(color, rmax, rmin, gmax, gmin, bmax, bmin)
- Start color filter for the given color with RGB range for this color. Two messages, $(color)_filter(pointcloud) and $(color)_filtered_image (RGB image), will be published until stopping with stop_color_filter function. Range of RGB value is [0, 255].HAL.stop_color_filter(color)
- Stop the color filter of the given color.HAL.start_shape_filter(color, shape, radius)
- Start the shape filter to detect one set of pointcloud that can represent the input shape and has a smaller than input radius size from color filtered pointcloud. If the filter can detect a possible shape from pointcloud, two messages, color_shape(pointcloud) and color_shape_image(depth image), will be published until stopping with stop_shape_filter function. A frame called color_shape will be added in tf tree. The origin of the frame is the center of predicted sphere center of a point in the center axis of predicted cylinder. The unit of radius is meter(m).HAL.stop_shape_filter(color, shape)
- Stop shape filter.HAL.get_object_position(color, shape)
- If a frame named with color_shape exists in the tf tree, output is the transformation from this frame to world frame. If not, output is None.HAL.get_object_position(object_name)
- If a frame named with color_shape exists in tf tree, output is the transformation from this frame to world frame. If not, output is None.HAL.get_target_position(target_name)
- Return the position of target where we are going to place the objects.
Instructions for ROSNode Templates
Installation
- Install the General Infrastructure of the JdeRobot Robotics Academy.
- Install PCL and octomap related packages
sudo apt-get install ros-melodic-octomap-ros sudo apt-get install ros-melodic-octomap-msgs sudo apt-get install ros-melodic-octomap-rviz-plugins sudo apt install libpcl-dev sudo apt-get install ros-melodic-perception-pcl
- Install Industrial Robot package
If you have done this part in other Industrial Robots exercises, you can skip to next section.
mkdir -p catkin_ws/src cd catkin_ws/src
after pull request to the industrial robot repo
git clone https://github.com/JdeRobot/IndustrialRobotics.git -b melodic_devel cd ..
Update ROS dependencies
rosdep update rosdep check --from-paths . --ignore-src --rosdistro melodic rosdep install --from-paths . --ignore-src --rosdistro melodic -y
Build workspace
catkin build
Export environment variables
echo 'source '$PWD'/devel/setup.bash' >> ~/.bashrc echo 'export GAZEBO_MODEL_PATH=${GAZEBO_MODEL_PATH}:'$PWD'/src/IndustrialRobotics/assets/models' >> ~/.bashrc source ~/.bashrc
How to run the exercise
TO launch the exercise, open a terminal windows, navigate to machine_vision
folder inside exercises
folder and execute following command:
roslaunch machine_vision.launch
Three different windows will pop up:
- Gazebo simulator: A warehouse environment with a industrial robot(robot arm and gripper), multiple objects, two kinect cameras, a conveyor, a table and a box will be shown in Gazebo.
- Rviz: Robot arm, cameras, model of objects, the pointcloud of fixed camera and the octomap build from the pointcloud of camera on robot will be shown in Rviz.
- Industrial robot teleoperator: A GUI which provides following functionalities:
- A Forward Kinematics teleoperator providing sliders to change the angle of each joint of the robot arm and the gripper. The limits of each joints are shown in the two sides of the slider. The true angle of the joints are shown in the text box beside the sliders.
- An Inverse Kinematics teleoperator allowing users to set the desired end effector pose.
- Plan button can plan the trajectory to the desired pose
- Execute button can make the robot execute the planned trajectory
- Plan & Execute button is the integration of last two buttons
- Stop button allows users to stop the robot
- Back to home button can make the robot move back to home pose
- Two update button can update the value of current robot state
- Code Manager part
- Four buttons to start, stop, pause and restart the main code you program
- One button to launch Rviz
- One button to Respawn all objects in Gazebo and Rviz
- An info box showing the status of the main code(“start” or “stop”)
- Camera viewer
- Two combo boxes to choose image topics to show in below image windows
- Two image windows to show chosen image topics
Then open a new terminal window, navigate to machine_vision
folder inside exercises
folder and execute following command:
python MyAlgorithm.py
You can start running the algorithm with the start button when you see You can start your algorithm with GUI
in the terminal.
How should I solve the exercise
To solve the exercise, you must edit the MyAlgorithm.py file and insert control logic in myalgorithm() function. Before writing the main logic, you should implement build_map() function to detect obstacles in surrounding environments and get_object_position() function to detect the position of the objects.
def build_map(self):
############## Insert your code here ###############
self.pick_place.send_message("Building map")
####################################################
def get_object_position(self, object_name):
############## Insert your code here ###############
return position
####################################################
def myalgorithm(self):
############## Insert your code here ###############
self.build_map()
# Move the robot back to home as a start
self.pick_place.back_to_home()
# insert following two lines where you want to pause or stop the algorithm
# with the stop button in GUI
while (not self.pauseevent.isSet()) or (not self.stopevent.isSet()):
if not self.stopevent.isSet():
return
##### A brief example to pick and place object "green_cylinder" #####
# get object position and pick it up
# parameters HEIGHT_OFFSET need to be tuned according to the object height
# Height offset between robot base and conveyor is 0.2m
object_name = "green_cylinder"
position = self.get_object_position(object_nam)
self.pick_place.pickup(object_name, position)
# setup stop signal detector
while (not self.pauseevent.isSet()) or (not self.stopevent.isSet()):
if not self.stopevent.isSet():
return
# choose target position and place the object
target_name = "target6"
position = self.pick_place.get_target_position(target_name)
self.pick_place.place(object_name, position)
####################################################
Multiple APIs can be used to implement your algorithm. They are provided in Pick_Place class, so you should always add “self.pick_place.” as a prefix to following introduced APIs in your algorithm.
API
Detect Object
start_color_filter(color, rmax, rmin, gmax, gmin, bmax, bmin)
- Start color filter for givencolor
with RGB range for thiscolor
. Two messages,$(color)_filter
(pointcloud) and$(color)_filtered_image
(RGB image), will be published until stopping withstop_color_filter
function. Range of RGB value is [0, 255]stop_color_filter(color)
- Stop the color filter for givencolor
.start_shape_filter(color, shape, radius)
- Start the shape filter to detect one set of pointcloud that can represent the inputshape
and has a smaller than inputradius
size from color filtered pointcloud. If the filter can detect a possible shape from pointcloud, two messages,$(color)_$(shape)
(pointcloud) and$(color)_$(shape)_image
(depth image), will be published until stopping withstop_shape_filter
function. A frame called$(color)_$(shape)
will be added in tf tree. The origin of the frame is the center of predicted sphere center of a point in the center axis of predicted cylinder. The unit of radius is meter(m)stop_shape_filter(color, shape)
- Stop the shape filter.get_object_position(color, shape)
- If a frame named with$(color)_$(shape)
exists in tf tree, output is the transformation from this frame to world frame. If not, output is None.
Environment Information
get_object_list()
- Return the name list of all objects.get_object_info(object_name)
- Return the height, width, length, shape, color of the object in order.get_target_list()
- Return the name list of all targets.get_target_position(target_name)
- Return the position of target where we are going to place the objects.
Convert Pose Message
pose2msg(roll, pitch, yaw, x, y, z)
- Convert pose to Pose message. The unit of roll, pitch, yaw is radian.pose2msg_deg(roll, pitch, yaw, x, y, z)
- Convert pose to Pose message. The unit of roll, pitch, yaw is degree.msg2pose(pose)
- Convert Pose message to pose, return roll, pitch, yaw, x, y, z in order. The unit of roll, pitch, yaw is radian.msg2pose_deg(pose)
- Convert Pose message to pose, return roll, pitch, yaw, x, y, z in order. The unit of roll, pitch, yaw is degree.
Basic Robot Movement
move_pose_arm(pose_goal)
- Command the robot with Pose message to make its end effector frame move to the desired pose with inverse kinematics.move_joint_arm(joint_0,joint_1,joint_2,joint_3,joint_4,joint_5)
- Command the robot joints to move to desired joints valueback_to_home()
- Command the robot arm and gripper to move back to the home pose.gripper_grasp()
- Turn on the vacuum gripper.gripper_release()
- Turn off the vacuum gripper.
Pick and Place
pickup(object_name, position[, distance])
- Command the industrial robot to pick up the object by moving the end effector to given position. Distance is the distance the robot arm will move in z axis before and after grasping objects.place(object_name, position[, distance])
- Command the industrial robot to place the object by moving the end effector to given position. Distance is the distance the robot arm will move in z axis before and after placing objects.
Theory
Object Detection
In this exercise, object detectors are implemented based on Point Cloud Library(PCL). It is an opensource point cloud processing library. There are multiple methods to detect the pose of known objects with vision. The method we choose here is fully based on pointcloud.
Assume that we only know the color, size and shape(sphere or cylinder) of the object we want to pick. Firstly, a color filter will filter out all points that are not inside chosen RGB range. Secondly, a shape segmentation will be done to find points that have the highest possibility to be a part of chosen shape and size. Some parameters about this possible shape will also be provided by the segmentation filter. With these information, we are able to find the position of sphere or cylinder.
Obstacle Detection and Avoidance
In Pick and Place
exercise, we have introduced that objects in planning scene will be considered as obstacles when doing motion planning to avoid collision. Obstacles are known and added into planning scene in that exercise, but what if we have no information about the surrounding environment? Obstacle detection will be necessary.
Obstacle detection can be done using many different sensors. What we use in this exercise is kinect camera which provides rgb image, depth image and pointcloud. Pointcloud from camera is what we finally use to build the obstacle map. Pointcloud contains the position of points and points can represent obstacles. If we merging these points and representing each of them with small cube, we will build a simplified map with obstacles in planning scene.
Hints
How to write buildmap() function:
The pointcloud from the camera fixed to the robot will be automatically monitored occupancy_map_monitor/PointCloudOctomapUpdater
to update the planning scene, so what you have to do is move the robot around and make sure that the camera fixed to the robot can take image of all surrounding environment inside robot workspace.
How to write get_object_position() function:
- Get the color, shape and size of the object.
- Choose RGB range for the color filter and start it. Check the color filter result with image viewer or Rviz and tune parameters to get better result.
- Choose the radius for the shape filter and start it. Check the shape filter result and tune parameters to get better result.
- Check the position output from
get_object_position
API. - Return the position of detected object when getting a relatively stable object position.
Note: Please remember to stop the color filter and shape filter after getting the object position. If too many filters are running at the same time, you might not be able to get a stable result.
How to check the result of color filter and shape filter?
Two image windows are provided in GUI. You can choose corresponding topic to check the result. All filtering process are done with pointcloud. The image is the projection of the pointcloud. From the image side, the expected result for color filter is that only the part with your chosen RGB value will be shown with original color in the image. All filtered out parts are black. The expected for shape filter is that only the points related to the detected shape will be shown with non-black color in the image. If nothing is detected, the whole image is black or you won’t see the image change from the previously chosen image. Here are the results(topic: “green_filtered_image” and “green_cylinder_image” of detecting green cylinder.
To view 3D pointcloud, you need to launch Rviz and change the topic of Poindcloud to the topic you want to check. If nothing is detected, you will see nothing new in Rviz after choosing the topic. Here are the pointcloud results(topic: “yellow_filter” and “yellow_cylinder”) of detecting yellow cylinder.
Limitation of vacuum gripper
Because the simulation of vacuum gripper is not perfect in this exercise, the robot sometimes cannot plan a path to place the object to target position or may drop the object on its way to target. Please take successfully building map and picking up desired objects as the sign of success.
Ignorable ERROR and WARNING
No p gain specified for pid.
gazebo_ros_vacuum_gripper: already status is 'off'
Following three errors can be ignored in the beginning, but if it keep spawning when you run your algorithm or move the robot with GUI, please relaunch the exercise.
The complete state of the robot is not yet known. Missing gripper_joint, gripper_joint1, gripper_joint2, gripper_joint3, gripper_joint4, gripper_joint5, gripper_joint6, gripper_joint7, gripper_joint8
Transform error: "vacuum_gripper5" passed to lookupTransform argument source_frame does not exist.
Transform cache was not updated. Self-filtering may fail.
Object and Target lists:
Object list:
- red_ball
- green_ball
- blue_ball
- yellow_ball
- red_cylinder
- green_cylinder
- blue_cylinder
- yellow_cylinder
Target list: target_ID, ID are integers from 1 to 16