---
title: "Why Does a W5500 Ethernet Link Carry ROS 2 Drive Commands in the ULSTU Buggy?"
url: "https://maker.wiznet.io/Benjamin/projects/why-does-a-w5500-ethernet-link-carry-ros-2-drive-commands-in-the-ulstu-buggy/"
markdown_url: "https://maker.wiznet.io/Benjamin/projects/why-does-a-w5500-ethernet-link-carry-ros-2-drive-commands-in-the-ulstu-buggy/md"
type: "UCC: User Created Content"
author: "Ulyanovsk State Technical University (ULSTU)"
author_url: "https://github.com/ulstu/buggy-learn"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "Ulyanovsk State Technical University (ULSTU)"
original_url: "https://github.com/ulstu/buggy-learn"
license: "MIT license (MIT)"
published: "2026-08-27"
language: "en"
tags: ["W5500", "ESP32", "Linux"]
hardware: ["WIZnet W5500"]
likes: 0
views: 132
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# Why Does a W5500 Ethernet Link Carry ROS 2 Drive Commands in the ULSTU Buggy?

> ULSTU put a W5500 on the ESP32 board of its Ackermann teaching robot, so a Jetson AGX Xavier sends JSON-RPC drive commands and reads IMU data over wired UDP.

Original author: Ulyanovsk State Technical University (ULSTU) (source: https://github.com/ulstu/buggy-learn)

## Components

- **WIZnet W5500** x 1: Ethernet controller on the ULSTU low-level control board. Carries ROS 2 drive commands from a Jetson AGX Xavier to the ESP32 as JSON-RPC over UDP port 9090, and returns IMU samples on the same port. T ([docs](https://docs.wiznet.io/Product/Chip/Ethernet/W5500))

WIZnet parts: W5500 ([Datasheet](https://docs.wiznet.io/Product/Chip/Ethernet/W5500/datasheet?utm_source=maker&utm_medium=project&utm_campaign=w5500), [product hub](https://maker.wiznet.io/products/w5500/))

## Documents and links

- [buggy-learn repository](https://github.com/ulstu/buggy-learn) (code): The platform repository from Ulyanovsk State Technical University. MIT licence, created 2025-04-05, last push 2025-04-11.
- [Robot build and run instructions](https://github.com/ulstu/buggy-learn/blob/main/buggy/README.md) (schematics): Hardware description and the sentence stating that data exchange uses Ethernet implemented with a W5500, plus the ROS 2 build, mapping and navigation steps.
- [robot_controller_node.py](https://github.com/ulstu/buggy-learn/blob/main/buggy/urg_node2/urg_node2/scripts/robot_controller_node.py): The UDP bridge. Defines 192.168.2.11 port 9090, the JSON-RPC set_control_values message, the 30 degree steering clamp and the three second watchdog.
- [Control board artwork](https://raw.githubusercontent.com/ulstu/buggy-learn/main/ros2/docs/img/scheme_el.png): Board layout showing the W5500 silkscreen and its ten-pad SPI header next to the ESP32 and MPU-6050 footprints.
- [Control board mounted on the robot](https://raw.githubusercontent.com/ulstu/buggy-learn/main/ros2/docs/img/scheme_robot.png): Photograph of the installed board with a patch cable plugged into the blue W5500 Ethernet module.
- [Nav2 parameter file](https://github.com/ulstu/buggy-learn/blob/main/buggy/urg_node2/config/nav2/nav2_params.yaml): Nav2 settings for the built map. The AMCL block ships commented out, and the README prints the same block with laser_max_range 5.6 m, 100 to 500 particles and 30 beams.
- [ULSTU on GitHub](https://github.com/ulstu): Organisation profile of Ulyanovsk State Technical University, listing Ulyanovsk, Russia and fist@ulstu.ru.
- [WIZnet W5500](https://docs.wiznet.io/Product/Chip/Ethernet/W5500): Datasheet and documentation for the Ethernet controller used on the control board.

## Article

## 📌 An Ackermann Teaching Robot From Ulyanovsk State Technical University

Ulyanovsk State Technical University created the `buggy-learn` repository on GitHub on 2025-04-05, and the low-level control board of the robot inside it carries a WIZnet W5500 Ethernet controller. The GitHub organisation `ulstu` lists its location as Ulyanovsk, Russia and its contact address as fist@ulstu.ru. The repository is MIT licensed, copyright 2025 Ulyanovsk State Technical University, with commits from k.svyatov@ulstu.ru and the account ghub-ayrtom, the last of them on 2025-04-11.

![Photograph of the ULSTU buggy robot, a black short-course radio-controlled car chassis with a scanning laser on an acrylic plate at the front, a red lithium battery, a black finned computer, and a grey Ethernet cable looping over the rear, standing on a laboratory floor in front of a cardboard building model](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853106%2Epng) *The assembled robot. The scanning laser sits on the front plate, the onboard computer behind it, and a network cable loops over the rear deck. Photo: ULSTU, buggy-learn repository.*

ULSTU describes `buggy-learn` as a platform for learning robotics from scratch, shipping 3D models, control libraries, a virtual proving ground, a map editor and circuit designs alongside the physical robot. The published progression diagram runs from block programming for school grades 4 to 9, through a ROS 2 simulator for grades 10 to 11, to ROS 2 on the real robot for engineering teams.

## Why Ackermann Steering Changes the Software Stack

Most teaching robots, and most ready-made ROS packages, assume differential-drive or mecanum wheels that can spin in place. Real cars steer with Ackermann geometry, where the front wheels turn through slightly different angles and the vehicle cannot rotate about its own centre, which restricts the trajectories a planner may produce. ULSTU chose an Ackermann chassis so that lab work transfers to full-size driverless cars.

The base is a Traxxas Raptor Ford F-150 short-course radio-controlled model with the factory radio gear removed and replaced by a networked control kit, a Nvidia Jetson AGX Xavier and a Hokuyo laser rangefinder. That choice shows up in the code as `ackermann_keyboard_teleop_node.py`, a WASD keyboard node publishing `ackermann_msgs/AckermannDrive` on `/cmd_ackermann` with `ROBOT_MAX_SPEED` set to 8.0 cm/s and `ROBOT_MAX_STEERING_ANGLE` set to 30.0 degrees.

## The Two Layers and the Board That Joins Them

![Generated block diagram showing three groups. Actuators and sensors on the left hold a steering servo, a BTS7960 driver feeding the traction motor, and an IMU. The custom control board in the middle holds a W5500 highlighted in red above an ESP32, joined by SPI. The onboard computer on the right holds a Hokuyo laser on USB, a Jetson AGX Xavier, and a dashed Wi-Fi adapter on USB. Ethernet on UDP port 9090 joins the W5500 to the Jetson](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853107%2Epng) *Generated technical diagram, redrawn in English from the block diagram published in the repository.*

The upper layer of the ULSTU buggy is a Nvidia Jetson AGX Xavier running Ubuntu 20.04 and ROS 2 Foxy. The README explains that choice by the age of the hardware, noting the Xavier was released in 2018, and states the same instructions were tested on Ubuntu 22.04 with ROS 2 Humble. A Raspberry Pi or the cheaper Orange Pi can take the same role.

The lower layer is a board of the team's own design. The README lists an ESP32-family microcontroller, a W5500 Ethernet module, a MEMS inertial measurement unit, a 12 V to 5 V converter, and connectors for a BTS7960 transistor board and the steering servo. The perception sensor is a Hokuyo URG-04LX-UG01 single-plane lidar, which the README says can be swapped for equivalent Chinese units, with a camera as an optional addition.

Autonomy here means physical self-containment as well as software. The README states it plainly: "Все оборудование размещается непосредственно на роботе, что позволяет работать полностью автономно", meaning all the equipment sits directly on the robot so it can operate fully autonomously.

![Close-up photograph of the ULSTU control board mounted on the robot, showing a blue W5500 Ethernet module with an RJ45 jack and a grey patch cable plugged into it, an ESP32 development board with a lit blue LED, a small green sensor module, green screw terminals and a black finned heatsink below](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853107%5F0%2Epng) *The control board after installation, with the patch cable plugged into the blue W5500 module. Photo: ULSTU, buggy-learn repository.*

## ⚙️ What the W5500 Does for This Robot

The README states the networking decision in one sentence: "В отличие от многих других роботов для обмена данными используется интерфейс Ethernet, реализованный при помощи W5500." In English, unlike many other robots, data exchange uses an Ethernet interface implemented with a W5500.

The README then lists three benefits of that Ethernet link: high operational stability, immunity to interference, and no need to occupy the microcomputer's Wi-Fi adapter or to have an external wireless network available. The root README adds the performance claim, that the ESP32 with its Ethernet module transmits control commands and odometry data "надежно и с низкими задержками", reliably and with low latency.

The published board artwork backs the README. A silkscreen block marked W5500 sits next to a ten-pad module header labelled 3V3, 5V, MISO, GND, MOSI, RST, CS, INT, CLK and GND, which is the standard SPI plus reset and interrupt pinout of an off-the-shelf W5500 module. The same artwork shows an ESP32 devkit footprint and, next to it, an MPU-6050 footprint whose pads read GND, SCL, SDA, XDA, XCL, AD0 and INT.

![Two crops of the ULSTU board artwork side by side. The left crop shows green copper traces on black with red silkscreen reading W5500 and a header labelled CLK GND, CS INT, MOSI RST, MISO GND, 3V3 5V. The right crop shows a footprint marked ESP32 beside an MPU-6050 footprint with pads GND, SCL, SDA, XDA, XCL, AD0 and INT](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853107%5F1%2Epng) *Edited repository image: two crops of the published board artwork, upscaled and captioned. The W5500 crop is rotated 180 degrees because that block is drawn upside down in the original.*

## How Drive Commands and IMU Data Share One Cable

![Generated diagram in two lanes. The downlink lane runs from the /cmd_vel and /cmd_ackermann topics through robot_controller_node to the W5500 on the ESP32 board at 192.168.2.11 port 9090, carrying a JSON-RPC message with method set_control_values. The uplink lane runs from the same board over UDP to a socket bound on 0.0.0.0 port 9090 and out to the /imu topic](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853107%5F2%2Epng) *Generated technical diagram. Endpoints and field names read from robot_controller_node.py in the repository.*

The bridge between the two layers is a single Python node, `buggy/urg_node2/urg_node2/scripts/robot_controller_node.py`. It defines `UDP_SERVER_IP = '192.168.2.11'`, `UDP_SERVER_PORT = 9090` and `RECV_BUFFER_SIZE = 1024`, then subscribes to `/cmd_vel` and `/cmd_ackermann` and sends each command down as a JSON-RPC 2.0 datagram.

```python
jsonrpc_message = {
    'jsonrpc': '2.0',
    'method': 'set_control_values',
    'params': [speed, steering_angle],
}

jsonrpc_message_str = json.dumps(jsonrpc_message)
self.__sock.sendto(jsonrpc_message_str.encode(), (UDP_SERVER_IP, UDP_SERVER_PORT))
```

Conversion from ROS 2 velocity commands happens in the same node. Nav2 publishes `geometry_msgs/Twist` on `/cmd_vel`, and the node multiplies `linear.x` by 17.5, multiplies `angular.z` by -500, then clamps the steering angle to plus or minus 30 degrees before sending. A watchdog in the receive thread stops the robot if no `/cmd_vel` message has arrived for more than three seconds, which matters on a vehicle whose throttle is held by a separate microcontroller.

The return path uses the same port in the opposite direction. A background thread binds `0.0.0.0` on port 9090, reads datagrams of up to 1024 bytes, parses each as JSON, and copies `params[0]` into a `sensor_msgs/Imu` message: the timestamp in seconds and nanoseconds, linear acceleration, angular velocity and orientation. That message is published on `/imu`, which is where the `robot_localization` package picks it up.

| Link | Interface | Endpoint or setting | Where it is stated |
| --- | --- | --- | --- |
| ESP32 to W5500 | SPI | Ten-pad header: 3V3, 5V, MISO, GND, MOSI, RST, CS, INT, CLK, GND | Board artwork `ros2/docs/img/scheme_el.png` |
| Control board to onboard computer | Ethernet, UDP | 192.168.2.11 port 9090, 1024 byte receive buffer | `robot_controller_node.py` |
| ESP32 to IMU | I2C | MPU-6050 footprint, SCL and SDA pads | Board artwork and block diagram |
| Onboard computer to lidar | USB or Ethernet | `ip_port` 10940, `ip_address` left blank in the shipped file | `config/params_ether.yaml` |
| Onboard computer to operator laptop | USB Wi-Fi adapter | Remote desktop session | Block diagram and repository photographs |

## Mapping and Navigation on the Onboard Computer

One launch file, `urg_node2.launch.py`, starts the whole robot, and the README shows which entries to comment in or out for mapping, for localisation and for EKF fusion. The composed node list is the part a reader would otherwise have to assemble by hand:

- `urg_node2_node`, the Hokuyo lifecycle driver publishing `/scan`

- `lidar_odometry_node`, scan matching that publishes `/odom` and the odom transform

- `robot_state_publisher`, fed by `robot.urdf.xacro`

- `robot_controller_node`, the UDP bridge to the ESP32 board

- `ekf_filter_node` from `robot_localization`, fusing lidar odometry with the IMU

- `async_slam_toolbox_node` for mapping, or `localization_slam_toolbox_node` for pose tracking

- `rviz` plus `joint_state_publisher_gui` for visualisation and wheel joints

- a static transform publisher tying `map` to `odom`

![Photograph of a laptop screen showing an RViz window with a partly built black and white occupancy map and red odometry arrows, with the buggy robot and cardboard building models visible on the floor behind the laptop](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853107%5F3%2Epng) *A mapping run in progress. The red arrows are the robot odometry, and the physical test area sits behind the laptop. Photo: ULSTU, buggy-learn repository.*

The lidar odometry node declares three tunable parameters, defaulting to 0.25 m for `max_correspondence_distance`, 0.005 for `transformation_epsilon` and 30 for `maximum_iterations`, and the README says they can be retuned for odometry quality or for lower compute cost. Mapping runs `slam_toolbox` in `mapping` mode, after which the operator saves and serialises the map from an RViz panel.

The repository ships five saved maps. The one `nav2_params.yaml` points at, `real_map.pgm`, is 97 by 83 pixels at 0.05 m per pixel, so that space is roughly 4.85 m by 4.15 m, an indoor room rather than a car park. Localisation can then use `slam_toolbox` in `localization` mode or AMCL from Nav2, whose parameter block in the README sets `laser_max_range` to 5.6 m, particles between 100 and 500, and 30 beams per update, all commented out in the shipped file.

![Photograph of a monitor showing an RViz navigation view with a grey global costmap, cyan inflation circles around obstacles, a dark blue mapped wall, and a magenta planned path running from the robot footprint to a goal on the right](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853107%5F4%2Epng) *Navigation with Nav2 on the built map. The cyan discs are inflated obstacles and the magenta line is the planned path. Photo: ULSTU, buggy-learn repository.*

## What Still Runs Over the Air

The wired link is not a claim that the robot is wireless-free. The block diagram in the repository shows a Wi-Fi adapter attached to the Jetson AGX Xavier over USB, and repository photographs show an operator laptop driving RViz through a remote desktop session to a host named `nvidia-xavier`. The split is the useful part: the real-time control loop and the IMU stream stay on the cable between the ESP32 board and the onboard computer, while the operator connection stays wireless.

![Top-down photograph of the robot on a wooden floor, showing the Nvidia onboard computer with its finned case in the centre, a red lithium battery beside it, the custom control board with its blue Ethernet module at the left, and the Hokuyo scanning laser on an acrylic plate at the right](https://maker.wiznet.io/upload/ckeditor5/1061698615%5F1787853107%5F5%2Epng) *The same robot from above. The onboard computer, battery and control board share the chassis deck. Photo: ULSTU, buggy-learn repository.*

## What the Repository Publishes and What It Does Not

The firmware for the ESP32 board is not in this repository. A listing of the 881 tracked files outside `node_modules`, checked on 2026-08-27, contains no ESP-IDF or Arduino project for the control board, so the register-level detail of how the W5500 is driven cannot be read here. What the repository does publish is the ROS 2 side, the board artwork and the wire protocol, which is enough to rebuild the link against any firmware.

A related repository from the same organisation shows the house pattern. `ulstu/cad-self-driving`, created on 2022-05-31 and last pushed on 2025-07-24, holds ESP32 control units for full-size vehicles whose `sdkconfig` files carry `CONFIG_ETH_SPI_ETHERNET_W5500=y` and whose `Ethernet.cpp` opens the SPI device at 36 MHz. That is a different vehicle programme, but it is the closest published reference for the low-level side.

Two smaller gaps are worth naming. The README describes the inertial sensor as a MEMS device from ST Microelectronics while the board artwork carries a GY-521 MPU-6050 footprint, so a rebuilder should trust the artwork. The board is published as a rendered image rather than schematic or Gerber sources, and no bill of materials or cost figure appears in the repository.

## Related WIZnet Maker Projects

[How to Bridge a ROS2 Jazzy Rover to Wired Ethernet with W5500 on ESP32?](https://maker.wiznet.io/viktor/projects/ros2-jazzy-rover-control-esp32-mqtt-w5500-ethernet/) covers the same division of labour, an ESP32 handling motors and sensors below a ROS 2 host. The difference is the wire protocol, since SzufladaV2 carries its traffic over MQTT while the ULSTU buggy sends raw JSON-RPC datagrams and adds Ackermann steering limits.

[How Did RoboMagellan Implement a UDP-Based Robot Motor Controller Using the RP2040 and W5500?](https://maker.wiznet.io/Aimee0/projects/robomagellan-rp2040-firmware/) is the closest match on the protocol side, a UDP command channel to a motor controller over a W5500. The difference is the microcontroller and the return path, since the ULSTU node reuses the same port to lift IMU samples into a ROS 2 topic.

[PipeInspect: Wired Ethernet Control & Wi-Fi Video Streaming](https://maker.wiznet.io/irina/projects/pipeinspect-wired-ethernet-control-wi-fi-video-streaming/) shows the same layering in a different machine, wired control with wireless payload traffic. The difference is what rides the wireless side, since PipeInspect streams camera video while the ULSTU buggy uses Wi-Fi only to reach the operator desktop.

## ❓ FAQ

**Q. What does the ULSTU buggy use the W5500 for?** The W5500 gives the ESP32 control board its Ethernet port, over which the Jetson AGX Xavier sends drive commands as JSON-RPC datagrams to 192.168.2.11 port 9090 and receives IMU samples on the same port.

**Q. Why did ULSTU choose Ethernet for the control link?** The README names three reasons: high operational stability, immunity to interference, and no need to occupy the onboard computer's Wi-Fi adapter or to provide an external wireless network. Wi-Fi is still used for the operator desktop.

**Q. Is the ESP32 firmware published?** No. A listing of the 881 tracked files on 2026-08-27 found no firmware project for the control board, so the SPI driver and pin assignment for the W5500 are not visible here.

**Q. What ROS 2 version does the stack need?** The instructions were written for ROS 2 Foxy on Ubuntu 20.04 because the Jetson AGX Xavier dates from 2018, and the README states the same steps were tested on Ubuntu 22.04 with ROS 2 Humble.

**Q. Can this platform be rebuilt on cheaper hardware?** The README names Raspberry Pi and Orange Pi as alternatives to the Jetson AGX Xavier, and says the Hokuyo URG-04LX-UG01 lidar can be replaced by equivalent units.

---

Source: https://maker.wiznet.io/Benjamin/projects/why-does-a-w5500-ethernet-link-carry-ros-2-drive-commands-in-the-ulstu-buggy/
