ROS 2 Electronics Stack for a 4-Wheel Mecanum Drive Robot
Complete bridge between ROS 2 navigation software and embedded motor controllers for an autonomous vehicle โ inverse/forward kinematics, serial handshake protocol, and IMU integration.
- Overview
- System Architecture
- Hardware
- ROS 2 Nodes
- ROS Topics
- Serial Communication Protocol
- Firmware
- Directory Structure
- Getting Started
- Usage
- Maintainer
The AV Elec Stack is the electronics and software backbone for a mecanum-wheeled autonomous vehicle. It provides:
- Inverse kinematics โ converts
cmd_vel(Twist) into individual wheel angular velocities (ฯ) - Forward kinematics โ converts encoder feedback back into body velocities for odometry
- MCU serial bridge โ reliable handshake-based communication with Teensy 4.1 motor controllers
- ESP32 camera/Z-axis bridge โ serial interface for a Z-axis stepper + theta motor subsystem
- IMU integration โ BNO055 9-DOF IMU data (roll, pitch, yaw + linear acceleration)
graph LR
subgraph "ROS 2 (Host PC)"
JOY["๐ฎ Joystick\n(joy_node)"]
NAV["๐งญ Nav Stack\n(Software)"]
V2O["vel_to_omega\n(Inverse Kinematics)"]
MCU["mcu_feedback\n(Serial Bridge)"]
FWD["forward_kinematics\n(Forward Kinematics)"]
JOY -- "/cmd_vel" --> V2O
NAV -- "/cmd_vel" --> V2O
V2O -- "/omegas" --> MCU
MCU -- "/omega" --> FWD
FWD -- "/fdb_cmd_vel" --> NAV
MCU -- "/imu/data" --> NAV
end
subgraph "Hardware"
T41["Teensy 4.1\n(Motor + IMU)"]
ESP["ESP32\n(Z-axis + Theta)"]
M1["Motor 1 (FL)"]
M2["Motor 2 (FR)"]
M3["Motor 3 (RL)"]
M4["Motor 4 (RR)"]
IMU["BNO055 IMU"]
ZAX["Z-Axis Stepper"]
end
MCU <-- "USB Serial\n9600 baud" --> T41
T41 -- "Modbus ASCII\n(Serial1-8)" --> M1
T41 --> M2
T41 --> M3
T41 --> M4
T41 <--> IMU
ESP <-- "USB Serial" --> ESP_NODE["esp_feedback\n(Serial Bridge)"]
ESP --> ZAX
| Component | Model | Role |
|---|---|---|
| Main MCU | Teensy 4.1 | 4-motor control via Modbus ASCII + BNO055 IMU |
| Aux MCU | ESP32 | Z-axis stepper + theta motor (camera positioning) |
| IMU | Adafruit BNO055 | 9-DOF orientation & linear acceleration (IยฒC on Wire1) |
| Motor Drivers | Modbus ASCII VFDs | 4ร BLDC/induction motors at 9600 baud |
| Wheels | Mecanum (100mm radius) | 4-wheel omnidirectional drive |
| Parameter | Value |
|---|---|
Wheel radius (a) |
0.10 m |
Wheelbase length (L) |
0.444 m |
Track half-width (D) |
0.184 m |
Subscribes to /cmd_vel (Twist) and computes individual wheel angular velocities using mecanum inverse kinematics:
ฯ_FL = (1/a) ร (Vx - Vy - (L+D) ร ฯz)
ฯ_FR = (1/a) ร (Vx + Vy + (L+D) ร ฯz)
ฯ_RL = (1/a) ร (Vx + Vy - (L+D) ร ฯz)
ฯ_RR = (1/a) ร (Vx - Vy + (L+D) ร ฯz)
Includes configurable velocity scaling factors (vx_multiplier = 22.03, etc.) to match the real robot's capabilities.
Publishes: Float32MultiArray on /omegas โ [FL, FR, RL, RR]
The main communication bridge between ROS and the Teensy 4.1.
- Subscribes to
/omegasโ sends#ฯ1 ฯ2 ฯ3 ฯ4*to Teensy over USB serial - Receives
$rpm1 rpm2 rpm3 rpm4 imu_data&from Teensy - Publishes wheel speeds on
/omegaand IMU data on/imu/data - Implements a handshake protocol on startup (see Serial Protocol)
- Auto-reconnects on serial failure
Serial Port: /dev/serial/by-id/usb-Teensyduino_USB_Serial_18632580-if00
Converts encoder-measured wheel angular velocities back into body-frame velocities:
Vx = (r/4) ร (ฯFL + ฯFR + ฯRL + ฯRR)
Vy = (r/4) ร (-ฯFL + ฯFR + ฯRL - ฯRR)
ฯz = (r / 4(L+W)) ร (-ฯFL + ฯFR - ฯRL + ฯRR)
Includes a complementary filter (ฮฑ = 0.85) for noise smoothing.
Publishes: Twist on /fdb_cmd_vel
| Topic | Type | Direction | Description |
|---|---|---|---|
/cmd_vel |
geometry_msgs/Twist |
Input | Commanded body velocities |
/omegas |
std_msgs/Float32MultiArray |
Internal | Wheel ฯ commands โ MCU |
/omega |
std_msgs/Float32MultiArray |
Internal | Wheel ฯ feedback โ MCU |
/imu/data |
std_msgs/Float32MultiArray |
Output | IMU data from BNO055 |
/fdb_cmd_vel |
geometry_msgs/Twist |
Output | Feedback body velocities |
/camera_pose |
std_msgs/Float32MultiArray |
Input | Z-axis + theta commands |
/Z_axis_height |
std_msgs/Float32MultiArray |
Internal | Height commands to ESP32 |
/Z_axis_software |
std_msgs/Float32MultiArray |
Input | Height setpoint from software |
Teensy โ PC: "Started\n" (repeated every 500ms)
PC โ Teensy: "++\n" (acknowledgement)
Teensy โ PC: "Received acknowledgement"
โ data exchange begins
If data arrives before handshake: PC sends "--\n" to request restart.
| Direction | Format | Example |
|---|---|---|
| PC โ Teensy | #val1 val2 val3 val4*\n |
#120.5 -85.3 120.5 -85.3* |
| Teensy โ PC | $val1 val2 val3 val4 imu...&\n |
$100 95 100 95 0.5 -0.3 9.8& |
Uses Modbus ASCII protocol at 9600 baud over Serial1/2/7/8:
| Command | Modbus Hex | Description |
|---|---|---|
| Enable CW | 010600020101 |
Clockwise rotation |
| Enable CCW | 010600020109 |
Counter-clockwise rotation |
| Brake | 010600020103 |
Active braking |
| Disable | 010600020100 |
Motor off |
| Set Frequency | 01060006XXXX |
Set speed (freq = 14ร4รRPM/60) |
Production firmware for the Teensy 4.1:
- Controls 4 motors via Modbus ASCII on Serial1, Serial2, Serial7, Serial8
- Reads BNO055 IMU over IยฒC (Wire1)
- Implements the handshake protocol for reliable startup
- Receives wheel ฯ commands, sets motor direction and RPM
- Sends back motor RPM feedback + IMU orientation data
- Supports software reboot command (
'R')
Production firmware for the ESP32 Z-axis controller:
- Stepper motor control for vertical (Z) positioning
- 28BYJ-48 stepper for theta (angle) rotation
- Limit switch homing with ISR-based crash detection
- Accepts height + angle commands via serial
- Auto-homes on power-up and after crash events
AV_Elec_Stack/
โโโ firmware/
โ โโโ teensy/
โ โ โโโ FinalTeensy.ino # Teensy 4.1 motor + IMU firmware
โ โโโ esp32/
โ โโโ ESP32Code.ino # ESP32 Z-axis controller firmware
โโโ src/
โ โโโ elecstack/
โ โโโ elecstack/ # Python ROS 2 nodes
โ โ โโโ __init__.py
โ โ โโโ mcu_feedback.py # Teensy serial bridge node
โ โ โโโ vel_to_omega.py # Inverse kinematics node
โ โ โโโ forward_kinematics.py# Forward kinematics node
โ โ โโโ esp_feedback.py # ESP32 serial bridge node
โ โ โโโ Zaxis_reading.py # Z-axis height relay node
โ โ โโโ Z_axis_testing.py # Z-axis serial test node
โ โ โโโ testing_node.py # Debug/test publisher node
โ โโโ launch/
โ โ โโโ elec.launch.py # Main launch (mcu_feedback + vel_to_omega)
โ โ โโโ joylaunch.py # Dual joystick launch
โ โโโ test/ # Linting & style tests
โ โโโ package.xml
โ โโโ setup.py
โ โโโ setup.cfg
โโโ README.md
- ROS 2 Humble (Ubuntu 22.04)
- Python 3.10+
pyserial(pip install pyserial)
# Clone the repository
git clone https://github.com/your-username/AV_Elec_Stack.git
# Navigate to your ROS 2 workspace
cd ~/ros2_ws/src
ln -s /path/to/AV_Elec_Stack/src/elecstack .
# Build
cd ~/ros2_ws
colcon build --packages-select elecstack
source install/setup.bash- Teensy 4.1: Open
firmware/teensy/FinalTeensy.inoin Arduino IDE / PlatformIO with Teensyduino. Select Board โ Teensy 4.1, upload. - ESP32: Open
firmware/esp32/ESP32Code.inoin Arduino IDE. Select Board โ ESP32 Dev Module, upload.
# Launch MCU feedback + inverse kinematics
ros2 launch elecstack elec.launch.py
# (Optional) Launch dual joystick nodes
ros2 launch elecstack joylaunch.py# Send a velocity command
ros2 topic pub /cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 0.5, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"
# Monitor wheel omegas
ros2 topic echo /omegas
# Monitor feedback velocities
ros2 topic echo /fdb_cmd_velMadhav Pradheep โ madhavpradeep2207@gmail.com
Built with โค๏ธ for autonomous mobility
This project is open source. See LICENSE for details.