Recorded in RViz. MoveIt 2 plans a path to the goal pose set with the interactive marker, then executes it.
| Robot | SO-101 (LeRobot) arm, 5 arm joints plus gripper |
| Actuators | 6 Feetech ST3215 serial bus servos, 12-bit encoders (4096 ticks/rev) |
| Connection | USB serial bus adapter on the Linux host |
| Middleware | ROS 2 Jazzy, ros2_control, controller_manager at 100 Hz |
| Motion planning | MoveIt 2 (move_group), RViz MotionPlanning panel |
| Hardware interface | Custom C++ SystemInterface plugin, servo driver linked in-process |
| Modes | Real hardware or mock hardware, switched with one launch argument |
| Automation | C++ startup node using MoveGroupInterface to run named poses on launch |
The goal was simple to state: when I plan and execute a motion in RViz, the physical arm should follow. The SO-101 had a URDF and a servo driver, but nothing that connected MoveIt 2 to the real servos. I wrote that layer as a ros2_control hardware plugin and brought the arm up end to end.
hardware_interface::SystemInterface plugin that reads and writes all six ST3215 servos directly, with no bridge node in between.mode:= argument.MoveGroupInterface to move through two named poses automatically after launch.The physical arm follows the motion planned in RViz on the laptop beside it.
$(eval ...) stops at the first closing bracket. I traced this in the xacro source and switched to the ${...} form.