Lesson 20 - 3-Axis Velocity Control
Learning Objective
- Publish custom 3-axis velocity vectors using
bot.move(linear_x, linear_y, angular_z). - Combine linear translation and angular rotation to create smooth curved trajectories.
- Understand how velocity vectors map to ROS 2
/cmd_vel(geometry_msgs/Twist) topics.
Introduction
Directional shortcuts like move_forward drive in straight lines. However, complex mobile robot motion (such as navigating smooth curves or executing spiral trajectories) requires specifying simultaneous linear translation and angular rotation.
This lesson covers driving with bot.move(linear_x, linear_y, angular_z).
Code
import time
from bonicbot_bridge import BonicBot
with BonicBot(host="192.168.29.52") as bot:
print("1. Driving forward in a smooth arc to the left...")
# linear_x = 0.3 m/s forward, angular_z = 0.4 rad/s counter-clockwise
bot.move(linear_x=1, linear_y=0.0, angular_z=55)
time.sleep(2.5)
print("2. Driving backward while curving right...")
# linear_x = -0.2 m/s backward, angular_z = -0.3 rad/s clockwise
bot.move(linear_x=-1.5, linear_y=0.0, angular_z=-55)
time.sleep(2.0)
print("3. Pure in-place rotation...")
bot.move(linear_x=0.0, linear_y=0.0, angular_z=360)
time.sleep(1.5)
print("4. Halting robot...")
bot.stop()[!NOTE] Before running the code, make sure to replace
"192.168.29.52"with your BonicBot’s actual IP address.
Expected Output
Click to see expected output
🔧 Under the Hood
How move() constructs ROS 2 Twist messages
move() constructs ROS 2 Twist messagesMotionController.move() packs vector components into a geometry_msgs/Twist JSON payload:
msg = {
"linear": {"x": linear_x, "y": linear_y, "z": 0.0},
"angular": {"x": 0.0, "y": 0.0, "z": angular_z}
}It publishes this message directly to the /cmd_vel ROS 2 topic.
Student Challenge
Challenge 1 — Python Only
Write a function generate_arc_cmd(radius_meters, linear_speed) that computes the required angular_z turn rate for a given turn radius radius_meters and linear_speed.
Click to see solution
def generate_arc_cmd(radius_meters, linear_speed):
# angular_speed = linear_speed / radius
angular_z = linear_speed / radius_meters
return {"linear_x": linear_speed, "angular_z": angular_z}
cmd = generate_arc_cmd(radius_meters=1.5, linear_speed=0.3)
print("Arc velocity vector:", cmd)Challenge 2 — Robot
Drive the robot in an “S-curve” pattern: 2 seconds curving left (linear_x=0.3, angular_z=0.4), followed immediately by 2 seconds curving right (linear_x=0.3, angular_z=-0.4), then stop.
Click to see solution
import time
from bonicbot_bridge import BonicBot
with BonicBot(host="192.168.0.188") as bot:
print("Executing left curve...")
bot.move(linear_x=0.3, angular_z=0.4)
time.sleep(2.0)
print("Executing right curve...")
bot.move(linear_x=0.3, angular_z=-0.4)
time.sleep(2.0)
bot.stop()Quick Reference
Vector Parameters
| Parameter | Type | Unit | Description |
|---|---|---|---|
linear_x | float | m/s | Forward (+) or Backward (-) translation speed |
linear_y | float | m/s | Lateral translation speed (0 for differential drive) |
angular_z | float | rad/s | Counter-clockwise (+) or Clockwise (-) rotation |
Reflection Questions
What happens to a differential drive robot if you specify linear_y != 0 in bot.move()?
How does varying linear_x while keeping angular_z constant change the turning radius of the robot?