Reactive Move
The goal is to create a straight
node that permits the robot to move straight until obstacles are detected
then turn left or right to avoid the obstacle.
Node Structure
The straight
node is our first real complex node.
It will process scan messages to characterize the local environment and regularly send coherent move instructions.
That for, we want to set up a node with \(2\) callback function. A sensing callback and a control callback. In facts, it is not recommended to send control messages only went sensing messages are received. This way, the robot will be capable of dealing failures as interruption in the sensing messages.
So, the straight
script will be structured like this:
#!/usr/bin/python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
from geometry_msgs.msg import Twist
import sys
# Ros Node process:
def main():
# Initialize ROS and a ROS node
rclpy.init(args=sys.argv)
node= Node( 'basic_move' )
# Initialize our control:
control= StraightCtrl()
control.initializeRosNode( node )
# infinite Loop:
rclpy.spin( node )
# clean end
node.destroy_node()
rclpy.shutdown()
# Ros Node Class:
class StraightCtrl :
def initializeRosNode(self, rosNode ):
# Get logger from the node:
self._logger= rosNode.get_logger()
# Initialize publisher:
self._pubVelocity= rosNode.create_publisher(
Twist, '/multi/cmd_nav', 10
)
# Initialize scan callback:
self._subToScan= rosNode.create_subscription(
LaserScan, '/scan',
self.scan_callback, 10
)
# Initialize control callback:
self._timForCtrl= rosNode.create_timer(
0.05, self.control_callback
)
def scan_callback(self, scanMsg ):
self._logger.info( '> get scan' )
def control_callback(self):
self._logger.info( '< define control' )
# Go:
if __name__ == '__main__' :
main()
Include your straight
node into your package, and test it:
ros2 run tutorial_pkg straight
Scan Callback
Implement the scan_callback
method in a way that it fills \(2\) boolean class variables: self.obstacle_left
and self.obstacle_right
.
The self._obstacle_left
should be True
if an obstacle is detected front-left of the robot and Flase
else.
The self._obstacle_right
should be True
if an obstacle is detected front-right of the robot and Flase
else.
We consider obstacles only if there are at \(1\) meter or less to the robot.
Control Callback
Implement the control_callback
method in a way that it sent velocity message coherent with the presence of obstacles on the left and/or right side of the robot.
The move straight until an obstacle is found in a range of 1 meter in front of it (self.obstacle_left
or self.obstacle_right
is True
).
The robot rotate with a positive or negative value depending on which of the obstacle variable is true.
For security reason, the control should not send velocity messages while scan messages were not received and should stop if scan message stop.
Smart Control
At this point, the control is defined on \(4\) states, with on/off velocity control.
The states are :
state | action |
---|---|
no scan | empty |
no obstacle | go straight |
left obstacle | turn right |
right obstacle | turn left |
both obstacle | turn left |
As a side effect, the robot behavior is not really efficient. First we can increase the state definition to handle more possibilities.
For instance, if the robot faces a both obstacle situation while it is turning right (i.e. avoiding a left obstacle ) it would be more interesting to continue to turn on the same direction. For that the robot state should remenber the last performed action.
Another example would be to differentiate close and distant obstacles to apply different control velocities (move and turn in a same time while possible), and generate fluid trajectories.
Finally, the desired speed can be reached with several steps, to force a soft acceleration.