Wiznet makers

Grace_Koo

Published May 13, 2026 ©

61 UCC

25 WCC

9 VAR

0 Contests

0 Followers

0 Following

Original Link

ORION_VI_PROPULSION_SYSTEM

Open-source rover propulsion system using ESP32 + WIZnet W5500, controlling four ODrive motors over CAN bus via MQTT.

COMPONENTS Hardware components

WIZnet - W5500

x 1


PROJECT DESCRIPTION

Rover Propulsion System Powered by ESP32 and W5500 — ORION VI

In One Sentence

"A propulsion and steering control system for a six-wheeled rover, built by a Polish university engineering team — receiving MQTT commands over ESP32 + W5500 Ethernet and controlling four ODrive motor controllers in real time via CAN bus."

A rover is a wheeled robotic vehicle designed to traverse rough terrain. The concept originates from NASA's planetary exploration missions, and university teams around the world now design and compete with their own rover builds. Events like the European Rover Challenge are a driving force behind projects like this one. ORION VI, developed by team KN Microchip, is a product of that same engineering culture.

One of the trickiest parts of building a remotely operated rover is network communication. Latency means delayed steering; a dropped connection means the rover must stop. The ORION VI Propulsion System addresses this with an ESP32 and WIZnet W5500 Ethernet chip combination — an open-source project that keeps control reliable under field conditions.

KN Microchip is a student engineering team at Politechnika Lubelska (Lublin University of Technology), Poland. The project currently has 62 commits and 2 forks.


Key Concept

What is ODrive? ODrive is an open-source high-performance motor driver for BLDC and brushless servo motors. It receives velocity and position commands over CAN bus and closes the control loop using encoder feedback. It's widely used in robotics, rovers, and CNC systems.


Hardware Setup

The rover's left and right drivetrain each run on an independent ESP32 + W5500 module. Each ESP32 controls two ODrive units (front and rear) over CAN, and handles two steering servos as well.

ComponentModel / InterfaceRole
MCUESP32Main controller
EthernetWIZnet W5500 (SPI)Dedicated MQTT communication
Motor driversODrive × 2 (Front / Rear)BLDC motor velocity control
Communication busCAN 2.0B (500 kbps)ESP32 ↔ ODrive
SteeringServo motors × 2Independent front and rear steering
SensorsACS712 (current), ADC (voltage)Servo health monitoring
Ground station softwarePython (Tkinter + pygame)Operator dashboard

Pin Map (ESP32 ↔ W5500):

SignalESP32 GPIO
SPI SCKGPIO 18
SPI MISOGPIO 19
SPI MOSIGPIO 23
CS (Chip Select)GPIO 5
RESETGPIO 27

System Architecture and Data Flow

Generated by Gemini

Features

MQTT Control Protocol

The operator PC publishes JSON packets to the propulsion/cmd topic at 20 Hz. Each packet carries velocity (RPS) and steering angle (rad) for all four wheels simultaneously.

{
  "eventType": "propulsion",
  "velocity": {
    "fl_speed": 12.5,  "rl_speed": 12.5,
    "fr_speed": 12.5,  "rr_speed": 12.5,
    "fl_rad": 0.5,     "rl_rad": -0.5,
    "fr_rad": 0.5,     "rr_rad": -0.5
  }
}

The ESP32 publishes telemetry in the opposite direction every 100 ms, including per-wheel velocity and position, plus servo current and voltage.

Ackermann Steering Geometry

Rather than applying a simple left/right steering value, the ground station calculates the precise steering angle for each wheel using the Ackermann formula. This ensures the inner and outer wheels turn at different angles through a corner, minimizing slip.

# Calculated in the Python ground station
fl_rad = math.atan((s * L) / (2 + s * W))
fr_rad = math.atan((s * L) / (2 - s * W))
rl_rad = -fl_rad
rr_rad = -fr_rad

Steering Servo PID Control

Applying abrupt PWM jumps to a high-torque servo can strip the gears. The ESP32 firmware uses a software PID controller to limit the steering rate.

  • Maximum steering velocity: 0.5 rad/s (STEER_MAX_VEL)
  • Maximum steering angle: ±1.0 rad (MAX_STEER_RAD)
  • Anti-windup included (integral clamped to ±1.0 rad)

Safety System

