Wheel Control
This section covers the two packages for direct ROS2 wheel control of the ballbot:
ballbot_balancing_pid— Reference PID balancing controller (reads IMU, closes the balance loop, outputs wheel commands)enchanted_wheel_commands_test— Raw wheel velocity test node (for verifying the full stack end-to-end)
Important: Run on the robot, not from a remote computer
These nodes must be launched directly on the robot.
They rely on low-latency communication with Legend's internal controller. Running them remotely via Zenoh introduces network jitter that degrades control performance and can cause unsafe behaviour.
Zenoh is not required when running these nodes on the robot — they communicate directly over the local ROS2 DDS network.
Prerequisites
Before running either node, make sure:
- The robot is running with the
vokarinabridge active (travel launched on the robot). - The bridge is configured with the
wheel_commandsandwheel_source_selectiontopic mappings (traveldevbranch or later). - Legend's
WheelCommandRouteris active (legenddevbranch or later). - The robot is in User Control Mode with joints enabled (via Wizard → Debug window).
I. Wheel Commands Test Node
Use this node to verify that the full wheel command stack is working before running the PID controller.
Launch
source install/setup.bash
ros2 launch enchanted_wheel_commands_test wheel_commands_test.launch.py
What it does
- Waits 500 ms for publisher connections.
- Switches wheel control source to ROS (
ros_control=true). - Sends cyclic ±velocity commands to all 3 wheels at 50 Hz.
- After
duration_seconds, stops the wheels and hands control back to Legend.
Parameters
| Parameter | Default | Description |
|---|---|---|
velocity_a/b/c |
0.5 | Wheel velocities (rad/s) |
cycle_period |
2.0 | Full cycle duration (positive + negative phase) in seconds |
duration_seconds |
30 | Total test duration in seconds |
switch_to_ros |
true | If false, sends commands without switching source (dry-run) |
II. Ballbot Balancing PID Controller
Real robot only. This node does not apply to simulation.
Reference PID balancing controller. Reads IMU orientation, runs independent roll/pitch PID loops, converts trunk velocity commands to wheel velocities using the ballbot kinematic model, and publishes them via the bridge.
Quick start
# 1. Launch (starts DISABLED for safety)
ros2 launch ballbot_balancing_pid balancing.launch.py
# 2. Put the robot on the ring stand
# 3. Enable
ros2 topic pub --once /balancing_pid_node/enable std_msgs/msg/Bool "data: true"
# 4. Disable
ros2 topic pub --once /balancing_pid_node/enable std_msgs/msg/Bool "data: false"
Safety
- Node starts disabled. Must be explicitly enabled.
- If trunk tilt exceeds
max_tilt_rad(0.23 rad / ~13°), wheel commands stop immediately. - Control resumes only when tilt drops below
min_tilt_rad(0.065 rad / ~3.7°). - Source switch is blocked if any wheel velocity > 0.001 rad/s — always switch on the ring stand.
- On disable: wheels are zeroed before handing control back to Legend.
III. ROS2 Topics
Published by the control nodes
| Topic | Type | Description |
|---|---|---|
/commands/wheels |
enchanted_msgs/ExtendedJointState |
Wheel velocity commands (wheel_a, wheel_b, wheel_c) |
/commands/wheels/ros_control |
std_msgs/Bool |
Source switch: true = ROS control, false = Legend internal |
Subscribed by the control nodes
| Topic | Type | Description |
|---|---|---|
/imu |
sensor_msgs/Imu |
IMU orientation (from bridge) — balancing PID only |
~/enable |
std_msgs/Bool |
Enable/disable — balancing PID only |
IV. Zenoh configuration (remote computer only)
Skip this section if you are running the nodes on the robot.
Zenoh is only needed if you want to send wheel commands from an external computer to the robot over the network. This is not the recommended workflow for control — use it only for monitoring or debugging from a remote machine.
If you do need remote access, add the following topics to the Zenoh allow list on the robot:
install/share/travel/configs/enchanted_bringup/zenoh.json5
Add these two topics to the allow → publishers / subscribers sections:
"/commands/wheels",
"/commands/wheels/ros_control"
Or remove the allow block entirely to let all topics through (less secure, fine for development).