diff --git a/.github/actions/platformio-env/action.yml b/.github/actions/platformio-env/action.yml index f273d7e9..9e42843d 100644 --- a/.github/actions/platformio-env/action.yml +++ b/.github/actions/platformio-env/action.yml @@ -9,6 +9,7 @@ runs: apt update export DEBIAN_FRONTEND=noninteractive apt install -y git curl python3 python3-pip python3-venv git cmake - python3 -c "$(curl -fsSL https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)" + curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py + python3 get-platformio.py echo 'export PATH=$PATH:~/.platformio/penv/bin' >> ~/.bashrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f85da831..27750a46 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,43 +11,14 @@ jobs: runs-on: ubuntu-20.04 container: ubuntu:20.04 - strategy: - fail-fast: false - matrix: - pio-environment: - - teensy41 - - teensy40 - - teensy36 - - teensy35 - - teensy31 - - due - - zero - - olimex_e407 - - esp32dev - - nanorp2040connect - - portenta_h7_m7 - - teensy41_eth - - nanorp2040connect_wifi - - portenta_h7_m7_wifi - - esp32dev_wifi - - portenta_h7_m7_galactic - - portenta_h7_m7_foxy - - portenta_h7_m7_rolling - - teensy41_custom - - pico + micro_ros_platformio: + runs-on: ubuntu-22.04 + container: ubuntu:22.04 - steps: - - uses: actions/checkout@v3 - with: - path: repo - - name: Install environment - uses: ./repo/.github/actions/platformio-env - - name: Build - shell: bash - run: | - export PATH=$PATH:~/.platformio/penv/bin - cd repo/ci/arduino - pio run -e ${{ matrix.pio-environment }} + strategy: + fail-fast: false + matrix: + 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, portenta_h7_m7_humble, portenta_h7_m7_jazzy, portenta_h7_m7_rolling, teensy41_custom, pico] micro_ros_platformio_stm32cube: runs-on: ubuntu-20.04 diff --git a/README.md b/README.md index 3bfd4d25..f77c0919 100755 --- a/README.md +++ b/README.md @@ -54,6 +54,17 @@ The community is encouraged to open pull request with custom use cases. ```bash apt install -y git cmake python3-pip ``` + +### Platform specific requirements + +#### MacOS + +XCode command line tools are distributed with toolchain that is not fully compatible with micro-ROS build process. +To fix this, install GNU [binutils](https://www.gnu.org/software/binutils/) using [Homebrew](https://brew.sh/): + +```bash +brew install binutils +``` ## How to add to your project @@ -87,7 +98,8 @@ A explanation for adding custom targets is also present ### ROS 2 distribution The target ROS 2 distribution can be configured with the `board_microros_distro = `, supported values are: - `humble` - - `iron` *(default value)* + - `iron` + - `jazzy` *(default value)* - `rolling` ### Transport configuration @@ -208,7 +220,7 @@ It is also possible to use custom transports on a `micro-XRCE Agent` instance. M ## Examples 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. -- More micro-ROS usage examples are available on [micro-ROS-demos/rclc](https://github.com/micro-ROS/micro-ROS-demos/tree/iron/rclc). +- More micro-ROS usage examples are available on [micro-ROS-demos/rclc](https://github.com/micro-ROS/micro-ROS-demos/tree/jazzy/rclc). - For a complete micro-ROS tutorial, check [Programming with rcl and rclc](https://micro.ros.org/docs/tutorials/programming_rcl_rclc/overview/) documentation. ## Purpose of the Project diff --git a/ci/arduino/platformio.ini b/ci/arduino/platformio.ini index f2c4ac78..99f19a0e 100644 --- a/ci/arduino/platformio.ini +++ b/ci/arduino/platformio.ini @@ -8,6 +8,16 @@ board_microros_distro = humble lib_deps = ../../ +; Jazzy test +[env:portenta_h7_m7_jazzy] +platform = ststm32 +board = portenta_h7_m7 +framework = arduino +board_microros_transport = serial +board_microros_distro = jazzy +lib_deps = + ../ + ; Rolling test [env:portenta_h7_m7_rolling] platform = ststm32 diff --git a/extra_script.py b/extra_script.py index 27a21574..47c49213 100644 --- a/extra_script.py +++ b/extra_script.py @@ -62,7 +62,21 @@ def clean_microros_callback(*args, **kwargs): print("micro-ROS library cleaned!") os._exit(0) -global_env.AddCustomTarget("clean_microros", None, clean_microros_callback, title="Clean Micro-ROS", description="Clean Micro-ROS build environment") +if "clean_microros" not in global_env.get("__PIO_TARGETS", {}): + global_env.AddCustomTarget("clean_microros", None, clean_microros_callback, title="Clean Micro-ROS", description="Clean Micro-ROS build environment") + +def clean_libmicroros_callback(*args, **kwargs): + library_path = main_path + '/libmicroros' + + # Delete libmicroros folder + shutil.rmtree(library_path, ignore_errors=True) + + print("libmicroros cleaned") + os._exit(0) + +if "clean_libmicroros" not in global_env.get("__PIO_TARGETS", {}): + global_env.AddCustomTarget("clean_libmicroros", None, clean_libmicroros_callback, title="Clean libmicroros", description="Clean libmicroros") + def build_microros(*args, **kwargs): ############################## @@ -70,7 +84,7 @@ def build_microros(*args, **kwargs): ############################## pip_packages = [x.split("==")[0] for x in os.popen('{} -m pip freeze'.format(env['PYTHONEXE'])).read().split('\n')] - required_packages = ["catkin-pkg", "lark-parser", "empy", "colcon-common-extensions", "importlib-resources", "pyyaml", "pytz", "markupsafe==2.0.1"] + required_packages = ["catkin-pkg", "lark-parser", "colcon-common-extensions", "importlib-resources", "pyyaml", "pytz", "markupsafe==2.0.1", "empy==3.3.4"] if all([x in pip_packages for x in required_packages]): print("All required Python pip packages are installed") @@ -157,7 +171,7 @@ def update_env(): from SCons.Script import COMMAND_LINE_TARGETS # Do not build library on clean_microros target or when IDE fetches C/C++ project metadata -if set(["clean_microros", "__idedata", "_idedata", "idedata"]).isdisjoint(set(COMMAND_LINE_TARGETS)): +if set(["clean_microros", "clean_libmicroros", "_idedata", "idedata"]).isdisjoint(set(COMMAND_LINE_TARGETS)): build_microros() update_env() diff --git a/microros_utils/library_builder.py b/microros_utils/library_builder.py index 44a9efc2..49248991 100644 --- a/microros_utils/library_builder.py +++ b/microros_utils/library_builder.py @@ -55,7 +55,7 @@ def __init__(self, library_folder, packages_folder, distro, python_env): self.env = {} def run(self, meta, toolchain, user_meta = ""): - if os.path.exists(self.library_path): + if os.path.exists(self.library): print("micro-ROS already built") return @@ -66,9 +66,6 @@ def run(self, meta, toolchain, user_meta = ""): self.build_mcu_environment(meta, toolchain, user_meta) self.package_mcu_library() - # Delete build folders - shutil.rmtree(self.build_folder, ignore_errors=True) - def ignore_package(self, name): for p in self.mcu_packages: if p.name == name: @@ -90,8 +87,7 @@ def check_env(self): self.env = os.environ.copy() def download_dev_environment(self): - shutil.rmtree(self.dev_src_folder, ignore_errors=True) - os.makedirs(self.dev_src_folder) + os.makedirs(self.dev_src_folder, exist_ok=True) print("Downloading micro-ROS dev dependencies") for repo in Sources.dev_environments[self.distro]: repo.clone(self.dev_src_folder) @@ -108,8 +104,7 @@ def build_dev_environment(self): sys.exit(1) def download_mcu_environment(self): - shutil.rmtree(self.mcu_src_folder, ignore_errors=True) - os.makedirs(self.mcu_src_folder) + os.makedirs(self.mcu_src_folder, exist_ok=True) print("Downloading micro-ROS library") for repo in Sources.mcu_environments[self.distro]: repo.clone(self.mcu_src_folder) @@ -183,6 +178,7 @@ def build_mcu_environment(self, meta_file, toolchain_file, user_meta = ""): sys.exit(1) def package_mcu_library(self): + binutils_path = self.resolve_binutils_path() aux_folder = self.build_folder + "/aux" shutil.rmtree(aux_folder, ignore_errors=True) @@ -194,12 +190,12 @@ def package_mcu_library(self): if f.endswith('.a'): os.makedirs(aux_folder + "/naming", exist_ok=True) os.chdir(aux_folder + "/naming") - os.system("ar x {}".format(root + "/" + f)) + os.system("{}ar x {}".format(binutils_path, root + "/" + f)) for obj in [x for x in os.listdir() if x.endswith('obj')]: os.rename(obj, '../' + f.split('.')[0] + "__" + obj) os.chdir(aux_folder) - command = "ar rc libmicroros.a $(ls *.o *.obj 2> /dev/null); rm *.o *.obj 2> /dev/null; ranlib libmicroros.a" + 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) result = run_cmd(command) if 0 != result.returncode: @@ -221,3 +217,15 @@ def package_mcu_library(self): if os.path.exists(repeated_path): shutil.copytree(repeated_path, folder_path, copy_function=shutil.move, dirs_exist_ok=True) shutil.rmtree(repeated_path) + + def resolve_binutils_path(self): + if sys.platform == "darwin": + homebrew_binutils_path = "/opt/homebrew/opt/binutils/bin/" + if os.path.exists(homebrew_binutils_path): + return homebrew_binutils_path + + print("ERROR: GNU binutils not found. ({}) Please install binutils with homebrew: brew install binutils" + .format(homebrew_binutils_path)) + sys.exit(1) + + return "" diff --git a/microros_utils/repositories.py b/microros_utils/repositories.py index 896d44b3..56d400d4 100644 --- a/microros_utils/repositories.py +++ b/microros_utils/repositories.py @@ -27,6 +27,14 @@ def __init__(self, name, url, distribution, branch=None): def clone(self, folder): self.path = folder + "/" + self.name # TODO(pablogs) ensure that git is installed + if os.path.exists(self.path): + command = f"cd {self.path} && git pull {self.url} {self.branch}" + result = run_cmd(command) + if 0 != result.returncode: + print(f"{self.name} pull failed: \n{result.stderr.decode('utf-8')}") + sys.exit(1) + return + command = "git clone -b {} {} {}".format(self.branch, self.url, self.path) result = run_cmd(command) @@ -88,6 +96,14 @@ class Sources: Repository("ament_cmake_ros", "https://github.com/ros2/ament_cmake_ros", "iron"), Repository("ament_index", "https://github.com/ament/ament_index", "iron") ], + 'jazzy': [ + Repository("ament_cmake", "https://github.com/ament/ament_cmake", "jazzy"), + Repository("ament_lint", "https://github.com/ament/ament_lint", "jazzy"), + Repository("ament_package", "https://github.com/ament/ament_package", "jazzy"), + Repository("googletest", "https://github.com/ament/googletest", "jazzy"), + Repository("ament_cmake_ros", "https://github.com/ros2/ament_cmake_ros", "jazzy"), + Repository("ament_index", "https://github.com/ament/ament_index", "jazzy") + ], 'rolling': [ Repository("ament_cmake", "https://github.com/ament/ament_cmake", "rolling"), Repository("ament_lint", "https://github.com/ament/ament_lint", "rolling"), @@ -164,6 +180,30 @@ class Sources: Repository("rcl_logging", "https://github.com/ros2/rcl_logging", "iron"), Repository("ros2_tracing", "https://github.com/ros2/ros2_tracing", "iron"), ], + 'jazzy': [ + Repository("micro-CDR", "https://github.com/eProsima/micro-CDR", "jazzy", "ros2"), + Repository("Micro-XRCE-DDS-Client", "https://github.com/eProsima/Micro-XRCE-DDS-Client", "jazzy", "ros2"), + Repository("rcl", "https://github.com/micro-ROS/rcl", "jazzy"), + Repository("rclc", "https://github.com/ros2/rclc", "jazzy"), + Repository("micro_ros_utilities", "https://github.com/micro-ROS/micro_ros_utilities", "jazzy"), + Repository("rcutils", "https://github.com/micro-ROS/rcutils", "jazzy"), + Repository("micro_ros_msgs", "https://github.com/micro-ROS/micro_ros_msgs", "jazzy"), + Repository("rmw-microxrcedds", "https://github.com/micro-ROS/rmw-microxrcedds", "jazzy"), + Repository("rosidl_typesupport", "https://github.com/micro-ROS/rosidl_typesupport", "jazzy"), + Repository("rosidl_typesupport_microxrcedds", "https://github.com/micro-ROS/rosidl_typesupport_microxrcedds", "jazzy"), + Repository("rosidl", "https://github.com/ros2/rosidl", "jazzy"), + Repository("rosidl_dynamic_typesupport", "https://github.com/ros2/rosidl_dynamic_typesupport", "jazzy"), + Repository("rosidl_core", "https://github.com/ros2/rosidl_core", "jazzy"), + Repository("rmw", "https://github.com/ros2/rmw", "jazzy"), + Repository("rcl_interfaces", "https://github.com/ros2/rcl_interfaces", "jazzy"), + Repository("rosidl_defaults", "https://github.com/ros2/rosidl_defaults", "jazzy"), + Repository("unique_identifier_msgs", "https://github.com/ros2/unique_identifier_msgs", "jazzy"), + Repository("common_interfaces", "https://github.com/ros2/common_interfaces", "jazzy"), + Repository("test_interface_files", "https://github.com/ros2/test_interface_files", "jazzy"), + Repository("rmw_implementation", "https://github.com/ros2/rmw_implementation", "jazzy"), + Repository("rcl_logging", "https://github.com/ros2/rcl_logging", "jazzy"), + Repository("ros2_tracing", "https://github.com/ros2/ros2_tracing", "jazzy"), + ], 'rolling': [ Repository("micro-CDR", "https://github.com/eProsima/micro-CDR", "rolling", "ros2"), Repository("Micro-XRCE-DDS-Client", "https://github.com/eProsima/Micro-XRCE-DDS-Client", "rolling", "ros2"), @@ -215,5 +255,6 @@ class Sources: ], 'humble': ['rcl_logging_log4cxx', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples'], 'iron': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples'], - 'rolling': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples'] - } \ No newline at end of file + 'jazzy': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples','lttngpy'], + 'rolling': ['test_tracetools', 'rcl_logging_spdlog', 'rcl_yaml_param_parser', 'rclc_examples','lttngpy'] + } diff --git a/platform_code/arduino/clock_gettime.cpp b/platform_code/arduino/clock_gettime.cpp index c98b9e9e..2422498e 100644 --- a/platform_code/arduino/clock_gettime.cpp +++ b/platform_code/arduino/clock_gettime.cpp @@ -3,7 +3,7 @@ #include #define micro_rollover_useconds 4294967295 -#ifndef WITH_POSIX +#if !defined(_POSIX_TIMERS) || !_POSIX_TIMERS extern "C" int clock_gettime(clockid_t unused, struct timespec *tp) { @@ -22,4 +22,4 @@ extern "C" int clock_gettime(clockid_t unused, struct timespec *tp) return 0; } -#endif // ifndef WITH_POSIX \ No newline at end of file +#endif // ifndef _POSIX_TIMERS