LayerMechanismTrigger
MQTT WatchdogESP32 internal timerFull stop if no command for 1000 ms
Emergency BrakeL2 + R2 simultaneouslyImmediate velocity = 0, ramp mode disabled
Connection RecoveryW5500 hard reset after 5 failuresUnstable MQTT connection

The W5500 reset logic is particularly noteworthy. Rather than simply retrying the MQTT connection, five consecutive failures trigger a call to initNetwork(), which physically resets the W5500 via GPIO 27 (LOW → HIGH) and reinitializes the full Ethernet stack from scratch. This allows network recovery in the field without cutting power.


The Role of WIZnet W5500

The W5500 does more than provide an Ethernet port in this system.

Hardwired TCP/IP stack Network processing is offloaded entirely to the chip, freeing the ESP32 CPU to handle CAN bus traffic, PID computation, and ADC sensor reads in parallel without introducing latency into MQTT communication.

Bidirectional real-time communication Incoming commands (propulsion/cmd) and outgoing telemetry (propulsion/feedback_*) operate simultaneously on the same connection — 20 Hz control commands and 10 Hz telemetry coexisting without interference.

Self-recovery via hard reset

void initNetwork() {
  pinMode(ETH_RST_PIN, OUTPUT);
  digitalWrite(ETH_RST_PIN, LOW);  delay(100);
  digitalWrite(ETH_RST_PIN, HIGH); delay(200);
  SPI.begin(SPI_SCK_PIN, SPI_MISO_PIN, SPI_MOSI_PIN, ETH_CS_PIN);
  Ethernet.init(ETH_CS_PIN);
  Ethernet.begin(mac, ip);
  // ...
}

5 failed MQTT connections → initNetwork() re-called → W5500 physically reset via GPIO → full Ethernet stack reinitialized. Network recovery in the field without a power cycle.


Ground Station Software

A Python-based operator dashboard is included. A separate Steam Deck build (Base_ApplicationSteamDeck) is also available for outdoor field operations.

  • Real-time velocity gauge and graph (Matplotlib)
  • Per-ODrive monitoring for all four units (RPS, position, servo current, packet age)
  • Latency estimator (cross-correlates command publish time with encoder feedback)
  • Network status indicators (MQTT broker, rover, ground station TCP health LEDs)
  • Joystick / Steam Deck pad / keyboard input support

Extensibility

Splitting the left and right drivetrain into independent ESP32 + W5500 modules makes the architecture easy to scale. The same hardware configuration is reused for both sides — only the CURRENT_SIDE macro in config.h differs between the two builds. The same pattern can be extended to additional modules or adapted to different robot platforms without restructuring the codebase.


Tech Stack Summary

ComponentDetails
MCUESP32 (Xtensa LX6, 240 MHz)
EthernetWIZnet W5500 (Hardwired TCP/IP, SPI)
Firmware languageC++ (Arduino IDE / PlatformIO)
Motor driver communicationCAN 2.0B, 500 kbps, ODrive Simple CAN v3.6/v4
Message brokerMQTT (paho, port 1883)
Data formatJSON (ArduinoJson)
Ground station languagePython 3.10+
Ground station librariesTkinter, Matplotlib, paho-mqtt, pygame
LicenseMIT

FAQ

Q. Both ESP32 modules subscribe to the same MQTT topic — how are commands kept separate? A. The control topic (propulsion/cmd) is shared, but the JSON packet contains per-wheel keys (fl_speed, fr_speed, etc.). The left ESP32 only parses fl_speed, rl_speed, fl_rad, and rl_rad; the right parses the fr_* and rr_* equivalents. Which side a module belongs to is determined at compile time by the CURRENT_SIDE macro in config.h.

Q. How does the system recover when the W5500 connection becomes unstable? A. After five consecutive MQTT connection failures, the firmware calls initNetwork() rather than just retrying the client. This physically resets the W5500 by toggling GPIO 27 LOW then HIGH, and reinitializes the full Ethernet stack from scratch — all without a power cycle.

Q. Can CAN bus and Ethernet run on the same ESP32 simultaneously? A. Yes. The W5500 exclusively uses the SPI bus (GPIO 18/19/23/5), while the CAN transceiver uses separate pins (GPIO 25/26). Because the W5500's hardwired TCP/IP stack handles all network processing at the chip level, the ESP32 CPU remains free for CAN packet handling, PID computation, and ADC reads without contention.


Project Links

Documents
Comments Write