Setting Up Micro-ROS in STM32CubeIDE
Begin by adding the following Micro-ROS source files to your project's Core/Src directory:
- extra_sources/microros_time.c
- extra_sources/microros_allocators.c
- extra_sources/custom_memory_manager.c
- extra_sources/microros_transports/dma_transport.c
After copying these files, right-click on your project in STM32CubeIDE and select "Refresh" to make them appear.
Resolving Docker Permissions
During compilation, you may encounter Docker permission issues. To resolve these:
- Add docker to user groups:
sudo groupadd docker
sudo usermod -aG docker your_username
newgrp docker
- Test Docker installation:
docker run hello-world
If you see "Hello from Docker!" the setup is successful. If compilation still fails, run:
sudo chmod 666 /var/run/docker.sock
Now retry compilation. During the pre-compilation phase, Docker will download necessary files. Network issues may cause failures, so retry if needed.
Project Configuration
Once compilation succeeds, configure your project as follows:
RCC Clock Configuration
Set up the external 8MHz crystal oscillator for your PCB design.
FreeRTOS Configuration
Select FreeRTOS V2 for enhanced functionality. Modify task stack size to 3000 and change memory allocation to static for better resource management.
UART Communication Setup
Configure the UART interface for host communication (UART1 in this example):
- Mode: Asynchronous
- USART1_RX: Set priority to Very High and DMA Request Mode to Circular
- USART1_TX: Set priority to Very High
- In NVIC Settings, enable USART1 global interrupt
FreeRTOS Time Base
Select an unused timer (TIM1 recommended) as the time base source for FreeRTOS, ensuring accuracy and stability.
Clock System Configuration
Set the system clock to maximum 168MHz using an external clock source.
Code Style Settings
In Project Manager, configure code generation style for better project organization.
Modifying the Project for Micro-ROS
After generating code from your .ioc file, reference the sample_main.c file in the micro_ros_stm32cubemx_utils folder to modify your project.
Add the following includes to freertos.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "usart.h"
Add these transport function prototypes:
bool cubemx_transport_open(struct uxrCustomTransport * transport);
bool cubemx_transport_close(struct uxrCustomTransport * transport);
size_t cubemx_transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * err);
size_t cubemx_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err);
void * microros_allocate(size_t size, void * state);
void microros_deallocate(void * pointer, void * state);
void * microros_reallocate(void * pointer, size_t size, void * state);
void * microros_zero_allocate(size_t number_of_elements, size_t size_of_element, void * state);
Replace the content of the StartDefaultTask function with the following Micro-ROS implementation:
rmw_uros_set_custom_transport(
true,
(void *) &huart3,
cubemx_transport_open,
cubemx_transport_close,
cubemx_transport_write,
cubemx_transport_read);
rcl_allocator_t freeRTOS_allocator = rcutils_get_zero_initialized_allocator();
freeRTOS_allocator.allocate = microros_allocate;
freeRTOS_allocator.deallocate = microros_deallocate;
freeRTOS_allocator.reallocate = microros_reallocate;
freeRTOS_allocator.zero_allocate = microros_zero_allocate;
if (!rcutils_set_default_allocator(&freeRTOS_allocator)) {
printf("Error on default allocators (line %d)\n", __LINE__);
}
// micro-ROS app
rcl_publisher_t publisher;
std_msgs__msg__Int32 msg;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
allocator = rcl_get_default_allocator();
//create init_options
rclc_support_init(&support, 0, NULL, &allocator);
// create node
rclc_node_init_default(&node, "cubemx_node", "", &support);
// create publisher
rclc_publisher_init_default(
&publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
"cubemx_publisher");
msg.data = 0;
for(;;)
{
rcl_ret_t ret = rcl_publish(&publisher, &msg, NULL);
if (ret != RCL_RET_OK)
{
printf("Error publishing (line %d)\n", __LINE__);
}
msg.data++;
osDelay(10);
}