Connecting a microcontroller to a modern robotics ecosystem can be a daunting task, especially when working across different operating systems.
In this tutorial, we will explore how to transform an STM32F3 Discovery board into a fully functional ROS 2 node with the help of micro-ROS library.
More specifically, we’ll use the STM32 native USB serial port to establish real-time communication with a Linux host running inside WSL 2.
Github of this tutorial :
To successfully follow this tutorial, you will need a specific set of hardware and software tools.
This setup is designed for developers working on Windows using WSL2.
Hardware Requirements
Software Stack
An interesting thing is the use of Ubuntu 24.04 as host for WSL and Ubuntu 22.04 as Docker environment for ROS 2 Humble (inside the host).
Hierarchically we have:
Windows 10 (or 11) > Ubuntu 24.04 via WSL 2 > Ubuntu 22.04 as dev container > ROS 2 Humble + micro-ROS.
And more generally we can resume our stack as follows:
Data Flow: From silicon to ROS 2:
The first thing is to follow to plug your STM32F3Discovery board to your PC.
Then follow this tutorial explaining how to set your Windows environment in order to use WSL with your board:
The above tutorial was for a basic interaction with the board.
For our new current tutorial we are going to use the second USB connector of the STM32F3 board.
Connect the USB ST-LINK with a cable to a first USB PC port and the USB USER with another cable to a second USB port.
Then from your Powershell type the following commands (if not already done):
usbipd list
It's generate the following output:
Connected: BUSID VID:PID DEVICE STATE 2-1 0483:3748 STM32 STLink Shared 2-2 0483:5740 Serial device USB (COM5) Shared
If you don't see the Serial device USB (COM5), don't worry, it means that you have to firstly flash your board with the firmware compiled further in this tutorial.
If you see the both USB devices, then let's continue.
Start your WSL 2 instance.
From Powershell, for the ST-LINK USB, use this command:
usbipd attach --wsl --busid 2-1
For the USER USB use this one :
usbipd attach --wsl --busid 2-2 --auto-attach
You can note the last option: « --auto-attach ».
This last option is really important because even a micro second can make the device lose the connection with the USB port.
So the connection with the serial port can be lost by micro-ROS if there no auto attach mode.
Let’s assume you have your source files in your Ubuntu (24.04) WSL folder, such as :
Then from VSCode, let’s rebuild the project as a dev container:
Select the .devcontainer/devcontainer.json file from the list if many files or from the directory taken from the Github project.
Let the container build.
Create now a project directory in your dev container as the following :
Go inside this directory :
cd badprog-ros-2-micro-ros-using-stm32-usb-serial-port-to-communicate-with-a-linux-host-via-wsl-2
Copy the platformio.ini file (from the Github link up above) and add it at the root of your project.
So globally this is so far the only file of your project.
To make the STM32 "User USB" port visible as a COM port on Windows, we must force the microcontroller to behave as a USB Communication Device Class (CDC).
In your platformio.ini, these two flags are the "magic" that triggers the hardware:
Note: Without these flags, the STM32 will not be detected by usbipd on the second cable, as the USB User port remains inactive by default.
In the main.cpp, we use the function with the SerialUSB parameter instead of just Serial:
set_microros_serial_transports(SerialUSB);
This tells micro-ROS to bypass the standard UART pins (TX/RX) and send data directly through the USB User connector.
This allows for a much cleaner setup with higher bandwidth and no need for an external FTDI adapter.
Let’s now build the microros library from the dev container instance:
pio run
This command will download everything needed to build the micro-ROS library for our STM32F3Discovery board.
It’s a cross compilation, from our container on Ubuntu 22.04 for the STM32F303VC microcontroller.
If you see the following line appear and blocking in the terminal it's a good sign:
Building micro-ROS library
The first time it could take several minutes (between 5 to 10 minutes) to build.
The next compilation of your program will be shorter of course (don’t need anymore to build the micro-ROS library).
If everything went OK then we can upload our program on the STM32F3Discovery board:
pio run --target upload
If you see the following output then your firmware has been flashed on the microcontroller:
...
Uploading .pio/build/disco_f303vc/firmware.elf
xPack Open On-Chip Debugger 0.12.0-01004-g9ea7f3d64-dirty (2023-01-30-15:03)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
debug_level: 1
srst_only separate srst_nogate srst_open_drain connect_deassert_srst
[stm32f3x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x0800638c msp: 0x2000a000
** Programming Started **
Warn : Adding extra erase range, 0x08015d6c .. 0x08015fff
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked
=========== [SUCCESS] Took 12.38 seconds =========This is not the end.
Indeed, at this point you shouldn’t see your green LED blinking.
To see it blink, we have to come back to our host (Ubuntu 24.04 as WSL) and first check if the /dev/ttyACM0 serial port is available:
ls /dev/tty*
Every device should appear and hopefully the ttyACM0 one as well.
If it’s the case, then run the following Docker command from the host (Ubuntu 24.04):
docker run -it --rm --privileged -v /dev:/dev microros/micro-ros-agent:humble serial --dev /dev/ttyACM0
You should see the output saying that the session has been established, a participant, topic and publisher created.
At this time, the green LED should blink on your board.
To finish the demonstration, come back to the dev container (Ubuntu 22.04 where ROS 2 is installed) then type this command:
ros2 topic echo /badprog_topic_counter
The counter should increment each second like this :
data: 0 --- data: 1 --- data: 2 …
Well done, you did it ![]()
Add new comment