Initial robot pose at time
-
$l$ wheel separation -
$r$ wheel radius -
$\theta$ angular orientation of robot -
$\omega_R$ rotational speed of right wheel -
$\omega_L$ rotational speed of left wheel
The equations of differential kinematics are a combination of two equations which we can derive separately:
- linear and angular velocities of the robot in the robot reference frame, as a function of rotational speeds of the robot wheels. These equations allow sending velocity commands, in robot frame, to the robot.
- robot velocity in the world reference frame from velocity in robot frame (using the rotation matrix)
Hypotheses:
-
no slippage in wheel contact points: $ v_{R, L} = r . \omega_{R, L}$
-
CoG midpoint between wheels
Inverse equations:
We apply the rotation matrix
This 3x2 matrix is the Jacobian (??)
See Python_code_examples.md for the python code of a simple velocity controller (7.69) and CPP_code_examples.md for the C++ code (7.70)
Modify the launch file controller.launch.py
:
- add 3 arguments:
use_python
to toggle between python and cpp nodes,wheel_radius
andwheel_separation
- declare two nodes
simple_controller_py
andsimple_controller_cpp
with conditionsIfCondition
andUnlessCondition
, passing the parameterswheel_radius
andwheel_separation
-
build with
$ colcon build
-
In a second terminal, source and launch gazebo:
$ source install/setup.bash
$ ros2 launch bumperbot_description gazebo.launch.py
- In another terminal, source and launch the controller:
$ source install/setup.bash
$ ros2 launch bumperbot_controller controller.launch.py --show-args
Arguments (pass arguments as '<name>:=<value>'):
'use_python':
Whether to use Python or C++ nodes
(default: 'true')
'wheel_radius':
Wheel radius
(default: '0.033')
'wheel_separation':
Wheel separation
(default: '0.17')
- with the controller running, publish
TwistStamped
messages tobumperbot_controller/cmd_vel
to get the robot to move:
$ ros2 topic list
/bumperbot_controller/cmd_vel
/clock
/dynamic_joint_states
/joint_states
/parameter_events
/performance_metrics
/robot_description
/rosout
/simple_velocity_controller/commands
/tf
/tf_static
$ ros2 topic pub /bumperbot_controller/cmd_vel geometry_msgs/msg/TwistStamped "header:
stamp:
sec: 0
nanosec: 0
frame_id: ''
twist:
linear:
x: 0.1
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.5"
Create a launch file joystick_teleop.launch.py
that launches nodes:
joy_node
fromjoy
package, with parameters defined injoy_config.yaml
:
joystick:
ros__parameters:
device_id: 0
device_name: ""
deadzone: 0.5
autorepeat_rate: 0.0
sticky_buttons: false
coalesce_interval_ms: 1
- and
joy_teleop
fromjoy_teleop
package, with parameters defined injoy_teleop.yaml
:
joy_teleop:
ros__parameters:
move:
type: topic
interface_type: geometry_msgs/msg/TwistStamped
topic_name: bumperbot_controller/cmd_vel
deadman_buttons: [5]
axis_mappings:
twist-linear-x:
axis: 1
scale: 1.0
offset: 0.0
twist-angular-z:
axis: 3
scale: 1.0
offset: 0.0
Note this configuration works with my gamepad in Mode X:
-
fwd/backwards moving the left stick up/down
-
left/right rotation moving the right stick left/right
-
deadman button: RB (right index). Note: deadman button does not work properly
ros2 control libraries have a standard controller for differential drive robots
-
modify
bumperbot_controllers.yaml
to declare and configure a new node named e.g.bumperbot_controller
based ondiff_drive_controller/DiffDriveController
-
modify
controller.launch.py
to add an argumentuse_simple_controller
, true by default, which will toggle between using thesimple_controller
we wrote and the standarddiff_drive_controller
node we namedbumperbot_controller
. We useGroupAction
to launch on condition the group of nodes forsimple_controller
.
colcon build and in other terminals source and launch gazebo, the control system of the robot, and the joystick :
(T2): $ ros2 launch bumperbot_description gazebo.launch.py
(T3): $ ros2 launch bumperbot_controller controller.launch.py use_simple_controller:=false
(T4): $ ros2 launch bumperbot_controller joystick_teleop.launch.py
it works!