├── ci ├── .gitignore ├── extra_packages │ ├── extra_packages.repos │ └── my_custom_message │ │ ├── msg │ │ └── MyCustomMessage.msg │ │ ├── package.xml │ │ └── CMakeLists.txt ├── atomic.meta ├── custom.meta ├── src │ └── main.cpp └── platformio.ini ├── microros_utils ├── __init__.py ├── utils.py ├── library_builder.py └── repositories.py ├── platform_code ├── arduino │ ├── custom │ │ └── micro_ros_transport.h │ ├── serial │ │ ├── micro_ros_transport.h │ │ └── micro_ros_transport.cpp │ ├── native_ethernet │ │ ├── micro_ros_transport.h │ │ └── micro_ros_transport.cpp │ ├── clock_gettime.cpp │ ├── wifi │ │ ├── micro_ros_transport.h │ │ └── micro_ros_transport.cpp │ ├── wifi_nina │ │ ├── micro_ros_transport.h │ │ └── micro_ros_transport.cpp │ └── ethernet │ │ ├── micro_ros_transport.cpp │ │ └── micro_ros_transport.h └── micro_ros_platformio.h ├── .images ├── banner-dark-theme.png └── banner-light-theme.png ├── 3rd-party-licenses.txt ├── examples ├── micro-ros_publisher │ ├── platformio.ini │ └── src │ │ └── Main.cpp └── ethernet_pubsub │ ├── platformio.ini │ ├── docker-compose.yaml │ ├── README.md │ └── src │ └── main.cpp ├── metas ├── colcon.meta ├── colcon_lowmem.meta ├── colcon_verylowmem.meta └── common.meta ├── package.xml ├── .github ├── actions │ └── platformio-env │ │ └── action.yml ├── ISSUE_TEMPLATE │ └── general-issue.md └── workflows │ └── ci.yml ├── library.json ├── NOTICE ├── CHANGELOG.rst ├── .gitignore ├── CONTRIBUTING.md ├── extra_script.py ├── LICENSE └── README.md /ci/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | -------------------------------------------------------------------------------- /microros_utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /platform_code/arduino/custom/micro_ros_transport.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.images/banner-dark-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro-ROS/micro_ros_platformio/HEAD/.images/banner-dark-theme.png -------------------------------------------------------------------------------- /.images/banner-light-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micro-ROS/micro_ros_platformio/HEAD/.images/banner-light-theme.png -------------------------------------------------------------------------------- /3rd-party-licenses.txt: -------------------------------------------------------------------------------- 1 | Third Party Licenses 2 | ==================== 3 | 4 | This repository does not directly contain 3rd party source code. 5 | 6 | -------------------------------------------------------------------------------- /ci/extra_packages/extra_packages.repos: -------------------------------------------------------------------------------- 1 | repositories: 2 | control_msgs: 3 | type: git 4 | url: https://github.com/ros-controls/control_msgs 5 | version: humble -------------------------------------------------------------------------------- /ci/atomic.meta: -------------------------------------------------------------------------------- 1 | { 2 | "names": { 3 | "rcutils": { 4 | "cmake-args": [ 5 | "-DRCUTILS_NO_64_ATOMIC=OFF" 6 | ] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /microros_utils/utils.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | def run_cmd(command, env=None): 4 | return subprocess.run(command, 5 | capture_output = True, 6 | shell = True, 7 | env=env 8 | ) 9 | -------------------------------------------------------------------------------- /examples/micro-ros_publisher/platformio.ini: -------------------------------------------------------------------------------- 1 | ; [env:teensy41] 2 | ; platform = teensy 3 | ; board = teensy41 4 | framework = arduino 5 | board_microros_transport = serial 6 | lib_deps = 7 | https://github.com/micro-ROS/micro_ros_platformio -------------------------------------------------------------------------------- /examples/ethernet_pubsub/platformio.ini: -------------------------------------------------------------------------------- 1 | [env:esp32dev] 2 | platform = espressif32 3 | board = esp32dev 4 | framework = arduino 5 | board_microros_transport = ethernet 6 | monitor_speed = 115200 7 | lib_deps = 8 | https://github.com/micro-ROS/micro_ros_platformio -------------------------------------------------------------------------------- /ci/extra_packages/my_custom_message/msg/MyCustomMessage.msg: -------------------------------------------------------------------------------- 1 | bool bool_test 2 | byte byte_test 3 | char char_test 4 | float32 float32_test 5 | float64 double_test 6 | int8 int8_test 7 | uint8 uint8_test 8 | int16 int16_test 9 | uint16 uint16_test 10 | int32 int32_test 11 | uint32 uint32_test 12 | int64 int64_test 13 | uint64 uint64_test -------------------------------------------------------------------------------- /platform_code/arduino/serial/micro_ros_transport.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static inline void set_microros_serial_transports(Stream & stream){ 4 | rmw_uros_set_custom_transport( 5 | true, 6 | &stream, 7 | platformio_transport_open, 8 | platformio_transport_close, 9 | platformio_transport_write, 10 | platformio_transport_read 11 | ); 12 | } -------------------------------------------------------------------------------- /ci/custom.meta: -------------------------------------------------------------------------------- 1 | { 2 | "names": { 3 | "rmw_microxrcedds": { 4 | "cmake-args": [ 5 | "-DRMW_UXRCE_MAX_NODES=1", 6 | "-DRMW_UXRCE_MAX_PUBLISHERS=1", 7 | "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=1", 8 | "-DRMW_UXRCE_MAX_SERVICES=0", 9 | "-DRMW_UXRCE_MAX_CLIENTS=0", 10 | "-DRMW_UXRCE_MAX_HISTORY=1", 11 | "-DRMW_UXRCE_TRANSPORT=custom" 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /metas/colcon.meta: -------------------------------------------------------------------------------- 1 | { 2 | "names": { 3 | "rmw_microxrcedds": { 4 | "cmake-args": [ 5 | "-DRMW_UXRCE_MAX_NODES=1", 6 | "-DRMW_UXRCE_MAX_PUBLISHERS=10", 7 | "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=5", 8 | "-DRMW_UXRCE_MAX_SERVICES=1", 9 | "-DRMW_UXRCE_MAX_CLIENTS=1", 10 | "-DRMW_UXRCE_MAX_HISTORY=4", 11 | "-DRMW_UXRCE_TRANSPORT=custom" 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /metas/colcon_lowmem.meta: -------------------------------------------------------------------------------- 1 | { 2 | "names": { 3 | "rmw_microxrcedds": { 4 | "cmake-args": [ 5 | "-DRMW_UXRCE_MAX_NODES=1", 6 | "-DRMW_UXRCE_MAX_PUBLISHERS=10", 7 | "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=5", 8 | "-DRMW_UXRCE_MAX_SERVICES=1", 9 | "-DRMW_UXRCE_MAX_CLIENTS=1", 10 | "-DRMW_UXRCE_MAX_HISTORY=1", 11 | "-DRMW_UXRCE_TRANSPORT=custom" 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /metas/colcon_verylowmem.meta: -------------------------------------------------------------------------------- 1 | { 2 | "names": { 3 | "rmw_microxrcedds": { 4 | "cmake-args": [ 5 | "-DRMW_UXRCE_MAX_NODES=1", 6 | "-DRMW_UXRCE_MAX_PUBLISHERS=2", 7 | "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=1", 8 | "-DRMW_UXRCE_MAX_SERVICES=0", 9 | "-DRMW_UXRCE_MAX_CLIENTS=1", 10 | "-DRMW_UXRCE_MAX_HISTORY=1", 11 | "-DRMW_UXRCE_TRANSPORT=custom" 12 | ] 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | micro_ros_platformio 5 | 2.0.0 6 | micro-ROS tools for Platform.IO 7 | Eugenio Collado 8 | Carlos Espinoza 9 | Apache License 2.0 10 | 11 | -------------------------------------------------------------------------------- /.github/actions/platformio-env/action.yml: -------------------------------------------------------------------------------- 1 | name: 'platformio-env' 2 | description: 'Install Platform.IO environment' 3 | runs: 4 | using: "composite" 5 | steps: 6 | - id: install-platformio-env 7 | shell: bash 8 | run: | 9 | apt update 10 | export DEBIAN_FRONTEND=noninteractive 11 | apt install -y git curl python3 python3-pip python3-venv git cmake 12 | curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py 13 | python3 get-platformio.py 14 | echo 'export PATH=$PATH:~/.platformio/penv/bin' >> ~/.bashrc 15 | 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General issue 3 | about: General issue template for micro-ROS 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Issue template 11 | 12 | - Hardware description: 13 | - RTOS: 14 | - Installation type: 15 | - Version or commit hash: 16 | 17 | #### Steps to reproduce the issue 18 | 19 | 20 | #### Expected behavior 21 | 22 | #### Actual behavior 23 | 24 | #### Additional information 25 | -------------------------------------------------------------------------------- /platform_code/arduino/native_ethernet/micro_ros_transport.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct micro_ros_agent_locator { 4 | IPAddress address; 5 | int port; 6 | }; 7 | 8 | static inline void set_microros_native_ethernet_transports(byte mac[], IPAddress client_ip, IPAddress agent_ip, uint16_t agent_port){ 9 | 10 | static struct micro_ros_agent_locator locator; 11 | 12 | Ethernet.begin(mac, client_ip); 13 | delay(1000); 14 | 15 | locator.address = agent_ip; 16 | locator.port = agent_port; 17 | 18 | rmw_uros_set_custom_transport( 19 | false, 20 | &locator, 21 | platformio_transport_open, 22 | platformio_transport_close, 23 | platformio_transport_write, 24 | platformio_transport_read 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /platform_code/arduino/clock_gettime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #define micro_rollover_useconds 4294967295 5 | 6 | #if !defined(_POSIX_TIMERS) || !_POSIX_TIMERS 7 | 8 | extern "C" int clock_gettime(clockid_t unused, struct timespec *tp) 9 | { 10 | (void)unused; 11 | static uint32_t rollover = 0; 12 | static uint32_t last_measure = 0; 13 | 14 | uint32_t m = micros(); 15 | rollover += (m < last_measure) ? 1 : 0; 16 | 17 | uint64_t real_us = (uint64_t) (m + rollover * micro_rollover_useconds); 18 | tp->tv_sec = real_us / 1000000; 19 | tp->tv_nsec = (real_us % 1000000) * 1000; 20 | last_measure = m; 21 | 22 | return 0; 23 | } 24 | 25 | #endif // ifndef _POSIX_TIMERS 26 | -------------------------------------------------------------------------------- /platform_code/arduino/wifi/micro_ros_transport.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct micro_ros_agent_locator { 5 | IPAddress address; 6 | int port; 7 | }; 8 | 9 | static inline void set_microros_wifi_transports(char * ssid, char * pass, IPAddress agent_ip, uint16_t agent_port){ 10 | WiFi.begin(ssid, pass); 11 | 12 | while (WiFi.status() != WL_CONNECTED) { 13 | delay(500); 14 | } 15 | 16 | static struct micro_ros_agent_locator locator; 17 | locator.address = agent_ip; 18 | locator.port = agent_port; 19 | 20 | rmw_uros_set_custom_transport( 21 | false, 22 | (void *) &locator, 23 | platformio_transport_open, 24 | platformio_transport_close, 25 | platformio_transport_write, 26 | platformio_transport_read 27 | ); 28 | } -------------------------------------------------------------------------------- /platform_code/arduino/wifi_nina/micro_ros_transport.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct micro_ros_agent_locator { 6 | IPAddress address; 7 | int port; 8 | }; 9 | 10 | static inline void set_microros_wifi_transports(char * ssid, char * pass, IPAddress agent_ip, uint16_t agent_port){ 11 | while (WiFi.begin(ssid, pass) != WL_CONNECTED) { 12 | delay(500); 13 | } 14 | 15 | static struct micro_ros_agent_locator locator; 16 | locator.address = agent_ip; 17 | locator.port = agent_port; 18 | 19 | rmw_uros_set_custom_transport( 20 | false, 21 | (void *) &locator, 22 | platformio_transport_open, 23 | platformio_transport_close, 24 | platformio_transport_write, 25 | platformio_transport_read 26 | ); 27 | } -------------------------------------------------------------------------------- /ci/extra_packages/my_custom_message/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | my_custom_message 5 | 0.0.0 6 | TODO: Package description 7 | root 8 | TODO: License declaration 9 | 10 | ament_cmake 11 | 12 | rosidl_default_generators 13 | rosidl_default_runtime 14 | rosidl_interface_packages 15 | 16 | ament_lint_auto 17 | ament_lint_common 18 | 19 | 20 | ament_cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/ethernet_pubsub/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "2.1" 2 | 3 | services: 4 | micro-ros-agent: 5 | image: microros/micro-ros-agent:humble 6 | container_name: micro-ros-agent 7 | network_mode: host 8 | stdin_open: true 9 | tty: true 10 | environment: 11 | - ROS_DOMAIN_ID=8 12 | ports: 13 | - 8888:8888/udp 14 | command: udp4 --port 8888 --verbose 6 15 | 16 | rqt: 17 | image: osrf/ros:humble-desktop 18 | container_name: rqt-visualizer 19 | network_mode: host 20 | ipc: host 21 | pid: host 22 | tty: true 23 | privileged: true 24 | device_cgroup_rules: 25 | - 'c 189:* rmw' 26 | environment: 27 | - ROS_DOMAIN_ID=8 28 | - DISPLAY=${DISPLAY} 29 | - QT_X11_NO_MITSHM=1 30 | volumes: 31 | - /tmp/.X11-unix:/tmp/.X11-unix:rw 32 | command: bash -c "source /opt/ros/humble/setup.bash && rqt" 33 | 34 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "micro_ros_platformio", 3 | "version" : "0.0.1", 4 | "authors": [ 5 | { 6 | "name": "Pablo Garrido", 7 | "email": "pablogarrido@eprosima.com", 8 | "maintainer": true 9 | }, 10 | { 11 | "name": "Antonio Cuadros", 12 | "email": "antoniocuadros@eprosima.com", 13 | "maintainer": true 14 | } 15 | ], 16 | 17 | "description" : "micro-ROS Platform.IO library", 18 | "homepage" : "https://micro.ros.org", 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/micro-ROS/micro_ros_platformio.git" 22 | }, 23 | 24 | "build": { 25 | "extraScript": "./extra_script.py" 26 | }, 27 | 28 | "frameworks": "arduino", 29 | "platforms": "teensy, https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream, atmelsam, raspberrypi, ststm32" 30 | } -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | 2 | # This is the official list of copyright holders and authors. 3 | # 4 | # Often employers or academic institutions have ownership over code that is 5 | # written in certain circumstances, so please do due diligence to ensure that 6 | # you have the right to submit the code. 7 | # 8 | # When adding J Random Contributor's name to this file, either J's name on its 9 | # own or J's name associated with J's organization's name should be added, 10 | # depending on whether J's employer (or academic institution) has ownership 11 | # over code that is written for this project. 12 | # 13 | # How to add names to this file: 14 | # Individual's name . 15 | # 16 | # If Individual's organization is copyright holder of her contributions add the 17 | # organization's name, optionally also the contributor's name: 18 | # 19 | # Organization's name 20 | # Individual's name 21 | # 22 | # Please keep the list sorted. 23 | 24 | eProsima 25 | Pablo Garrido 26 | Antonio Cuadros 27 | -------------------------------------------------------------------------------- /platform_code/arduino/serial/micro_ros_transport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | extern "C" { 12 | 13 | bool platformio_transport_open(struct uxrCustomTransport * transport) 14 | { 15 | return true; 16 | } 17 | 18 | bool platformio_transport_close(struct uxrCustomTransport * transport) 19 | { 20 | return true; 21 | } 22 | 23 | size_t platformio_transport_write(struct uxrCustomTransport * transport, const uint8_t *buf, size_t len, uint8_t *errcode) 24 | { 25 | (void)errcode; 26 | 27 | Stream * stream = (Stream *) transport->args; 28 | size_t sent = stream->write(buf, len); 29 | return sent; 30 | } 31 | 32 | size_t platformio_transport_read(struct uxrCustomTransport * transport, uint8_t *buf, size_t len, int timeout, uint8_t *errcode) 33 | { 34 | (void)errcode; 35 | 36 | Stream * stream = (Stream *) transport->args; 37 | stream->setTimeout(timeout); 38 | return stream->readBytes((char *)buf, len); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /platform_code/micro_ros_platformio.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MICRO_ROS_PLATFORMIO 3 | #define MICRO_ROS_PLATFORMIO 4 | 5 | #include 6 | 7 | // In GNU C < 6.0.0 __attribute__((deprecated(msg))) is not supported for enums, used in rmw/types.h 8 | #if __GNUC__ < 6 9 | #define aux__attribute__(x) __attribute__(x) 10 | #define __attribute__(x) 11 | #endif 12 | 13 | #include 14 | 15 | #if __GNUC__ < 6 16 | #undef __attribute__ 17 | #define __attribute__(x) aux__attribute__(x) 18 | #endif 19 | 20 | #ifdef __cplusplus 21 | extern "C" 22 | { 23 | #endif 24 | 25 | bool platformio_transport_open(struct uxrCustomTransport * transport); 26 | bool platformio_transport_close(struct uxrCustomTransport * transport); 27 | size_t platformio_transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * err); 28 | size_t platformio_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #include 35 | 36 | #endif // MICRO_ROS_PLATFORMIO 37 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - '**' 7 | schedule: 8 | - cron: '59 23 * * *' # every day at 23:59 UTC 9 | 10 | jobs: 11 | 12 | micro_ros_platformio: 13 | runs-on: ubuntu-24.04 14 | container: ubuntu:24.04 15 | 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | platform: [teensy41, teensy40, teensy36, teensy35, teensy31, due, zero, olimex_e407, esp32dev, nanorp2040connect, portenta_h7_m7, teensy41_eth, nanorp2040connect_wifi, portenta_h7_m7_wifi, esp32dev_wifi, esp32dev_ethernet, portenta_h7_m7_humble, portenta_h7_m7_jazzy, portenta_h7_m7_kilted, portenta_h7_m7_rolling, teensy41_custom, pico, pico2] 20 | 21 | steps: 22 | - uses: actions/checkout@v5 23 | with: 24 | path: repo 25 | - name: Install environment 26 | uses: ./repo/.github/actions/platformio-env 27 | - name: Build 28 | shell: bash 29 | run: | 30 | export PATH=$PATH:~/.platformio/penv/bin 31 | cd repo/ci 32 | pio run -e ${{ matrix.platform }} 33 | -------------------------------------------------------------------------------- /ci/extra_packages/my_custom_message/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(my_custom_message) 3 | 4 | # Default to C99 5 | if(NOT CMAKE_C_STANDARD) 6 | set(CMAKE_C_STANDARD 99) 7 | endif() 8 | 9 | # Default to C++14 10 | if(NOT CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 14) 12 | endif() 13 | 14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 15 | add_compile_options(-Wall -Wextra -Wpedantic) 16 | endif() 17 | 18 | # find dependencies 19 | find_package(ament_cmake REQUIRED) 20 | # uncomment the following section in order to fill in 21 | # further dependencies manually. 22 | # find_package( REQUIRED) 23 | 24 | if(BUILD_TESTING) 25 | find_package(ament_lint_auto REQUIRED) 26 | # the following line skips the linter which checks for copyrights 27 | # uncomment the line when a copyright and license is not present in all source files 28 | #set(ament_cmake_copyright_FOUND TRUE) 29 | # the following line skips cpplint (only works in a git repo) 30 | # uncomment the line when this package is not in a git repo 31 | #set(ament_cmake_cpplint_FOUND TRUE) 32 | ament_lint_auto_find_test_dependencies() 33 | endif() 34 | 35 | find_package(rosidl_default_generators REQUIRED) 36 | 37 | rosidl_generate_interfaces(${PROJECT_NAME} 38 | "msg/MyCustomMessage.msg" 39 | ) 40 | 41 | ament_package() 42 | -------------------------------------------------------------------------------- /metas/common.meta: -------------------------------------------------------------------------------- 1 | { 2 | "names": { 3 | "tracetools": { 4 | "cmake-args": [ 5 | "-DTRACETOOLS_DISABLED=ON", 6 | "-DTRACETOOLS_STATUS_CHECKING_TOOL=OFF" 7 | ] 8 | }, 9 | "rosidl_typesupport": { 10 | "cmake-args": [ 11 | "-DROSIDL_TYPESUPPORT_SINGLE_TYPESUPPORT=ON" 12 | ] 13 | }, 14 | "rcl": { 15 | "cmake-args": [ 16 | "-DBUILD_TESTING=OFF", 17 | "-DRCL_MICROROS=ON" 18 | ] 19 | }, 20 | "rcutils": { 21 | "cmake-args": [ 22 | "-DENABLE_TESTING=OFF", 23 | "-DRCUTILS_NO_FILESYSTEM=ON", 24 | "-DRCUTILS_NO_THREAD_SUPPORT=ON", 25 | "-DRCUTILS_NO_64_ATOMIC=ON", 26 | "-DRCUTILS_AVOID_DYNAMIC_ALLOCATION=ON" 27 | ] 28 | }, 29 | "microxrcedds_client": { 30 | "cmake-args": [ 31 | "-DUCLIENT_PIC=OFF", 32 | "-DUCLIENT_PROFILE_UDP=OFF", 33 | "-DUCLIENT_PROFILE_TCP=OFF", 34 | "-DUCLIENT_PROFILE_DISCOVERY=OFF", 35 | "-DUCLIENT_PROFILE_SERIAL=OFF", 36 | "-UCLIENT_PROFILE_STREAM_FRAMING=ON", 37 | "-DUCLIENT_PROFILE_CUSTOM_TRANSPORT=ON" 38 | ] 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /platform_code/arduino/wifi/micro_ros_transport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | extern "C" { 12 | 13 | static WiFiUDP udp_client; 14 | 15 | bool platformio_transport_open(struct uxrCustomTransport * transport) 16 | { 17 | struct micro_ros_agent_locator * locator = (struct micro_ros_agent_locator *) transport->args; 18 | return true == udp_client.begin(locator->port); 19 | } 20 | 21 | bool platformio_transport_close(struct uxrCustomTransport * transport) 22 | { 23 | udp_client.stop(); 24 | return true; 25 | } 26 | 27 | size_t platformio_transport_write(struct uxrCustomTransport * transport, const uint8_t *buf, size_t len, uint8_t *errcode) 28 | { 29 | (void)errcode; 30 | 31 | struct micro_ros_agent_locator *locator = (struct micro_ros_agent_locator *)transport->args; 32 | 33 | size_t sent = 0; 34 | if(true == udp_client.beginPacket(locator->address, locator->port)){ 35 | sent = udp_client.write(buf, len); 36 | sent = true == udp_client.endPacket() ? sent : 0; 37 | } 38 | 39 | udp_client.flush(); 40 | 41 | return sent; 42 | } 43 | 44 | size_t platformio_transport_read(struct uxrCustomTransport * transport, uint8_t *buf, size_t len, int timeout, uint8_t *errcode) 45 | { 46 | (void)errcode; 47 | 48 | int64_t start_time = uxr_millis(); 49 | 50 | while ((uxr_millis() - start_time) < ((int64_t)timeout) && udp_client.parsePacket() == 0) { 51 | delay(1); 52 | } 53 | 54 | size_t available = 0; 55 | if(udp_client.available()){ 56 | available = udp_client.read(buf, len); 57 | } 58 | 59 | return (available > 0) ? available : 0; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /platform_code/arduino/native_ethernet/micro_ros_transport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | extern "C" { 11 | 12 | static EthernetUDP udp_client; 13 | 14 | bool platformio_transport_open(struct uxrCustomTransport * transport) 15 | { 16 | struct micro_ros_agent_locator *locator = (struct micro_ros_agent_locator *)transport->args; 17 | return true == udp_client.begin(locator->port); 18 | } 19 | 20 | bool platformio_transport_close(struct uxrCustomTransport * transport) 21 | { 22 | udp_client.stop(); 23 | return true; 24 | } 25 | 26 | size_t platformio_transport_write(struct uxrCustomTransport * transport, const uint8_t *buf, size_t len, uint8_t *errcode) 27 | { 28 | (void)errcode; 29 | 30 | struct micro_ros_agent_locator *locator = (struct micro_ros_agent_locator *)transport->args; 31 | 32 | size_t sent = 0; 33 | if(true == udp_client.beginPacket(locator->address, locator->port)){ 34 | sent = udp_client.write(buf, len); 35 | sent = true == udp_client.endPacket() ? sent : 0; 36 | } 37 | 38 | udp_client.flush(); 39 | 40 | return sent; 41 | } 42 | 43 | size_t platformio_transport_read(struct uxrCustomTransport * transport, uint8_t *buf, size_t len, int timeout, uint8_t *errcode) 44 | { 45 | (void)errcode; 46 | 47 | int64_t start_time = uxr_millis(); 48 | 49 | while ((uxr_millis() - start_time) < ((int64_t)timeout) && udp_client.parsePacket() == 0) { 50 | delay(1); 51 | } 52 | 53 | size_t available = 0; 54 | if(udp_client.available()){ 55 | available = udp_client.read(buf, len); 56 | } 57 | 58 | return (available > 0) ? available : 0; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /platform_code/arduino/wifi_nina/micro_ros_transport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | extern "C" { 12 | 13 | static WiFiUDP udp_client; 14 | 15 | bool platformio_transport_open(struct uxrCustomTransport * transport) 16 | { 17 | struct micro_ros_agent_locator * locator = (struct micro_ros_agent_locator *) transport->args; 18 | return true == udp_client.begin(locator->port); 19 | } 20 | 21 | bool platformio_transport_close(struct uxrCustomTransport * transport) 22 | { 23 | udp_client.stop(); 24 | return true; 25 | } 26 | 27 | size_t platformio_transport_write(struct uxrCustomTransport * transport, const uint8_t *buf, size_t len, uint8_t *errcode) 28 | { 29 | (void)errcode; 30 | 31 | struct micro_ros_agent_locator *locator = (struct micro_ros_agent_locator *)transport->args; 32 | 33 | size_t sent = 0; 34 | if(true == udp_client.beginPacket(locator->address, locator->port)){ 35 | sent = udp_client.write(buf, len); 36 | sent = true == udp_client.endPacket() ? sent : 0; 37 | } 38 | 39 | udp_client.flush(); 40 | 41 | return sent; 42 | } 43 | 44 | size_t platformio_transport_read(struct uxrCustomTransport * transport, uint8_t *buf, size_t len, int timeout, uint8_t *errcode) 45 | { 46 | (void)errcode; 47 | 48 | int64_t start_time = uxr_millis(); 49 | 50 | while ((uxr_millis() - start_time) < ((int64_t)timeout) && udp_client.parsePacket() == 0) { 51 | delay(1); 52 | } 53 | 54 | size_t available = 0; 55 | if(udp_client.available()){ 56 | available = udp_client.read(buf, len); 57 | } 58 | 59 | return (available > 0) ? available : 0; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /examples/micro-ros_publisher/src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #if !defined(MICRO_ROS_TRANSPORT_ARDUINO_SERIAL) 11 | #error This example is only avaliable for Arduino framework with serial transport. 12 | #endif 13 | 14 | rcl_publisher_t publisher; 15 | std_msgs__msg__Int32 msg; 16 | 17 | rclc_executor_t executor; 18 | rclc_support_t support; 19 | rcl_allocator_t allocator; 20 | rcl_node_t node; 21 | rcl_timer_t timer; 22 | 23 | #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}} 24 | #define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}} 25 | 26 | // Error handle loop 27 | void error_loop() { 28 | while(1) { 29 | delay(100); 30 | } 31 | } 32 | 33 | void timer_callback(rcl_timer_t * timer, int64_t last_call_time) { 34 | RCLC_UNUSED(last_call_time); 35 | if (timer != NULL) { 36 | RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL)); 37 | msg.data++; 38 | } 39 | } 40 | 41 | void setup() { 42 | // Configure serial transport 43 | Serial.begin(115200); 44 | set_microros_serial_transports(Serial); 45 | delay(2000); 46 | 47 | allocator = rcl_get_default_allocator(); 48 | 49 | //create init_options 50 | RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); 51 | 52 | // create node 53 | RCCHECK(rclc_node_init_default(&node, "micro_ros_platformio_node", "", &support)); 54 | 55 | // create publisher 56 | RCCHECK(rclc_publisher_init_default( 57 | &publisher, 58 | &node, 59 | ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), 60 | "micro_ros_platformio_node_publisher")); 61 | 62 | // create timer, 63 | const unsigned int timer_timeout = 1000; 64 | RCCHECK(rclc_timer_init_default( 65 | &timer, 66 | &support, 67 | RCL_MS_TO_NS(timer_timeout), 68 | timer_callback)); 69 | 70 | // create executor 71 | RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator)); 72 | RCCHECK(rclc_executor_add_timer(&executor, &timer)); 73 | 74 | msg.data = 0; 75 | } 76 | 77 | void loop() { 78 | delay(100); 79 | RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100))); 80 | } 81 | -------------------------------------------------------------------------------- /platform_code/arduino/ethernet/micro_ros_transport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | void* transport_args; 12 | 13 | extern "C" { 14 | 15 | static WiFiUDP udp_client; 16 | 17 | bool platformio_transport_open(struct uxrCustomTransport * transport) 18 | { 19 | transport_args = transport->args; 20 | struct micro_ros_agent_locator * locator = (struct micro_ros_agent_locator *) transport->args; 21 | bool success = udp_client.begin(locator->port); 22 | return success; 23 | } 24 | 25 | bool platformio_transport_close(struct uxrCustomTransport * transport) 26 | { 27 | transport_args = nullptr; 28 | udp_client.stop(); 29 | return true; 30 | } 31 | 32 | size_t platformio_transport_write(struct uxrCustomTransport * transport, const uint8_t *buf, size_t len, uint8_t *errcode) 33 | { 34 | struct micro_ros_agent_locator *locator = (struct micro_ros_agent_locator *)transport->args; 35 | 36 | size_t sent = 0; 37 | if(true == udp_client.beginPacket(locator->address, locator->port)) { 38 | sent = udp_client.write(buf, len); 39 | if(true == udp_client.endPacket()) { 40 | udp_client.flush(); 41 | if(sent < len) { 42 | *errcode = 1; // Incomplete write 43 | return sent; 44 | } 45 | return sent; 46 | } 47 | } 48 | 49 | *errcode = 2; // Write failed 50 | return 0; 51 | } 52 | 53 | size_t platformio_transport_read(struct uxrCustomTransport * transport, uint8_t *buf, size_t len, int timeout, uint8_t *errcode) 54 | { 55 | int64_t start_time = uxr_millis(); 56 | 57 | // Wait for packet or timeout 58 | while ((uxr_millis() - start_time) < ((int64_t)timeout)) { 59 | int packet_size = udp_client.parsePacket(); 60 | if(packet_size > 0) { 61 | size_t available = udp_client.read(buf, len); 62 | if(available < len) { 63 | *errcode = 1; // Incomplete read 64 | return available; 65 | } 66 | return available; 67 | } 68 | delay(1); 69 | } 70 | 71 | *errcode = 2; // Timeout 72 | return 0; 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | Changelog for package micro_ros_platformio 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4 | 5 | 2.0.0 (2023-06-12) 6 | ------------------ 7 | * Iron release (`#102 `_) 8 | * Update rolling sources (`#99 `_) 9 | * Set rmw default implementation (`#62 `_) 10 | * Add rosidl_core (`#54 `_) 11 | * Fix Arduino with POSIX (`#48 `_) 12 | * Fix generation of idedata (`#44 `_) 13 | * micro_ros_platformio works on Raspberry Pi Pico (`#39 `_) 14 | * Fix native ethernet (`#37 `_) 15 | * Fix user meta path (`#34 `_) 16 | * Fix project environment modifications (`#36 `_) 17 | * Fix wifi transport setup (`#29 `_) 18 | 19 | 1.0.0 (2022-05-25) 20 | ------------------ 21 | * Add humble as default ROS2 distro (`#27 `_) 22 | * Allow custom transports (`#21 `_) 23 | * Make clean_microros target be listed in IDE (`#23 `_) 24 | * Add libmicroros directory to gitignore (`#22 `_) 25 | * Add clean to source ROS2 (`#25 `_) 26 | * Update banner (`#19 `_) 27 | * Add foxy (`#18 `_) 28 | * Add rolling (`#17 `_) 29 | * Add examples (`#16 `_) 30 | * Add clean step and build error checks (`#15 `_) 31 | * Initial readme changes (`#3 `_) 32 | * Fix transport selection (`#11 `_) 33 | * Extra packages implementation (`#12 `_) 34 | * Fix SCons interface (`#10 `_) 35 | * Fix __attribute_\_ (`#9 `_) 36 | * Fix Portenta H7 (`#8 `_) 37 | * Fix RP2040 WiFi (`#7 `_) 38 | * Add configurable Arduino Serial (`#6 `_) -------------------------------------------------------------------------------- /platform_code/arduino/ethernet/micro_ros_transport.h: -------------------------------------------------------------------------------- 1 | #ifndef MICRO_ROS_TRANSPORT_H_ 2 | #define MICRO_ROS_TRANSPORT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef void (*ethernet_event_callback_t)(arduino_event_id_t event, void* event_info); 9 | 10 | struct micro_ros_agent_locator { 11 | IPAddress address; // Agent IP address 12 | IPAddress gateway; // Gateway IP address 13 | const char* hostname; // Device hostname 14 | int port; // Agent port 15 | 16 | ethernet_event_callback_t on_eth_event = nullptr; 17 | }; 18 | 19 | extern void* transport_args; 20 | 21 | extern "C" { 22 | bool platformio_transport_open(struct uxrCustomTransport * transport); 23 | bool platformio_transport_close(struct uxrCustomTransport * transport); 24 | size_t platformio_transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * err); 25 | size_t platformio_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err); 26 | } 27 | 28 | static void ethernet_event_handler(WiFiEvent_t event) { 29 | auto* locator = (micro_ros_agent_locator*)transport_args; 30 | if (!locator || !locator->on_eth_event) return; 31 | 32 | switch (event) { 33 | case ARDUINO_EVENT_ETH_START: 34 | if (locator->hostname != nullptr) { 35 | ETH.setHostname(locator->hostname); 36 | } 37 | locator->on_eth_event(event, nullptr); 38 | break; 39 | 40 | case ARDUINO_EVENT_ETH_CONNECTED: 41 | locator->on_eth_event(event, nullptr); 42 | break; 43 | 44 | case ARDUINO_EVENT_ETH_GOT_IP: { 45 | IPAddress ip = ETH.localIP(); 46 | locator->on_eth_event(event, &ip); 47 | break; 48 | } 49 | 50 | case ARDUINO_EVENT_ETH_DISCONNECTED: 51 | locator->on_eth_event(event, nullptr); 52 | break; 53 | 54 | case ARDUINO_EVENT_ETH_STOP: 55 | locator->on_eth_event(event, nullptr); 56 | break; 57 | 58 | default: 59 | break; 60 | } 61 | } 62 | 63 | static inline void set_microros_ethernet_transports( 64 | IPAddress client_ip, 65 | IPAddress gateway, 66 | IPAddress netmask, 67 | IPAddress agent_ip, 68 | uint16_t agent_port, 69 | const char* hostname = nullptr, 70 | ethernet_event_callback_t event_callback = nullptr 71 | ) { 72 | static struct micro_ros_agent_locator locator; 73 | 74 | WiFi.onEvent(ethernet_event_handler); 75 | ETH.begin(); 76 | ETH.config(client_ip, gateway, netmask); 77 | delay(1000); 78 | 79 | locator.address = agent_ip; 80 | locator.gateway = gateway; 81 | locator.hostname = hostname; 82 | locator.port = agent_port; 83 | locator.on_eth_event = event_callback; 84 | 85 | rmw_uros_set_custom_transport( 86 | false, 87 | (void *) &locator, 88 | platformio_transport_open, 89 | platformio_transport_close, 90 | platformio_transport_write, 91 | platformio_transport_read 92 | ); 93 | } 94 | 95 | #endif // MICRO_ROS_TRANSPORT_H_ -------------------------------------------------------------------------------- /examples/ethernet_pubsub/README.md: -------------------------------------------------------------------------------- 1 | # micro-ROS Ethernet Publisher/Subscriber Example 2 | 3 | This example demonstrates how to create a micro-ROS node on an ESP32 that communicates over Ethernet with a ROS 2 system. The node implements a simple request-response pattern where it listens for names and responds with greetings. 4 | 5 | ## Overview 6 | 7 | The ESP32 node: 8 | - Subscribes to the topic `micro_ros_name` 9 | - When it receives a name (e.g., "John"), it publishes "Hello John!" to the topic `micro_ros_response` 10 | - Uses Ethernet for communication with the ROS 2 system 11 | - Operates on ROS 2 domain ID 8 12 | 13 | ## Hardware Requirements 14 | 15 | - ESP32 development board 16 | - LAN8710 or LAN8720 Ethernet PHY module 17 | - Ethernet cable 18 | 19 | ### Ethernet PHY Wiring 20 | 21 | Connect the LAN8720 module to the ESP32 using the following pins: 22 | 23 | | ESP32 GPIO | LAN87XX Pin | Description | 24 | |------------|-------------|-------------| 25 | | GPIO 5 | POWER | PHY Power | 26 | | GPIO 23 | MDC | Clock | 27 | | GPIO 18 | MDIO | Data | 28 | | GPIO 17 | Clock | 50MHz Clock | 29 | 30 | ## Network Configuration 31 | 32 | The example uses the following network configuration (configurable in `main.cpp`): 33 | 34 | - ESP32 IP: 10.4.4.177 35 | - Gateway: 10.4.4.1 36 | - Netmask: 255.255.255.0 37 | - Agent IP: 10.4.4.187 38 | - Agent Port: 8888 39 | 40 | ## Software Setup 41 | 42 | 1. Install PlatformIO (if not already installed) 43 | 2. Install Docker and Docker Compose 44 | 3. Clone this repository 45 | 4. Navigate to the example directory: 46 | ```bash 47 | cd examples/ethernet_pubsub 48 | ``` 49 | 50 | ## Building and Flashing 51 | 52 | 1. Build and flash the firmware: 53 | ```bash 54 | pio run -t upload 55 | ``` 56 | 57 | 2. (Optional) Monitor the serial output: 58 | ```bash 59 | pio device monitor 60 | ``` 61 | 62 | ## Running the micro-ROS Agent and RQT 63 | 64 | 1. Allow X11 connections from Docker (needed for RQT): 65 | ```bash 66 | xhost +local:docker 67 | ``` 68 | 69 | 2. Start the micro-ROS agent and RQT: 70 | ```bash 71 | docker compose up 72 | ``` 73 | 74 | This will start: 75 | - A micro-ROS agent listening on UDP port 8888 76 | - RQT with proper X11 forwarding for visualization 77 | 78 | ## Testing the Example 79 | 80 | 1. In RQT: 81 | - Click on Plugins -> Topics -> Message Publisher 82 | - Add the topic `/micro_ros_name` 83 | - Set the message type to `std_msgs/String` 84 | - Enter a name in the `data` field and click the checkbox to publish 85 | 86 | 2. To view responses: 87 | - In RQT, click on Plugins -> Topics -> Topic Monitor 88 | - Subscribe to `/micro_ros_response` 89 | - You should see responses like "Hello !" when you publish names 90 | 91 | ## Troubleshooting 92 | 93 | - If RQT doesn't appear, ensure X11 forwarding is properly set up with `xhost +local:docker` 94 | - Check the serial monitor for connection status and debugging information 95 | - Verify that your network configuration matches the settings in `main.cpp` 96 | - Ensure all Ethernet pins are properly connected 97 | 98 | ## Cleaning Up 99 | 100 | 1. Stop the Docker containers: 101 | ```bash 102 | docker compose down 103 | ``` 104 | 105 | 2. Revoke X11 permissions (optional): 106 | ```bash 107 | xhost -local:docker 108 | ``` 109 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | platformio_toolchain.cmake 2 | libmicroros/ 3 | 4 | ################# 5 | ## Eclipse 6 | ################# 7 | 8 | *.pydevproject 9 | .project 10 | .metadata 11 | bin/ 12 | tmp/ 13 | *.tmp 14 | *.bak 15 | *.swp 16 | *~.nib 17 | local.properties 18 | .classpath 19 | .settings/ 20 | .loadpath 21 | 22 | # External tool builders 23 | .externalToolBuilders/ 24 | 25 | # Locally stored "Eclipse launch configurations" 26 | *.launch 27 | 28 | # CDT-specific 29 | .cproject 30 | 31 | # PDT-specific 32 | .buildpath 33 | 34 | 35 | ################# 36 | ## Visual Studio 37 | ################# 38 | 39 | ## Ignore Visual Studio temporary files, build results, and 40 | ## files generated by popular Visual Studio add-ons. 41 | 42 | # User-specific files 43 | *.suo 44 | *.user 45 | *.sln.docstates 46 | 47 | # Build results 48 | 49 | [Dd]ebug/ 50 | [Rr]elease/ 51 | x64/ 52 | build/ 53 | [Bb]in/ 54 | [Oo]bj/ 55 | 56 | # MSTest test Results 57 | [Tt]est[Rr]esult*/ 58 | [Bb]uild[Ll]og.* 59 | 60 | *_i.c 61 | *_p.c 62 | *.ilk 63 | *.obj 64 | *.pch 65 | *.pdb 66 | *.pgc 67 | *.pgd 68 | *.rsp 69 | *.sbr 70 | *.tlb 71 | *.tli 72 | *.tlh 73 | *.tmp 74 | *.tmp_proj 75 | *.log 76 | *.vspscc 77 | *.vssscc 78 | .builds 79 | *.pidb 80 | *.log 81 | *.scc 82 | 83 | # Visual C++ cache files 84 | ipch/ 85 | *.aps 86 | *.ncb 87 | *.opensdf 88 | *.sdf 89 | *.cachefile 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | *.ncrunch* 111 | .*crunch*.local.xml 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.Publish.xml 131 | *.pubxml 132 | 133 | # NuGet Packages Directory 134 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 135 | #packages/ 136 | 137 | # Windows Azure Build Output 138 | csx 139 | *.build.csdef 140 | 141 | # Windows Store app package directory 142 | AppPackages/ 143 | 144 | # Others 145 | sql/ 146 | *.Cache 147 | ClientBin/ 148 | [Ss]tyle[Cc]op.* 149 | ~$* 150 | *~ 151 | *.dbmdl 152 | *.[Pp]ublish.xml 153 | *.pfx 154 | *.publishsettings 155 | 156 | # RIA/Silverlight projects 157 | Generated_Code/ 158 | 159 | # Backup & report files from converting an old project file to a newer 160 | # Visual Studio version. Backup files are not needed, because we have git ;-) 161 | _UpgradeReport_Files/ 162 | Backup*/ 163 | UpgradeLog*.XML 164 | UpgradeLog*.htm 165 | 166 | # SQL Server files 167 | App_Data/*.mdf 168 | App_Data/*.ldf 169 | 170 | ############# 171 | ## Windows detritus 172 | ############# 173 | 174 | # Windows image file caches 175 | Thumbs.db 176 | ehthumbs.db 177 | 178 | # Folder config file 179 | Desktop.ini 180 | 181 | # Recycle Bin used on file shares 182 | $RECYCLE.BIN/ 183 | 184 | # Mac crap 185 | .DS_Store 186 | 187 | 188 | ############# 189 | ## Python 190 | ############# 191 | 192 | *.py[co] 193 | 194 | # Packages 195 | *.egg 196 | *.egg-info 197 | dist/ 198 | build/ 199 | eggs/ 200 | parts/ 201 | var/ 202 | sdist/ 203 | develop-eggs/ 204 | .installed.cfg 205 | 206 | # Installer logs 207 | pip-log.txt 208 | 209 | # Unit test / coverage reports 210 | .coverage 211 | .tox 212 | 213 | #Translations 214 | *.mo 215 | 216 | #Mr Developer 217 | .mr.developer.cfg 218 | -------------------------------------------------------------------------------- /ci/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(MICRO_ROS_TRANSPORT_ARDUINO_WIFI) 4 | #include 5 | #elif defined(MICRO_ROS_TRANSPORT_ARDUINO_ETHERNET) 6 | #include 7 | #endif 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | // Test custom transports 20 | #if defined(MICRO_ROS_TRANSPORT_ARDUINO_CUSTOM) 21 | bool platformio_transport_open(struct uxrCustomTransport * transport) {return false;}; 22 | bool platformio_transport_close(struct uxrCustomTransport * transport) {return false;}; 23 | size_t platformio_transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * err) {return 0;}; 24 | size_t platformio_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err) {return 0;}; 25 | #endif 26 | 27 | // Test extra packages 28 | #include 29 | #include 30 | control_msgs__msg__JointControllerState control_message; 31 | my_custom_message__msg__MyCustomMessage custom_msg; 32 | 33 | rcl_publisher_t publisher; 34 | std_msgs__msg__Int32 msg; 35 | rclc_executor_t executor; 36 | rclc_support_t support; 37 | rcl_allocator_t allocator; 38 | rcl_node_t node; 39 | rcl_timer_t timer; 40 | 41 | #define LED_PIN 13 42 | 43 | #define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}} 44 | #define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}} 45 | 46 | 47 | void error_loop(){ 48 | while(1){ 49 | digitalWrite(LED_PIN, !digitalRead(LED_PIN)); 50 | delay(100); 51 | } 52 | } 53 | 54 | void timer_callback(rcl_timer_t * timer, int64_t last_call_time) 55 | { 56 | RCLC_UNUSED(last_call_time); 57 | if (timer != NULL) { 58 | RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL)); 59 | msg.data++; 60 | } 61 | } 62 | 63 | void setup() { 64 | 65 | #if defined(MICRO_ROS_TRANSPORT_ARDUINO_SERIAL) 66 | Serial.begin(115200); 67 | set_microros_serial_transports(Serial); 68 | #elif defined(MICRO_ROS_TRANSPORT_ARDUINO_NATIVE_ETHERNET) 69 | byte local_mac[] = { 0xAA, 0xBB, 0xCC, 0xEE, 0xDD, 0xFF }; 70 | IPAddress local_ip(192, 168, 1, 177); 71 | IPAddress agent_ip(192, 168, 1, 113); 72 | size_t agent_port = 8888; 73 | 74 | set_microros_native_ethernet_transports(local_mac, local_ip, agent_ip, agent_port); 75 | #elif defined(MICRO_ROS_TRANSPORT_ARDUINO_WIFI) || defined(MICRO_ROS_TRANSPORT_ARDUINO_WIFI_NINA) 76 | IPAddress agent_ip(192, 168, 1, 113); 77 | size_t agent_port = 8888; 78 | 79 | char ssid[] = "WIFI_SSID"; 80 | char psk[]= "WIFI_PSK"; 81 | 82 | set_microros_wifi_transports(ssid, psk, agent_ip, agent_port); 83 | #elif defined(MICRO_ROS_TRANSPORT_ARDUINO_ETHERNET) 84 | IPAddress local_ip(192, 168, 1, 177); 85 | IPAddress gateway(192, 168, 1, 1); 86 | IPAddress netmask(255, 255, 255, 0); 87 | IPAddress agent_ip(192, 168, 1, 113); 88 | size_t agent_port = 8888; 89 | 90 | set_microros_ethernet_transports(local_ip, gateway, netmask, agent_ip, agent_port, "micro-ros-eth"); 91 | #elif defined(MICRO_ROS_TRANSPORT_ARDUINO_CUSTOM) 92 | rmw_uros_set_custom_transport( 93 | MICROROS_TRANSPORTS_FRAMING_MODE, 94 | NULL, 95 | platformio_transport_open, 96 | platformio_transport_close, 97 | platformio_transport_write, 98 | platformio_transport_read 99 | ); 100 | #else 101 | #error "No transport defined" 102 | #endif 103 | 104 | pinMode(LED_PIN, OUTPUT); 105 | digitalWrite(LED_PIN, HIGH); 106 | 107 | delay(2000); 108 | 109 | allocator = rcl_get_default_allocator(); 110 | 111 | //create init_options 112 | RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); 113 | 114 | // create node 115 | RCCHECK(rclc_node_init_default(&node, "microros_platformio_node", "", &support)); 116 | 117 | // create publisher 118 | RCCHECK(rclc_publisher_init_default( 119 | &publisher, 120 | &node, 121 | ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32), 122 | "microros_platformio_publisher")); 123 | 124 | // create timer, 125 | RCCHECK(rclc_timer_init_default( 126 | &timer, 127 | &support, 128 | RCL_MS_TO_NS(100), 129 | timer_callback)); 130 | 131 | // create executor 132 | RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator)); 133 | RCCHECK(rclc_executor_add_timer(&executor, &timer)); 134 | 135 | msg.data = 0; 136 | } 137 | 138 | void loop() { 139 | RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100))); 140 | } -------------------------------------------------------------------------------- /ci/platformio.ini: -------------------------------------------------------------------------------- 1 | ; Humble test 2 | [env:portenta_h7_m7_humble] 3 | platform = ststm32 4 | board = portenta_h7_m7 5 | framework = arduino 6 | board_microros_transport = serial 7 | board_microros_distro = humble 8 | lib_deps = 9 | ../ 10 | 11 | ; Jazzy test 12 | [env:portenta_h7_m7_jazzy] 13 | platform = ststm32 14 | board = portenta_h7_m7 15 | framework = arduino 16 | board_microros_transport = serial 17 | board_microros_distro = jazzy 18 | lib_deps = 19 | ../ 20 | 21 | ; Kilted test 22 | [env:portenta_h7_m7_kilted] 23 | platform = ststm32 24 | board = portenta_h7_m7 25 | framework = arduino 26 | board_microros_transport = serial 27 | board_microros_distro = kilted 28 | lib_deps = 29 | ../ 30 | 31 | ; Rolling test 32 | [env:portenta_h7_m7_rolling] 33 | platform = ststm32 34 | board = portenta_h7_m7 35 | framework = arduino 36 | board_microros_transport = serial 37 | board_microros_distro = rolling 38 | lib_deps = 39 | ../ 40 | 41 | ; Serial platforms 42 | 43 | [env:portenta_h7_m7] 44 | platform = ststm32 45 | board = portenta_h7_m7 46 | framework = arduino 47 | board_microros_transport = serial 48 | lib_deps = 49 | ../ 50 | 51 | [env:teensy41] 52 | platform = teensy 53 | board = teensy41 54 | framework = arduino 55 | board_microros_transport = serial 56 | lib_deps = 57 | ../ 58 | 59 | [env:teensy40] 60 | platform = teensy 61 | board = teensy40 62 | framework = arduino 63 | board_microros_transport = serial 64 | lib_deps = 65 | ../ 66 | 67 | [env:teensy36] 68 | platform = teensy 69 | board = teensy36 70 | framework = arduino 71 | board_microros_transport = serial 72 | lib_deps = 73 | ../ 74 | 75 | [env:teensy35] 76 | platform = teensy 77 | board = teensy35 78 | framework = arduino 79 | board_microros_transport = serial 80 | lib_deps = 81 | ../ 82 | 83 | [env:teensy31] 84 | platform = teensy 85 | board = teensy31 86 | framework = arduino 87 | board_microros_transport = serial 88 | lib_deps = 89 | ../ 90 | 91 | [env:due] 92 | platform = atmelsam 93 | board = due 94 | framework = arduino 95 | board_microros_transport = serial 96 | lib_deps = 97 | ../ 98 | 99 | [env:zero] 100 | platform = atmelsam 101 | board = zero 102 | framework = arduino 103 | board_microros_transport = serial 104 | lib_deps = 105 | ../ 106 | 107 | [env:olimex_e407] 108 | platform = ststm32 109 | board = olimex_e407 110 | framework = arduino 111 | board_microros_transport = serial 112 | lib_deps = 113 | ../ 114 | 115 | [env:esp32dev] 116 | platform = espressif32 117 | board = esp32dev 118 | framework = arduino 119 | board_microros_transport = serial 120 | lib_deps = 121 | ../ 122 | 123 | [env:nanorp2040connect] 124 | platform = https://github.com/maxgerhardt/platform-raspberrypi.git 125 | board = nanorp2040connect 126 | board_build.core = earlephilhower 127 | framework = arduino 128 | board_microros_transport = serial 129 | board_microros_user_meta = atomic.meta 130 | lib_deps = 131 | ../ 132 | 133 | [env:pico] 134 | platform = https://github.com/maxgerhardt/platform-raspberrypi.git 135 | board = rpipico 136 | board_build.core = earlephilhower 137 | framework = arduino 138 | board_microros_transport = serial 139 | board_microros_user_meta = atomic.meta 140 | lib_deps = 141 | ../ 142 | 143 | [env:pico2] 144 | platform = https://github.com/maxgerhardt/platform-raspberrypi.git 145 | board = rpipico2 146 | board_build.core = earlephilhower 147 | framework = arduino 148 | board_microros_transport = serial 149 | board_microros_user_meta = atomic.meta 150 | lib_deps = 151 | ../ 152 | 153 | ; Ethernet platforms 154 | 155 | [env:teensy41_eth] 156 | platform = teensy 157 | board = teensy41 158 | framework = arduino 159 | board_microros_transport = native_ethernet 160 | lib_deps = 161 | ../ 162 | 163 | [env:esp32dev_ethernet] 164 | platform = espressif32 165 | board = esp32dev 166 | framework = arduino 167 | board_microros_transport = ethernet 168 | lib_deps = 169 | ../ 170 | 171 | ; WiFi platforms 172 | 173 | [env:portenta_h7_m7_wifi] 174 | platform = ststm32 175 | board = portenta_h7_m7 176 | framework = arduino 177 | board_microros_transport = wifi 178 | lib_deps = 179 | ../ 180 | 181 | [env:esp32dev_wifi] 182 | platform = espressif32 183 | board = esp32dev 184 | framework = arduino 185 | board_microros_transport = wifi 186 | lib_deps = 187 | ../ 188 | 189 | [env:nanorp2040connect_wifi] 190 | platform = https://github.com/maxgerhardt/platform-raspberrypi.git 191 | board = nanorp2040connect 192 | board_build.core = earlephilhower 193 | framework = arduino 194 | board_microros_transport = wifi_nina 195 | board_microros_user_meta = atomic.meta 196 | lib_deps = 197 | arduino-libraries/WiFiNINA 198 | ../ 199 | 200 | ; Custom transports 201 | 202 | [env:teensy41_custom] 203 | platform = teensy 204 | board = teensy41 205 | framework = arduino 206 | board_microros_transport = custom 207 | lib_deps = 208 | ../ 209 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Want to contribute? Great! You can do so through the standard GitHub pull 4 | request model. For large contributions we do encourage you to file a ticket in 5 | the GitHub issues tracking system prior to any code development to coordinate 6 | with the system_modes development team early in the process. Coordinating up 7 | front helps to avoid frustration later on. 8 | 9 | Your contribution must be licensed under the Apache-2.0 license, the license 10 | used by this project. 11 | 12 | ## Add / retain copyright notices 13 | 14 | Include a copyright notice and license in each new file to be contributed, 15 | consistent with the style used by this project. If your contribution contains 16 | code under the copyright of a third party, document its origin, license, and 17 | copyright holders. 18 | 19 | ## Sign your work 20 | 21 | This project tracks patch provenance and licensing using a modified Developer 22 | Certificate of Origin (DCO; from [OSDL][DCO]) and Signed-off-by tags initially 23 | developed by the Linux kernel project. 24 | 25 | ``` 26 | system_modes Developer's Certificate of Origin. Version 1.0 27 | 28 | By making a contribution to this project, I certify that: 29 | 30 | (a) The contribution was created in whole or in part by me and I 31 | have the right to submit it under the "Apache License, Version 2.0" 32 | ("Apache-2.0"); or 33 | 34 | (b) The contribution is based upon previous work that is covered by 35 | an appropriate open source license and I have the right under 36 | that license to submit that work with modifications, whether 37 | created in whole or in part by me, under the Apache-2.0 license; 38 | or 39 | 40 | (c) The contribution was provided directly to me by some other 41 | person who certified (a) or (b) and I have not modified it. 42 | 43 | (d) I understand and agree that this project and the contribution 44 | are public and that a record of the contribution (including all 45 | metadata and personal information I submit with it, including my 46 | sign-off) is maintained indefinitely and may be redistributed 47 | consistent with this project and the requirements of the Apache-2.0 48 | license or any open source license(s) involved, where they are 49 | relevant. 50 | 51 | (e) I am granting the contribution to this project under the terms of 52 | Apache-2.0. 53 | 54 | http://www.apache.org/licenses/LICENSE-2.0 55 | ``` 56 | 57 | With the sign-off in a commit message you certify that you authored the patch 58 | or otherwise have the right to submit it under an open source license. The 59 | procedure is simple: To certify above system_modes Developer's Certificate of 60 | Origin 1.0 for your contribution just append a line 61 | 62 | Signed-off-by: Random J Developer 63 | 64 | to every commit message using your real name or your pseudonym and a valid 65 | email address. 66 | 67 | If you have set your `user.name` and `user.email` git configs you can 68 | automatically sign the commit by running the git-commit command with the `-s` 69 | option. There may be multiple sign-offs if more than one developer was 70 | involved in authoring the contribution. 71 | 72 | For a more detailed description of this procedure, please see 73 | [SubmittingPatches][] which was extracted from the Linux kernel project, and 74 | which is stored in an external repository. 75 | 76 | ### Individual vs. Corporate Contributors 77 | 78 | Often employers or academic institution have ownership over code that is 79 | written in certain circumstances, so please do due diligence to ensure that 80 | you have the right to submit the code. 81 | 82 | If you are a developer who is authorized to contribute to system_modes on 83 | behalf of your employer, then please use your corporate email address in the 84 | Signed-off-by tag. Otherwise please use a personal email address. 85 | 86 | ## Maintain Copyright holder / Contributor list 87 | 88 | Each contributor is responsible for identifying themselves in the 89 | [NOTICE](NOTICE) file, the project's list of copyright holders and authors. 90 | Please add the respective information corresponding to the Signed-off-by tag 91 | as part of your first pull request. 92 | 93 | If you are a developer who is authorized to contribute to system_modes on 94 | behalf of your employer, then add your company / organization to the list of 95 | copyright holders in the [NOTICE](NOTICE) file. As author of a corporate 96 | contribution you can also add your name and corporate email address as in the 97 | Signed-off-by tag. 98 | 99 | If your contribution is covered by this project's DCO's clause "(c) The 100 | contribution was provided directly to me by some other person who certified 101 | (a) or (b) and I have not modified it", please add the appropriate copyright 102 | holder(s) to the [NOTICE](NOTICE) file as part of your contribution. 103 | 104 | 105 | [DCO]: http://web.archive.org/web/20070306195036/http://osdlab.org/newsroom/press_releases/2004/2004_05_24_dco.html 106 | 107 | [SubmittingPatches]: https://github.com/wking/signed-off-by/blob/7d71be37194df05c349157a2161c7534feaf86a4/Documentation/SubmittingPatches 108 | -------------------------------------------------------------------------------- /extra_script.py: -------------------------------------------------------------------------------- 1 | Import("projenv") 2 | Import("env") 3 | 4 | import os 5 | import shutil 6 | 7 | ########################## 8 | #### Global variables #### 9 | ########################## 10 | 11 | boards_metas = { 12 | "portenta_h7_m7" : "colcon.meta", 13 | "nanorp2040connect" : "colcon_verylowmem.meta", 14 | "teensy41" : "colcon.meta", 15 | "teensy40" : "colcon.meta", 16 | "teensy36" : "colcon_lowmem.meta", 17 | "teensy35" : "colcon_lowmem.meta", 18 | "teensy32" : "colcon_lowmem.meta", 19 | "teensy31" : "colcon_lowmem.meta", 20 | "esp32dev" : "colcon.meta", 21 | "olimex_e407" : "colcon.meta", 22 | "due" : "colcon_verylowmem.meta", 23 | "zero" : "colcon_verylowmem.meta", 24 | "pico": "colcon.meta" 25 | 26 | } 27 | 28 | project_options = env.GetProjectConfig().items(env=env["PIOENV"], as_dict=True) 29 | main_path = os.path.realpath(".") 30 | global_env = DefaultEnvironment() 31 | board = env['BOARD'] 32 | framework = env['PIOFRAMEWORK'][0] 33 | extra_packages_path = "{}/extra_packages".format(env['PROJECT_DIR']) 34 | 35 | selected_board_meta = boards_metas[board] if board in boards_metas else "colcon.meta" 36 | 37 | # Retrieve the required transport. Default kilted 38 | microros_distro = global_env.BoardConfig().get("microros_distro", "kilted") 39 | 40 | # Retrieve the required transport. Default serial 41 | microros_transport = global_env.BoardConfig().get("microros_transport", "serial") 42 | 43 | # Retrieve the user meta. Default none 44 | microros_user_meta = "{}/{}".format(env['PROJECT_DIR'], global_env.BoardConfig().get("microros_user_meta", "")) 45 | 46 | # Do not include build folder 47 | env['SRC_FILTER'] += ' -' 48 | 49 | ################################ 50 | #### Library custom targets #### 51 | ################################ 52 | 53 | def clean_microros_callback(*args, **kwargs): 54 | library_path = main_path + '/libmicroros' 55 | build_path = main_path + '/build' 56 | 57 | # Delete library and build folders 58 | shutil.rmtree(library_path, ignore_errors=True) 59 | shutil.rmtree(build_path, ignore_errors=True) 60 | 61 | print("micro-ROS library cleaned!") 62 | os._exit(0) 63 | 64 | if "clean_microros" not in global_env.get("__PIO_TARGETS", {}): 65 | global_env.AddCustomTarget("clean_microros", None, clean_microros_callback, title="Clean Micro-ROS", description="Clean Micro-ROS build environment") 66 | 67 | def clean_libmicroros_callback(*args, **kwargs): 68 | library_path = main_path + '/libmicroros' 69 | 70 | # Delete libmicroros folder 71 | shutil.rmtree(library_path, ignore_errors=True) 72 | 73 | print("libmicroros cleaned") 74 | os._exit(0) 75 | 76 | if "clean_libmicroros" not in global_env.get("__PIO_TARGETS", {}): 77 | global_env.AddCustomTarget("clean_libmicroros", None, clean_libmicroros_callback, title="Clean libmicroros", description="Clean libmicroros") 78 | 79 | 80 | def build_microros(*args, **kwargs): 81 | ############################## 82 | #### Install dependencies #### 83 | ############################## 84 | 85 | pip_packages = [x.split("==")[0] for x in os.popen('{} -m pip freeze'.format(env['PYTHONEXE'])).read().split('\n')] 86 | required_packages = ["catkin-pkg", "lark-parser", "colcon-common-extensions", "importlib-resources", "pyyaml", "pytz", "markupsafe==2.0.1", "empy==3.3.4"] 87 | if all([x in pip_packages for x in required_packages]): 88 | print("All required Python pip packages are installed") 89 | 90 | for p in [x for x in required_packages if x not in pip_packages]: 91 | print('Installing {} with pip at PlatformIO environment'.format(p)) 92 | env.Execute('$PYTHONEXE -m pip install {}'.format(p)) 93 | 94 | import microros_utils.library_builder as library_builder 95 | 96 | ################################# 97 | #### Build micro-ROS library #### 98 | ################################# 99 | 100 | print("Configuring {} with transport {}".format(board, microros_transport)) 101 | 102 | cmake_toolchain = library_builder.CMakeToolchain( 103 | main_path + "/platformio_toolchain.cmake", 104 | env['CC'], 105 | env['CXX'], 106 | env['AR'], 107 | "{} {} -DCLOCK_MONOTONIC=0 -D'__attribute__(x)='".format(' '.join(env['CFLAGS']), ' '.join(env['CCFLAGS'])), 108 | "{} {} -fno-rtti -DCLOCK_MONOTONIC=0 -D'__attribute__(x)='".format(' '.join(env['CXXFLAGS']), ' '.join(env['CCFLAGS'])) 109 | ) 110 | 111 | python_env_path = env['PROJECT_CORE_DIR'] + "/penv/bin/activate" 112 | builder = library_builder.Build(library_folder=main_path, packages_folder=extra_packages_path, distro=microros_distro, python_env=python_env_path) 113 | builder.run('{}/metas/{}'.format(main_path, selected_board_meta), cmake_toolchain.path, microros_user_meta) 114 | 115 | ####################################################### 116 | #### Add micro-ROS library/includes to environment #### 117 | ####################################################### 118 | 119 | # Add library 120 | if (board == "portenta_h7_m7" or board == "nanorp2040connect" or board == "pico"): 121 | # Workaround for including the library in the linker group 122 | # This solves a problem with duplicated symbols in Galactic 123 | global_env["_LIBFLAGS"] = "-Wl,--start-group " + global_env["_LIBFLAGS"] + " -l{} -Wl,--end-group".format(builder.library_name) 124 | else: 125 | global_env.Append(LIBS=[builder.library_name]) 126 | 127 | # Add library path 128 | global_env.Append(LIBPATH=[builder.library_path]) 129 | 130 | def update_env(): 131 | # Add required defines 132 | global_env.Append(CPPDEFINES=[("CLOCK_MONOTONIC", 1)]) 133 | 134 | # Add micro-ROS include path 135 | global_env.Append(CPPPATH=[main_path + "/libmicroros/include"]) 136 | 137 | # Add micro-ROS include path to library include path 138 | env.Append(CPPPATH=[main_path + "/libmicroros/include"]) 139 | 140 | # Add platformio library general include path 141 | global_env.Append(CPPPATH=[ 142 | main_path + "/platform_code", 143 | main_path + "/platform_code/{}/{}".format(framework, microros_transport)]) 144 | 145 | # Add platformio library general to library include path 146 | env.Append(CPPPATH=[ 147 | main_path + "/platform_code", 148 | main_path + "/platform_code/{}/{}".format(framework, microros_transport)]) 149 | 150 | if (board == "teensy31" or board == "teensy35" or board == "teensy36"): 151 | projenv.Append(LINKFLAGS=["--specs=nosys.specs"]) 152 | 153 | # Add micro-ROS defines to user application 154 | projenv.Append(CPPDEFINES=[('MICRO_ROS_TRANSPORT_{}_{}'.format(framework.upper(), microros_transport.upper()), 1)]) 155 | projenv.Append(CPPDEFINES=[('MICRO_ROS_DISTRO_{} '.format(microros_distro.upper()), 1)]) 156 | 157 | # Include path for framework 158 | global_env.Append(CPPPATH=[main_path + "/platform_code/{}".format(framework)]) 159 | 160 | # Add clock implementation 161 | env['SRC_FILTER'] += ' +'.format(framework) 162 | 163 | # Add transport sources according to the framework and the transport 164 | env['SRC_FILTER'] += ' +'.format(framework, microros_transport) 165 | 166 | 167 | from SCons.Script import COMMAND_LINE_TARGETS 168 | 169 | # Do not build library on clean_microros target or when IDE fetches C/C++ project metadata 170 | if set(["clean_microros", "clean_libmicroros", "_idedata", "idedata"]).isdisjoint(set(COMMAND_LINE_TARGETS)): 171 | build_microros() 172 | 173 | update_env() 174 | -------------------------------------------------------------------------------- /examples/ethernet_pubsub/src/main.cpp: -------------------------------------------------------------------------------- 1 | #define ETH_PHY_POWER 5 2 | #define ETH_PHY_MDC 23 3 | #define ETH_PHY_MDIO 18 4 | #define ETH_PHY_TYPE ETH_PHY_LAN8720 5 | #define ETH_PHY_ADDR 0 6 | #define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // Network configuration 16 | const IPAddress kClientIP(10, 4, 4, 177); 17 | const IPAddress kGateway(10, 4, 4, 1); 18 | const IPAddress kNetmask(255, 255, 255, 0); 19 | const IPAddress kAgentIP(10, 4, 4, 187); 20 | const uint16_t kAgentPort = 8888; 21 | const char* kHostname = "micro-ros-eth"; 22 | 23 | // ROS node configuration 24 | const char* kNodeName = "eth_pubsub_node"; 25 | const char* kPublisherTopic = "micro_ros_response"; 26 | const char* kSubscriberTopic = "micro_ros_name"; 27 | const int kExecutorTimeout = 100; // ms 28 | const size_t kDomainId = 8; // ROS domain ID 29 | 30 | // ROS entities 31 | rclc_executor_t executor; 32 | rclc_support_t support; 33 | rcl_allocator_t allocator; 34 | rcl_node_t node; 35 | rcl_publisher_t publisher; 36 | rcl_subscription_t subscriber; 37 | rcl_timer_t timer; 38 | 39 | // Message buffers 40 | std_msgs__msg__String received_msg; 41 | std_msgs__msg__String response_msg; 42 | char received_buffer[50]; 43 | char response_buffer[100]; 44 | 45 | // Connection management 46 | enum class ConnectionState { 47 | kInitializing, 48 | kWaitingForAgent, 49 | kConnecting, 50 | kConnected, 51 | kDisconnected 52 | }; 53 | ConnectionState connection_state = ConnectionState::kInitializing; 54 | 55 | // Forward declarations 56 | void HandleConnectionState(); 57 | void SubscriptionCallback(const void* msgin); 58 | void PublishResponse(); 59 | bool CreateEntities(); 60 | void DestroyEntities(); 61 | 62 | // Ethernet event callback 63 | void OnEthernetEvent(arduino_event_id_t event, void* event_info) { 64 | switch (event) { 65 | case ARDUINO_EVENT_ETH_CONNECTED: 66 | Serial.println("[ETH] Connected"); 67 | break; 68 | 69 | case ARDUINO_EVENT_ETH_DISCONNECTED: 70 | Serial.println("[ETH] Disconnected"); 71 | break; 72 | 73 | case ARDUINO_EVENT_ETH_GOT_IP: 74 | Serial.print("[ETH] Got IP: "); 75 | Serial.println(*(IPAddress*)event_info); 76 | break; 77 | 78 | default: 79 | break; 80 | } 81 | } 82 | 83 | void setup() { 84 | Serial.begin(115200); 85 | Serial.println("[INIT] Starting micro-ROS node..."); 86 | 87 | // Initialize message buffers 88 | received_msg.data.data = received_buffer; 89 | received_msg.data.capacity = sizeof(received_buffer); 90 | response_msg.data.data = response_buffer; 91 | response_msg.data.capacity = sizeof(response_buffer); 92 | 93 | // Initialize micro-ROS transport with unified callback 94 | set_microros_ethernet_transports( 95 | kClientIP, kGateway, kNetmask, kAgentIP, kAgentPort, 96 | kHostname, OnEthernetEvent 97 | ); 98 | 99 | delay(2000); 100 | connection_state = ConnectionState::kWaitingForAgent; 101 | } 102 | 103 | void loop() { 104 | HandleConnectionState(); 105 | delay(100); // Prevent tight loop 106 | } 107 | 108 | void HandleConnectionState() { 109 | switch (connection_state) { 110 | case ConnectionState::kWaitingForAgent: 111 | if (RMW_RET_OK == rmw_uros_ping_agent(200, 3)) { 112 | Serial.println("[ROS] Agent found, establishing connection..."); 113 | connection_state = ConnectionState::kConnecting; 114 | } 115 | break; 116 | 117 | case ConnectionState::kConnecting: 118 | if (CreateEntities()) { 119 | Serial.println("[ROS] Connected and ready!"); 120 | connection_state = ConnectionState::kConnected; 121 | } else { 122 | Serial.println("[ROS] Connection failed, retrying..."); 123 | connection_state = ConnectionState::kWaitingForAgent; 124 | } 125 | break; 126 | 127 | case ConnectionState::kConnected: 128 | if (RMW_RET_OK != rmw_uros_ping_agent(200, 3)) { 129 | Serial.println("[ROS] Agent disconnected!"); 130 | connection_state = ConnectionState::kDisconnected; 131 | } else { 132 | rclc_executor_spin_some(&executor, RCL_MS_TO_NS(kExecutorTimeout)); 133 | } 134 | break; 135 | 136 | case ConnectionState::kDisconnected: 137 | DestroyEntities(); 138 | Serial.println("[ROS] Waiting for agent..."); 139 | connection_state = ConnectionState::kWaitingForAgent; 140 | break; 141 | 142 | default: 143 | break; 144 | } 145 | } 146 | 147 | void SubscriptionCallback(const void* msgin) { 148 | const std_msgs__msg__String* msg = (const std_msgs__msg__String*)msgin; 149 | Serial.print("[SUB] Received: "); 150 | Serial.println(msg->data.data); 151 | 152 | // Create response message: "Hello !" 153 | snprintf(response_buffer, sizeof(response_buffer), "Hello %s!", msg->data.data); 154 | response_msg.data.size = strlen(response_buffer); 155 | 156 | // Publish response 157 | PublishResponse(); 158 | } 159 | 160 | void PublishResponse() { 161 | rcl_ret_t ret = rcl_publish(&publisher, &response_msg, NULL); 162 | if (ret == RCL_RET_OK) { 163 | Serial.print("[PUB] Published: "); 164 | Serial.println(response_msg.data.data); 165 | } else { 166 | Serial.println("[PUB] Error publishing message"); 167 | } 168 | } 169 | 170 | bool CreateEntities() { 171 | allocator = rcl_get_default_allocator(); 172 | 173 | // Initialize options and set domain ID 174 | rcl_init_options_t init_options = rcl_get_zero_initialized_init_options(); 175 | if (rcl_init_options_init(&init_options, allocator) != RCL_RET_OK) { 176 | return false; 177 | } 178 | if (rcl_init_options_set_domain_id(&init_options, kDomainId) != RCL_RET_OK) { 179 | return false; 180 | } 181 | 182 | // Initialize support with domain ID options 183 | if (rclc_support_init_with_options(&support, 0, NULL, &init_options, &allocator) != RCL_RET_OK) { 184 | return false; 185 | } 186 | 187 | // Clean up initialization options 188 | if (rcl_init_options_fini(&init_options) != RCL_RET_OK) { 189 | return false; 190 | } 191 | 192 | // Initialize node and rest of entities 193 | if (rclc_node_init_default(&node, kNodeName, "", &support) != RCL_RET_OK) { 194 | return false; 195 | } 196 | 197 | // Create publisher 198 | if (rclc_publisher_init_default(&publisher, &node, 199 | ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String), 200 | kPublisherTopic) != RCL_RET_OK) { 201 | return false; 202 | } 203 | 204 | // Create subscriber 205 | if (rclc_subscription_init_default(&subscriber, &node, 206 | ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String), 207 | kSubscriberTopic) != RCL_RET_OK) { 208 | return false; 209 | } 210 | 211 | // Initialize executor 212 | if (rclc_executor_init(&executor, &support.context, 1, &allocator) != RCL_RET_OK) { 213 | return false; 214 | } 215 | 216 | // Add subscriber to executor 217 | if (rclc_executor_add_subscription(&executor, &subscriber, &received_msg, 218 | &SubscriptionCallback, ON_NEW_DATA) != RCL_RET_OK) { 219 | return false; 220 | } 221 | 222 | return true; 223 | } 224 | 225 | void DestroyEntities() { 226 | rmw_context_t* rmw_context = rcl_context_get_rmw_context(&support.context); 227 | (void)rmw_uros_set_context_entity_destroy_session_timeout(rmw_context, 0); 228 | 229 | rcl_ret_t rc = RCL_RET_OK; 230 | rc = rcl_subscription_fini(&subscriber, &node); 231 | rc = rcl_publisher_fini(&publisher, &node); 232 | rclc_executor_fini(&executor); 233 | rc = rcl_node_fini(&node); 234 | rclc_support_fini(&support); 235 | } -------------------------------------------------------------------------------- /microros_utils/library_builder.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import yaml 3 | import shutil 4 | 5 | from .utils import run_cmd 6 | from .repositories import Repository, Sources 7 | 8 | class CMakeToolchain: 9 | def __init__(self, path, cc, cxx, ar, cflags, cxxflags): 10 | cmake_toolchain = """include(CMakeForceCompiler) 11 | set(CMAKE_SYSTEM_NAME Generic) 12 | 13 | set(CMAKE_CROSSCOMPILING 1) 14 | set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 15 | 16 | SET (CMAKE_C_COMPILER_WORKS 1) 17 | SET (CMAKE_CXX_COMPILER_WORKS 1) 18 | 19 | set(CMAKE_C_COMPILER {C_COMPILER}) 20 | set(CMAKE_CXX_COMPILER {CXX_COMPILER}) 21 | set(CMAKE_AR {AR_COMPILER}) 22 | 23 | set(CMAKE_C_FLAGS_INIT "{C_FLAGS}" CACHE STRING "" FORCE) 24 | set(CMAKE_CXX_FLAGS_INIT "{CXX_FLAGS}" CACHE STRING "" FORCE) 25 | 26 | set(__BIG_ENDIAN__ 0)""" 27 | 28 | cmake_toolchain = cmake_toolchain.format(C_COMPILER=cc, CXX_COMPILER=cxx, AR_COMPILER=ar, C_FLAGS=cflags, CXX_FLAGS=cxxflags) 29 | 30 | with open(path, "w") as file: 31 | file.write(cmake_toolchain) 32 | 33 | self.path = os.path.realpath(file.name) 34 | 35 | class Build: 36 | def __init__(self, library_folder, packages_folder, distro, python_env): 37 | self.library_folder = library_folder 38 | self.packages_folder = packages_folder 39 | self.build_folder = library_folder + "/build" 40 | self.distro = distro 41 | 42 | self.dev_packages = [] 43 | self.mcu_packages = [] 44 | 45 | self.dev_folder = self.build_folder + '/dev' 46 | self.dev_src_folder = self.dev_folder + '/src' 47 | self.mcu_folder = self.build_folder + '/mcu' 48 | self.mcu_src_folder = self.mcu_folder + '/src' 49 | 50 | self.library_path = library_folder + '/libmicroros' 51 | self.library = self.library_path + "/libmicroros.a" 52 | self.includes = self.library_path+ '/include' 53 | self.library_name = "microros" 54 | self.python_env = python_env 55 | self.env = {} 56 | 57 | def run(self, meta, toolchain, user_meta = ""): 58 | if os.path.exists(self.library): 59 | print("micro-ROS already built") 60 | return 61 | 62 | self.check_env() 63 | self.download_dev_environment() 64 | self.build_dev_environment() 65 | self.download_mcu_environment() 66 | self.build_mcu_environment(meta, toolchain, user_meta) 67 | self.package_mcu_library() 68 | 69 | def ignore_package(self, name): 70 | for p in self.mcu_packages: 71 | if p.name == name: 72 | p.ignore() 73 | 74 | def check_env(self): 75 | ROS_DISTRO = os.getenv('ROS_DISTRO') 76 | 77 | if (ROS_DISTRO): 78 | PATH = os.getenv('PATH') 79 | os.environ['PATH'] = PATH.replace('/opt/ros/{}/bin:'.format(ROS_DISTRO), '') 80 | os.environ.pop('AMENT_PREFIX_PATH', None) 81 | 82 | RMW_IMPLEMENTATION = os.getenv('RMW_IMPLEMENTATION') 83 | 84 | if (RMW_IMPLEMENTATION): 85 | os.environ['RMW_IMPLEMENTATION'] = "rmw_microxrcedds" 86 | 87 | self.env = os.environ.copy() 88 | 89 | def download_dev_environment(self): 90 | os.makedirs(self.dev_src_folder, exist_ok=True) 91 | print("Downloading micro-ROS dev dependencies") 92 | for repo in Sources.dev_environments[self.distro]: 93 | repo.clone(self.dev_src_folder) 94 | print("\t - Downloaded {}".format(repo.name)) 95 | self.dev_packages.extend(repo.get_packages()) 96 | 97 | def build_dev_environment(self): 98 | print("Building micro-ROS dev dependencies") 99 | 100 | # Fix build: Ignore rmw_test_fixture_implementation in rolling 101 | touch_command = '' 102 | if self.distro in ('rolling', 'kilted'): 103 | touch_command = 'touch src/ament_cmake_ros/rmw_test_fixture_implementation/COLCON_IGNORE && ' 104 | 105 | command = "cd {} && {} . {} && colcon build --cmake-args -DBUILD_TESTING=OFF -DPython3_EXECUTABLE=`which python`".format(self.dev_folder, touch_command, self.python_env) 106 | result = run_cmd(command, env=self.env) 107 | 108 | if 0 != result.returncode: 109 | print("Build dev micro-ROS environment failed: \n {}".format(result.stderr.decode("utf-8"))) 110 | sys.exit(1) 111 | 112 | def download_mcu_environment(self): 113 | os.makedirs(self.mcu_src_folder, exist_ok=True) 114 | print("Downloading micro-ROS library") 115 | for repo in Sources.mcu_environments[self.distro]: 116 | repo.clone(self.mcu_src_folder) 117 | self.mcu_packages.extend(repo.get_packages()) 118 | for package in repo.get_packages(): 119 | if package.name in Sources.ignore_packages[self.distro] or package.name.endswith("_cpp"): 120 | package.ignore() 121 | 122 | print('\t - Downloaded {}{}'.format(package.name, " (ignored)" if package.ignored else "")) 123 | 124 | self.download_extra_packages() 125 | 126 | def download_extra_packages(self): 127 | if not os.path.exists(self.packages_folder): 128 | print("\t - Extra packages folder not found, skipping...") 129 | return 130 | 131 | print("Checking extra packages") 132 | 133 | # Load and clone repositories from extra_packages.repos file 134 | extra_repos = self.get_repositories_from_yaml("{}/extra_packages.repos".format(self.packages_folder)) 135 | for repo_name in extra_repos: 136 | repo_values = extra_repos[repo_name] 137 | version = repo_values['version'] if 'version' in repo_values else None 138 | Repository(repo_name, repo_values['url'], self.distro, version).clone(self.mcu_src_folder) 139 | print("\t - Downloaded {}".format(repo_name)) 140 | 141 | extra_folders = os.listdir(self.packages_folder) 142 | if 'extra_packages.repos' in extra_folders: 143 | extra_folders.remove('extra_packages.repos') 144 | 145 | for folder in extra_folders: 146 | print("\t - Adding {}".format(folder)) 147 | 148 | shutil.copytree(self.packages_folder, self.mcu_src_folder, ignore=shutil.ignore_patterns('extra_packages.repos'), dirs_exist_ok=True) 149 | 150 | def get_repositories_from_yaml(self, yaml_file): 151 | repos = {} 152 | try: 153 | with open(yaml_file, 'r') as repos_file: 154 | root = yaml.safe_load(repos_file) 155 | repositories = root['repositories'] 156 | 157 | if repositories: 158 | for path in repositories: 159 | repo = {} 160 | attributes = repositories[path] 161 | try: 162 | repo['type'] = attributes['type'] 163 | repo['url'] = attributes['url'] 164 | if 'version' in attributes: 165 | repo['version'] = attributes['version'] 166 | except KeyError as e: 167 | continue 168 | repos[path] = repo 169 | except (yaml.YAMLError, KeyError, TypeError) as e: 170 | print("Error on {}: {}".format(yaml_file, e)) 171 | finally: 172 | return repos 173 | 174 | def build_mcu_environment(self, meta_file, toolchain_file, user_meta = ""): 175 | print("Building micro-ROS library") 176 | 177 | common_meta_path = self.library_folder + '/metas/common.meta' 178 | colcon_command = '. {} && colcon build --merge-install --packages-ignore-regex=.*_cpp --metas {} {} {} --cmake-args -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=OFF -DTHIRDPARTY=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE={} -DPython3_EXECUTABLE=`which python`'.format(self.python_env, common_meta_path, meta_file, user_meta, toolchain_file) 179 | command = "cd {} && . {}/install/setup.sh && {}".format(self.mcu_folder, self.dev_folder, colcon_command) 180 | result = run_cmd(command, env=self.env) 181 | 182 | if 0 != result.returncode: 183 | print("Build mcu micro-ROS environment failed: \n{}".format(result.stderr.decode("utf-8"))) 184 | sys.exit(1) 185 | 186 | def package_mcu_library(self): 187 | binutils_path = self.resolve_binutils_path() 188 | aux_folder = self.build_folder + "/aux" 189 | 190 | shutil.rmtree(aux_folder, ignore_errors=True) 191 | shutil.rmtree(self.library_path, ignore_errors=True) 192 | os.makedirs(aux_folder, exist_ok=True) 193 | os.makedirs(self.library_path, exist_ok=True) 194 | for root, dirs, files in os.walk(self.mcu_folder + "/install/lib"): 195 | for f in files: 196 | if f.endswith('.a'): 197 | os.makedirs(aux_folder + "/naming", exist_ok=True) 198 | os.chdir(aux_folder + "/naming") 199 | os.system("{}ar x {}".format(binutils_path, root + "/" + f)) 200 | for obj in [x for x in os.listdir() if x.endswith('obj')]: 201 | os.rename(obj, '../' + f.split('.')[0] + "__" + obj) 202 | 203 | os.chdir(aux_folder) 204 | command = "{binutils}ar rc libmicroros.a $(ls *.o *.obj 2> /dev/null); rm *.o *.obj 2> /dev/null; {binutils}ranlib libmicroros.a".format(binutils=binutils_path) 205 | result = run_cmd(command) 206 | 207 | if 0 != result.returncode: 208 | print("micro-ROS static library build failed: \n{}".format(result.stderr.decode("utf-8"))) 209 | sys.exit(1) 210 | 211 | os.rename('libmicroros.a', self.library) 212 | 213 | # Copy includes 214 | shutil.copytree(self.build_folder + "/mcu/install/include", self.includes) 215 | 216 | # Fix include paths 217 | include_folders = os.listdir(self.includes) 218 | 219 | for folder in include_folders: 220 | folder_path = self.includes + "/{}".format(folder) 221 | repeated_path = folder_path + "/{}".format(folder) 222 | 223 | if os.path.exists(repeated_path): 224 | shutil.copytree(repeated_path, folder_path, copy_function=shutil.move, dirs_exist_ok=True) 225 | shutil.rmtree(repeated_path) 226 | 227 | def resolve_binutils_path(self): 228 | if sys.platform == "darwin": 229 | homebrew_binutils_path = "/opt/homebrew/opt/binutils/bin/" 230 | if os.path.exists(homebrew_binutils_path): 231 | return homebrew_binutils_path 232 | 233 | print("ERROR: GNU binutils not found. ({}) Please install binutils with homebrew: brew install binutils" 234 | .format(homebrew_binutils_path)) 235 | sys.exit(1) 236 | 237 | return "" 238 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![banner](.images/banner-dark-theme.png#gh-dark-mode-only) 2 | ![banner](.images/banner-light-theme.png#gh-light-mode-only) 3 | 4 | # micro-ROS for PlatformIO 5 | This is a micro-ROS library for bare metal projects based on platformIO. 6 | 7 | The build process for ROS 2 and micro-ROS is based on custom meta-build system tools and [CMake](https://cmake.org/). 8 | PlatformIO will handle the full build process, including dependencies, compilation and linkage. 9 | 10 | - [micro-ROS for PlatformIO](#micro-ros-for-platformio) 11 | - [Supported boards](#supported-boards) 12 | - [Requirements](#requirements) 13 | - [How to add to your project](#how-to-add-to-your-project) 14 | - [Library configuration](#library-configuration) 15 | - [ROS 2 distribution](#ros-2-distribution) 16 | - [Transport configuration](#transport-configuration) 17 | - [Extra packages](#extra-packages) 18 | - [Other configuration](#other-configuration) 19 | - [Extend library targets](#extend-library-targets) 20 | - [Transport implementation](#transport-implementation) 21 | - [Time source](#time-source) 22 | - [Using the micro-ROS Agent](#using-the-micro-ros-agent) 23 | - [Examples](#examples) 24 | - [Purpose of the Project](#purpose-of-the-project) 25 | - [License](#license) 26 | - [Known Issues/Limitations](#known-issueslimitations) 27 | 28 | ## Supported boards 29 | Supported boards are: 30 | 31 | | Board | Platform | Framework | Transports | Default meta file | 32 | | -------------------------------------------- | ------------- | ----------- | ---------------------------------------- | ------------------------ | 33 | | `portenta_h7_m7` | `ststm32` | `arduino` | `serial`
`wifi` | `colcon.meta` | 34 | | `teensy41` | `teensy` | `arduino` | `serial`
`native_ethernet` | `colcon.meta` | 35 | | `teensy40` | `teensy` | `arduino` | `serial` | `colcon.meta` | 36 | | `teensy36`
`teensy35`
`teensy31` | `teensy` | `arduino` | `serial` | `colcon_lowmem.meta` | 37 | | `due` | `atmelsam` | `arduino` | `serial` | `colcon_verylowmem.meta` | 38 | | `zero` | `atmelsam` | `arduino` | `serial` | `colcon_verylowmem.meta` | 39 | | `olimex_e407` | `ststm32` | `arduino` | `serial` | `colcon.meta` | 40 | | `esp32dev` | `espressif32` | `arduino` | `serial`
`wifi`
`ethernet`* | `colcon.meta` | 41 | | `nanorp2040connect` | `raspberrypi` | `arduino` | `serial`
`wifi_nina` | `colcon_verylowmem.meta` | 42 | | `pico`
`pico2` | `raspberrypi` | `arduino` | `serial` | `colcon.meta` | 43 | 44 | \* Community contributed 45 | 46 | The community is encouraged to open pull request with custom use cases. 47 | 48 | ## Requirements 49 | 50 | - PlatformIO [local installation](https://docs.platformio.org/en/stable/core/installation.html) or [PlatformIO IDE for VSCode](https://platformio.org/install/ide?install=vscode) 51 | - PlatformIO Core version 6.1.0 or greater 52 | - PlatformIO needs `git`, `cmake` and `pip3` to handle micro-ROS internal dependencies: 53 | 54 | ```bash 55 | apt install -y git cmake python3-pip 56 | ``` 57 | 58 | ### Platform specific requirements 59 | 60 | #### MacOS 61 | 62 | XCode command line tools are distributed with toolchain that is not fully compatible with micro-ROS build process. 63 | To fix this, install GNU [binutils](https://www.gnu.org/software/binutils/) using [Homebrew](https://brew.sh/): 64 | 65 | ```bash 66 | brew install binutils 67 | ``` 68 | 69 | ## How to add to your project 70 | 71 | The library can be included as a regular git library dependence on your `platform.ini` file: 72 | 73 | You may find a sample ini file at `ci/platformio.ini`. 74 | 75 | ```ini 76 | ... 77 | lib_deps = 78 | https://github.com/micro-ROS/micro_ros_platformio 79 | ``` 80 | 81 | Now to proceed with the PlatformIO workflow: 82 | 83 | ```bash 84 | pio lib install # Install dependencies 85 | pio run # Build the firmware 86 | pio run --target upload # Flash the firmware 87 | ``` 88 | 89 | After the library is compiled for first time the build process will be skipped, to trigger a library build and apply [library modifications](#library-configuration) on your next platformIO build: 90 | 91 | ```bash 92 | pio run --target clean_microros # Clean library 93 | ``` 94 | 95 | ## Library configuration 96 | This section details the different configuration parameters available on the project `platform.ini` file. 97 | A explanation for adding custom targets is also present 98 | 99 | 100 | ### ROS 2 distribution 101 | The target ROS 2 distribution can be configured with the `board_microros_distro = `, supported values are: 102 | - `humble` 103 | - `jazzy` 104 | - `kilted` *(default value)* 105 | - `rolling` 106 | 107 | ### Transport configuration 108 | The transport can be configured with the `board_microros_transport = `, supported values and configurations are: 109 | - `serial` *(default value)* 110 | 111 | ```c 112 | Serial.begin(115200); 113 | set_microros_serial_transports(Serial); 114 | ``` 115 | 116 | - `wifi` 117 | - `wifi_nina` 118 | 119 | ```c 120 | IPAddress agent_ip(192, 168, 1, 113); 121 | size_t agent_port = 8888; 122 | 123 | char ssid[] = "WIFI_SSID"; 124 | char psk[]= "WIFI_PSK"; 125 | 126 | set_microros_wifi_transports(ssid, psk, agent_ip, agent_port); 127 | ``` 128 | 129 | - `native_ethernet` 130 | 131 | ```c 132 | byte local_mac[] = { 0xAA, 0xBB, 0xCC, 0xEE, 0xDD, 0xFF }; 133 | IPAddress local_ip(192, 168, 1, 177); 134 | IPAddress agent_ip(192, 168, 1, 113); 135 | size_t agent_port = 8888; 136 | 137 | set_microros_native_ethernet_transports(local_mac, local_ip, agent_ip, agent_port); 138 | ``` 139 | 140 | - `ethernet` 141 | 142 | ```c 143 | IPAddress client_ip(192, 168, 1, 177); 144 | IPAddress gateway(192, 168, 1, 1); 145 | IPAddress netmask(255, 255, 255, 0); 146 | IPAddress agent_ip(192, 168, 1, 113); 147 | size_t agent_port = 8888; 148 | 149 | // Optional hostname, defaults to nullptr (no hostname set) 150 | set_microros_ethernet_transports(client_ip, gateway, netmask, agent_ip, agent_port, "my-microros-device"); 151 | ``` 152 | 153 | - `custom` 154 | 155 | The user will need to write transport functions in app code and provide it to the micro-ROS library using [`rmw_uros_set_custom_transport()` API](https://micro.ros.org/docs/tutorials/advanced/create_custom_transports/) 156 | 157 | ```c 158 | bool platformio_transport_open(struct uxrCustomTransport * transport) {...}; 159 | bool platformio_transport_close(struct uxrCustomTransport * transport) {...}; 160 | size_t platformio_transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * err) {...}; 161 | size_t platformio_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err) {...}; 162 | 163 | rmw_uros_set_custom_transport( 164 | MICROROS_TRANSPORTS_FRAMING_MODE, // Set the MICROROS_TRANSPORTS_FRAMING_MODE or MICROROS_TRANSPORTS_PACKET_MODE mode accordingly 165 | NULL, 166 | platformio_transport_open, 167 | platformio_transport_close, 168 | platformio_transport_write, 169 | platformio_transport_read 170 | ); 171 | ``` 172 | 173 | ### Extra packages 174 | Colcon packages can be added to the build process using this two methods: 175 | - Package directories copied on the `/extra_packages` folder. 176 | - Git repositories included on the `/extra_packages/extra_packages.repos` yaml file. 177 | 178 | This should be used for example when adding custom messages types or custom micro-ROS packages. 179 | 180 | ### Other configuration 181 | Library packages can be configured with a customized meta file on the project main folder: `board_microros_user_meta = `. 182 | 183 | This allows the user to customize the library memory resources or activate optional functionality such as multithreading, including configuration of user [Extra packages](#extra-packages). 184 | 185 | - Documentation on available parameters can be found [here](https://micro.ros.org/docs/tutorials/advanced/microxrcedds_rmw_configuration) and [here]([microxrcedds_rmw_configuration](https://micro-xrce-dds.docs.eprosima.com/en/latest/client.html)). 186 | - Default configurations can be found on the [metas](./metas) folder. 187 | 188 | *Note: the [common.meta](./metas/common.meta) file makes general adjustments to the library and shall not be modified by the user.* 189 | 190 | ## Extend library targets 191 | This library can be easily adapted to different boards, transports or RTOS, to achieve this the user shall provide: 192 | 193 | ### Transport implementation 194 | 195 | New transport implementations shall follow the signatures shown on [micro_ros_platformio.h](./platform_code/arduino/micro_ros_platformio.h), the [provided sources](./platform_code) can be used as reference along [this documentation](https://micro-xrce-dds.docs.eprosima.com/en/latest/transport.html#custom-transport). Contributed transport source code shall be added on the `./platform_code//` path. Example: 196 | 197 | - `platform.ini`: 198 | ```ini 199 | framework = arduino 200 | board_microros_transport = wifi 201 | ``` 202 | - Transport source files: [platform_code/arduino/wifi](https://github.com/micro-ROS/micro_ros_platformio/tree/main/platform_code/arduino/wifi) 203 | - Also, a `MICRO_ROS_TRANSPORT__` definition will be available: 204 | https://github.com/micro-ROS/micro_ros_platformio/blob/de7a61c7e86fdd0186ed8b7d8ec320994e8ebcbf/ci/src/main.cpp#L3 205 | 206 | *Note: `board_microros_transport = custom` should not be used, as it is used to add custom transports on user app code* 207 | 208 | ### Time source 209 | micro-ROS needs a time source to handle executor spins and synchronize reliable communication. To achieve this, a `clock_gettime` [POSIX compliant](https://linux.die.net/man/3/clock_gettime) implementation is required, with a minimum resolution of 1 millisecond. 210 | 211 | This method shall be included on a `clock_gettime.cpp` source file under the `./platform_code//` path, an example implementation can be found on [clock_gettime.cpp](./platform_code/arduino/clock_gettime.cpp) 212 | 213 | ## Using the micro-ROS Agent 214 | It is possible to use a **micro-ROS Agent** just by using this docker command: 215 | 216 | ```bash 217 | # UDPv4 micro-ROS Agent 218 | docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:$ROS_DISTRO udp4 --port 8888 -v6 219 | 220 | # Serial micro-ROS Agent 221 | docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:$ROS_DISTRO serial --dev [YOUR BOARD PORT] -v6 222 | 223 | # TCPv4 micro-ROS Agent 224 | docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:$ROS_DISTRO tcp4 --port 8888 -v6 225 | 226 | # CAN-FD micro-ROS Agent 227 | docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:$ROS_DISTRO canfd --dev [YOUR CAN INTERFACE] -v6 228 | ``` 229 | 230 | For the supported transports, only the `serial` and `udp4` versions shall be used, although users can develop 231 | and use the agent to test their own `tcp4` and `canfd` custom transports. 232 | 233 | It is also possible to use custom transports on a `micro-XRCE Agent` instance. More info available [here](https://micro-xrce-dds.docs.eprosima.com/en/latest/agent.html#custom-transport-agent). 234 | 235 | ## Examples 236 | A simple publisher project using serial transport is available on the [examples](./examples) directory, this examples is meant to be modified with the user board. 237 | 238 | - More micro-ROS usage examples are available on [micro-ROS-demos/rclc](https://github.com/micro-ROS/micro-ROS-demos/tree/jazzy/rclc). 239 | - For a complete micro-ROS tutorial, check [Programming with rcl and rclc](https://micro.ros.org/docs/tutorials/programming_rcl_rclc/overview/) documentation. 240 | - Community contributed tutorials for beginners with [examples ported from micro_ros_arduino](https://github.com/hippo5329/micro_ros_arduino_examples_platformio/wiki) and [examples ported from micro-ROS-demos](https://github.com/hippo5329/micro-ROS-demos-platformio/wiki). 241 | 242 | ## Purpose of the Project 243 | 244 | This software is not ready for production use. It has neither been developed nor 245 | tested for a specific use case. However, the license conditions of the 246 | applicable Open Source licenses allow you to adapt the software to your needs. 247 | Before using it in a safety relevant setting, make sure that the software 248 | fulfills your requirements and adjust it according to any applicable safety 249 | standards, e.g., ISO 26262. 250 | 251 | ## License 252 | 253 | This repository is open-sourced under the Apache-2.0 license. See the [LICENSE](LICENSE) file for details. 254 | 255 | For a list of other open-source components included in this repository, 256 | see the file [3rd-party-licenses.txt](3rd-party-licenses.txt). 257 | -------------------------------------------------------------------------------- /microros_utils/repositories.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import json 3 | import xml.etree.ElementTree as xml_parser 4 | 5 | from .utils import run_cmd 6 | 7 | class Package: 8 | def __init__(self, name, path): 9 | self.name = name 10 | self.path = path 11 | self.ignored = False 12 | 13 | def ignore(self): 14 | self.ignored = True 15 | ignore_path = self.path + '/COLCON_IGNORE' 16 | with open(ignore_path, 'a'): 17 | os.utime(ignore_path, None) 18 | 19 | class Repository: 20 | def __init__(self, name, url, distribution, branch=None): 21 | self.name = name 22 | self.url = url 23 | self.distribution = distribution 24 | self.branch = distribution if branch is None else branch 25 | self.path = None 26 | 27 | def clone(self, folder): 28 | self.path = folder + "/" + self.name 29 | # TODO(pablogs) ensure that git is installed 30 | if os.path.exists(self.path): 31 | command = f"cd {self.path} && git pull {self.url} {self.branch}" 32 | result = run_cmd(command) 33 | if 0 != result.returncode: 34 | print(f"{self.name} pull failed: \n{result.stderr.decode('utf-8')}") 35 | sys.exit(1) 36 | return 37 | 38 | command = "git clone -b {} {} {}".format(self.branch, self.url, self.path) 39 | result = run_cmd(command) 40 | 41 | if 0 != result.returncode: 42 | print("{} clone failed: \n{}".format(self.name, result.stderr.decode("utf-8"))) 43 | sys.exit(1) 44 | 45 | def get_packages(self): 46 | packages = [] 47 | if os.path.exists(self.path + '/package.xml'): 48 | packages.append(Package(self.name, self.path)) 49 | else: 50 | for root, dirs, files in os.walk(self.path): 51 | path = root.split(os.sep) 52 | if 'package.xml' in files: 53 | package_name = Repository.get_package_name_from_package_xml(os.path.join(root, 'package.xml')) 54 | package_path = os.path.join(os.getcwd(), root) 55 | packages.append(Package(package_name, package_path)) 56 | elif 'colcon.pkg' in files: 57 | package_name = Repository.get_package_name_from_colcon_pkg(os.path.join(root, 'colcon.pkg')) 58 | package_path = os.path.join(os.getcwd(), root) 59 | packages.append(Package(package_name, package_path)) 60 | return packages 61 | 62 | def get_package_name_from_package_xml(xml_file): 63 | root_node = xml_parser.parse(xml_file).getroot() 64 | name_node = root_node.find('name') 65 | if name_node is not None: 66 | return name_node.text 67 | return None 68 | 69 | def get_package_name_from_colcon_pkg(colcon_pkg): 70 | with open(colcon_pkg, 'r') as f: 71 | content = json.load(f) 72 | if content['name']: 73 | return content['name'] 74 | return None 75 | 76 | class Sources: 77 | dev_environments = { 78 | 'humble': [ 79 | Repository("ament_cmake", "https://github.com/ament/ament_cmake", "humble"), 80 | Repository("ament_lint", "https://github.com/ament/ament_lint", "humble"), 81 | Repository("ament_package", "https://github.com/ament/ament_package", "humble"), 82 | Repository("googletest", "https://github.com/ament/googletest", "humble"), 83 | Repository("ament_cmake_ros", "https://github.com/ros2/ament_cmake_ros", "humble"), 84 | Repository("ament_index", "https://github.com/ament/ament_index", "humble") 85 | ], 86 | 'iron': [ 87 | Repository("ament_cmake", "https://github.com/ament/ament_cmake", "iron"), 88 | Repository("ament_lint", "https://github.com/ament/ament_lint", "iron"), 89 | Repository("ament_package", "https://github.com/ament/ament_package", "iron"), 90 | Repository("googletest", "https://github.com/ament/googletest", "iron"), 91 | Repository("ament_cmake_ros", "https://github.com/ros2/ament_cmake_ros", "iron"), 92 | Repository("ament_index", "https://github.com/ament/ament_index", "iron") 93 | ], 94 | 'jazzy': [ 95 | Repository("ament_cmake", "https://github.com/ament/ament_cmake", "jazzy"), 96 | Repository("ament_lint", "https://github.com/ament/ament_lint", "jazzy"), 97 | Repository("ament_package", "https://github.com/ament/ament_package", "jazzy"), 98 | Repository("googletest", "https://github.com/ament/googletest", "jazzy"), 99 | Repository("ament_cmake_ros", "https://github.com/ros2/ament_cmake_ros", "jazzy"), 100 | Repository("ament_index", "https://github.com/ament/ament_index", "jazzy") 101 | ], 102 | 'kilted': [ 103 | Repository("ament_cmake", "https://github.com/ament/ament_cmake", "kilted"), 104 | Repository("ament_lint", "https://github.com/ament/ament_lint", "kilted"), 105 | Repository("ament_package", "https://github.com/ament/ament_package", "kilted"), 106 | Repository("googletest", "https://github.com/ament/googletest", "kilted"), 107 | Repository("ament_cmake_ros", "https://github.com/ros2/ament_cmake_ros", "kilted"), 108 | Repository("ament_index", "https://github.com/ament/ament_index", "kilted") 109 | ], 110 | 'rolling': [ 111 | Repository("ament_cmake", "https://github.com/ament/ament_cmake", "rolling"), 112 | Repository("ament_lint", "https://github.com/ament/ament_lint", "rolling"), 113 | Repository("ament_package", "https://github.com/ament/ament_package", "rolling"), 114 | Repository("googletest", "https://github.com/ament/googletest", "rolling"), 115 | Repository("ament_cmake_ros", "https://github.com/ros2/ament_cmake_ros", "rolling"), 116 | Repository("ament_index", "https://github.com/ament/ament_index", "rolling") 117 | ] 118 | } 119 | 120 | mcu_environments = { 121 | 'humble': [ 122 | Repository("micro-CDR", "https://github.com/eProsima/micro-CDR", "humble", "ros2"), 123 | Repository("Micro-XRCE-DDS-Client", "https://github.com/eProsima/Micro-XRCE-DDS-Client", "humble", "ros2"), 124 | Repository("rcl", "https://github.com/micro-ROS/rcl", "humble"), 125 | Repository("rclc", "https://github.com/ros2/rclc", "humble"), 126 | Repository("micro_ros_utilities", "https://github.com/micro-ROS/micro_ros_utilities", "humble"), 127 | Repository("rcutils", "https://github.com/micro-ROS/rcutils", "humble"), 128 | Repository("micro_ros_msgs", "https://github.com/micro-ROS/micro_ros_msgs", "humble"), 129 | Repository("rmw-microxrcedds", "https://github.com/micro-ROS/rmw-microxrcedds", "humble"), 130 | Repository("rosidl_typesupport", "https://github.com/micro-ROS/rosidl_typesupport", "humble"), 131 | Repository("rosidl_typesupport_microxrcedds", "https://github.com/micro-ROS/rosidl_typesupport_microxrcedds", "humble"), 132 | Repository("rosidl", "https://github.com/ros2/rosidl", "humble"), 133 | Repository("rmw", "https://github.com/ros2/rmw", "humble"), 134 | Repository("rcl_interfaces", "https://github.com/ros2/rcl_interfaces", "humble"), 135 | Repository("rosidl_defaults", "https://github.com/ros2/rosidl_defaults", "humble"), 136 | Repository("unique_identifier_msgs", "https://github.com/ros2/unique_identifier_msgs", "humble"), 137 | Repository("common_interfaces", "https://github.com/ros2/common_interfaces", "humble"), 138 | Repository("test_interface_files", "https://github.com/ros2/test_interface_files", "humble"), 139 | Repository("rmw_implementation", "https://github.com/ros2/rmw_implementation", "humble"), 140 | Repository("rcl_logging", "https://github.com/ros2/rcl_logging", "humble"), 141 | Repository("ros2_tracing", "https://github.com/ros2/ros2_tracing", "humble"), 142 | ], 143 | 'iron': [ 144 | Repository("micro-CDR", "https://github.com/eProsima/micro-CDR", "iron", "ros2"), 145 | Repository("Micro-XRCE-DDS-Client", "https://github.com/eProsima/Micro-XRCE-DDS-Client", "iron", "ros2"), 146 | Repository("rcl", "https://github.com/micro-ROS/rcl", "iron"), 147 | Repository("rclc", "https://github.com/ros2/rclc", "iron"), 148 | Repository("micro_ros_utilities", "https://github.com/micro-ROS/micro_ros_utilities", "iron"), 149 | Repository("rcutils", "https://github.com/micro-ROS/rcutils", "iron"), 150 | Repository("micro_ros_msgs", "https://github.com/micro-ROS/micro_ros_msgs", "iron"), 151 | Repository("rmw-microxrcedds", "https://github.com/micro-ROS/rmw-microxrcedds", "iron"), 152 | Repository("rosidl_typesupport", "https://github.com/micro-ROS/rosidl_typesupport", "iron"), 153 | Repository("rosidl_typesupport_microxrcedds", "https://github.com/micro-ROS/rosidl_typesupport_microxrcedds", "iron"), 154 | Repository("rosidl", "https://github.com/ros2/rosidl", "iron"), 155 | Repository("rosidl_dynamic_typesupport", "https://github.com/ros2/rosidl_dynamic_typesupport", "iron"), 156 | Repository("rosidl_core", "https://github.com/ros2/rosidl_core", "iron"), 157 | Repository("rmw", "https://github.com/ros2/rmw", "iron"), 158 | Repository("rcl_interfaces", "https://github.com/ros2/rcl_interfaces", "iron"), 159 | Repository("rosidl_defaults", "https://github.com/ros2/rosidl_defaults", "iron"), 160 | Repository("unique_identifier_msgs", "https://github.com/ros2/unique_identifier_msgs", "iron"), 161 | Repository("common_interfaces", "https://github.com/ros2/common_interfaces", "iron"), 162 | Repository("test_interface_files", "https://github.com/ros2/test_interface_files", "iron"), 163 | Repository("rmw_implementation", "https://github.com/ros2/rmw_implementation", "iron"), 164 | Repository("rcl_logging", "https://github.com/ros2/rcl_logging", "iron"), 165 | Repository("ros2_tracing", "https://github.com/ros2/ros2_tracing", "iron"), 166 | ], 167 | 'jazzy': [ 168 | Repository("micro-CDR", "https://github.com/eProsima/micro-CDR", "jazzy", "ros2"), 169 | Repository("Micro-XRCE-DDS-Client", "https://github.com/eProsima/Micro-XRCE-DDS-Client", "jazzy", "ros2"), 170 | Repository("rcl", "https://github.com/micro-ROS/rcl", "jazzy"), 171 | Repository("rclc", "https://github.com/ros2/rclc", "jazzy"), 172 | Repository("micro_ros_utilities", "https://github.com/micro-ROS/micro_ros_utilities", "jazzy"), 173 | Repository("rcutils", "https://github.com/micro-ROS/rcutils", "jazzy"), 174 | Repository("micro_ros_msgs", "https://github.com/micro-ROS/micro_ros_msgs", "jazzy"), 175 | Repository("rmw-microxrcedds", "https://github.com/micro-ROS/rmw-microxrcedds", "jazzy"), 176 | Repository("rosidl_typesupport", "https://github.com/micro-ROS/rosidl_typesupport", "jazzy"), 177 | Repository("rosidl_typesupport_microxrcedds", "https://github.com/micro-ROS/rosidl_typesupport_microxrcedds", "jazzy"), 178 | Repository("rosidl", "https://github.com/ros2/rosidl", "jazzy"), 179 | Repository("rosidl_dynamic_typesupport", "https://github.com/ros2/rosidl_dynamic_typesupport", "jazzy"), 180 | Repository("rosidl_core", "https://github.com/ros2/rosidl_core", "jazzy"), 181 | Repository("rmw", "https://github.com/ros2/rmw", "jazzy"), 182 | Repository("rcl_interfaces", "https://github.com/ros2/rcl_interfaces", "jazzy"), 183 | Repository("rosidl_defaults", "https://github.com/ros2/rosidl_defaults", "jazzy"), 184 | Repository("unique_identifier_msgs", "https://github.com/ros2/unique_identifier_msgs", "jazzy"), 185 | Repository("common_interfaces", "https://github.com/ros2/common_interfaces", "jazzy"), 186 | Repository("test_interface_files", "https://github.com/ros2/test_interface_files", "jazzy"), 187 | Repository("rmw_implementation", "https://github.com/ros2/rmw_implementation", "jazzy"), 188 | Repository("rcl_logging", "https://github.com/ros2/rcl_logging", "jazzy"), 189 | Repository("ros2_tracing", "https://github.com/ros2/ros2_tracing", "jazzy"), 190 | ], 191 | 'kilted': [ 192 | Repository("micro-CDR", "https://github.com/eProsima/micro-CDR", "kilted", "ros2"), 193 | Repository("Micro-XRCE-DDS-Client", "https://github.com/eProsima/Micro-XRCE-DDS-Client", "kilted", "ros2"), 194 | Repository("rcl", "https://github.com/micro-ROS/rcl", "kilted"), 195 | Repository("rclc", "https://github.com/ros2/rclc", "kilted"), 196 | Repository("micro_ros_utilities", "https://github.com/micro-ROS/micro_ros_utilities", "kilted"), 197 | Repository("rcutils", "https://github.com/micro-ROS/rcutils", "kilted"), 198 | Repository("micro_ros_msgs", "https://github.com/micro-ROS/micro_ros_msgs", "kilted"), 199 | Repository("rmw-microxrcedds", "https://github.com/micro-ROS/rmw-microxrcedds", "kilted"), 200 | Repository("rosidl_typesupport", "https://github.com/micro-ROS/rosidl_typesupport", "kilted"), 201 | Repository("rosidl_typesupport_microxrcedds", "https://github.com/micro-ROS/rosidl_typesupport_microxrcedds", "kilted"), 202 | Repository("rosidl", "https://github.com/ros2/rosidl", "kilted"), 203 | Repository("rosidl_dynamic_typesupport", "https://github.com/ros2/rosidl_dynamic_typesupport", "kilted"), 204 | Repository("rosidl_core", "https://github.com/ros2/rosidl_core", "kilted"), 205 | Repository("rmw", "https://github.com/ros2/rmw", "kilted"), 206 | Repository("rcl_interfaces", "https://github.com/ros2/rcl_interfaces", "kilted"), 207 | Repository("rosidl_defaults", "https://github.com/ros2/rosidl_defaults", "kilted"), 208 | Repository("unique_identifier_msgs", "https://github.com/ros2/unique_identifier_msgs", "kilted"), 209 | Repository("common_interfaces", "https://github.com/ros2/common_interfaces", "kilted"), 210 | Repository("test_interface_files", "https://github.com/ros2/test_interface_files", "kilted"), 211 | Repository("rmw_implementation", "https://github.com/ros2/rmw_implementation", "kilted"), 212 | Repository("rcl_logging", "https://github.com/ros2/rcl_logging", "kilted"), 213 | Repository("ros2_tracing", "https://github.com/ros2/ros2_tracing", "kilted"), 214 | ], 215 | 'rolling': [ 216 | Repository("micro-CDR", "https://github.com/eProsima/micro-CDR", "rolling", "ros2"), 217 | Repository("Micro-XRCE-DDS-Client", "https://github.com/eProsima/Micro-XRCE-DDS-Client", "rolling", "ros2"), 218 | Repository("rcl", "https://github.com/micro-ROS/rcl", "rolling"), 219 | Repository("rclc", "https://github.com/ros2/rclc", "rolling"), 220 | Repository("micro_ros_utilities", "https://github.com/micro-ROS/micro_ros_utilities", "rolling"), 221 | Repository("rcutils", "https://github.com/micro-ROS/rcutils", "rolling"), 222 | Repository("micro_ros_msgs", "https://github.com/micro-ROS/micro_ros_msgs", "rolling"), 223 | Repository("rmw-microxrcedds", "https://github.com/micro-ROS/rmw-microxrcedds", "rolling"), 224 | Repository("rosidl_typesupport", "https://github.com/micro-ROS/rosidl_typesupport", "rolling"), 225 | Repository("rosidl_typesupport_microxrcedds", "https://github.com/micro-ROS/rosidl_typesupport_microxrcedds", "rolling"), 226 | Repository("rosidl", "https://github.com/ros2/rosidl", "rolling"), 227 | Repository("rosidl_dynamic_typesupport", "https://github.com/ros2/rosidl_dynamic_typesupport", "rolling"), 228 | Repository("rosidl_core", "https://github.com/ros2/rosidl_core", "rolling"), 229 | Repository("rmw", "https://github.com/ros2/rmw", "rolling"), 230 | Repository("rcl_interfaces", "https://github.com/ros2/rcl_interfaces", "rolling"), 231 | Repository("rosidl_defaults", "https://github.com/ros2/rosidl_defaults", "rolling"), 232 | Repository("unique_identifier_msgs", "https://github.com/ros2/unique_identifier_msgs", "rolling"), 233 | Repository("common_interfaces", "https://github.com/ros2/common_interfaces", "rolling"), 234 | Repository("test_interface_files", "https://github.com/ros2/test_interface_files", "rolling"), 235 | Repository("rmw_implementation", "https://github.com/ros2/rmw_implementation", "rolling"), 236 | Repository("rcl_logging", "https://github.com/ros2/rcl_logging", "rolling"), 237 | Repository("ros2_tracing", "https://github.com/ros2/ros2_tracing", "rolling"), 238 | ] 239 | } 240 | 241 | ignore_packages = { 242 | 'humble': ['rcl_logging_log4cxx', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples'], 243 | 'iron': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples'], 244 | 'jazzy': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples', 'lttngpy'], 245 | 'kilted': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples', 'lttngpy', 'rmw_security_common'], 246 | 'rolling': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples', 'lttngpy', 'rmw_security_common'] 247 | } 248 | --------------------------------------------------------------------------------