Mobile robot tele-operation using ROS2 and ros2_canopen

New task

Recently, I was assigned a new task: to enable teleoperation for a compact mobile robot. This little bot boasts two motorized wheels (equipped with Maxon EPOS4 motors) and a set of caster wheels. In the preceding months, my colleagues have installed ROS2 (Humble) on the robot’s onboard computer. They also git cloned the ros2_canopen stack and attempted to control the robot using the “diff_drive_controller” — following the example “Pilz Manipulator PRBT 6” in the official documentation of ros2_canopen. Despite their efforts, the robot remained stubbornly stationary.

Then, the torch has been passed to me. I’ve been asked to continue this work, unravel the mystery, and breathe life into our mini mobile marvel. Let’s get those wheels turning!

Image description

Embarking on this task, I delved into the ros2_canopen documentation. Candidly, it wasn’t the most user-friendly read. Consequently, I found myself occasionally spelunking through the source code to grasp its concepts, overall structure, and various parameter configurations.

Next, I created a package called single_epos4_canopen — a modest creation aimed at controlling a solitary Epos4 motor using ros2_canopen. My inspiration? Well, this lightweight package sidesteps high-level features like ros2_control and robot description. Instead, it zeroes in on the nitty-gritty: CAN communication debugging.

With single_epos4_canopen in action, I managed to make wheel rotate by calling ros2 service call /single_motor/target canopen_interfaces/srv/COTargetDouble “{ target: 10.0 }” service (thanks to our default “velocity mode”). Ahoy, success! This, at least, confirms that our CAN network is fine.

And when it’s time to halt the motion, ros2 service call /single_motor/halt std_srvs/srv/Trigger does the trick. Similarly I can call nmt_state_reset service to restart the NMT of the node whose Heartbeat is configured to be sent every 1000ms.

CanOpen frames analysis

Thanks to the single_epos4_canopen package, I can monitor and analyze the CanOpen frames by calling

1
candump can0 

(sorry I was not allowed to share the images).

By conducting tests on respectively each CanOpen node and checking carefully the CanOpen frames, I found that issues come from the OD definitions. Updating the wrong OD entries via Epos Studio finally fixed those issues.

Use ros2_control with ros2_canopen

By following this example, I created the package for controlling both motors with help of diff_drive_controller in ros2_control. After having been struggling with the configurations and tests for multiple days, and by making some workaround to fix errors in some function for handling init, finally I can control the robot with joystick:

Simulation

Afterward, I spent 2 more days to update the robot description file, added some gazebo control and sensor plugins and make the simulated bot tele-operable in Gazebo simulator via “teleop_twist_keyboard”:

Future work

For some reason, this project has been paused, though I would like to continue to achieve autonomous navigation and fleet control on this robot. Probably there will be no more updates about future developments :(