diff --git a/.github/workflows/ros-docker-image.yaml b/.github/workflows/ros-docker-image.yaml index 34cce4c..f8fd7e0 100644 --- a/.github/workflows/ros-docker-image.yaml +++ b/.github/workflows/ros-docker-image.yaml @@ -43,7 +43,7 @@ jobs: repo_name: '' platforms: linux/amd64, linux/arm64 ros_distro: humble - - dockerfile: Dockerfile.simulation + - dockerfile: Dockerfile.gazebo repo_name: rosbot-gazebo platforms: linux/amd64 ros_distro: humble @@ -51,7 +51,7 @@ jobs: repo_name: '' platforms: linux/amd64, linux/arm64 ros_distro: iron - # - dockerfile: Dockerfile.simulation + # - dockerfile: Dockerfile.gazebo # repo_name: rosbot-gazebo # platforms: linux/amd64 # ros_distro: iron diff --git a/.github/workflows/vulcanexus-docker-image.yaml b/.github/workflows/vulcanexus-docker-image.yaml index 1ecd2be..4f64b52 100644 --- a/.github/workflows/vulcanexus-docker-image.yaml +++ b/.github/workflows/vulcanexus-docker-image.yaml @@ -43,7 +43,7 @@ jobs: repo_name: '' platforms: linux/amd64, linux/arm64 ros_distro: humble - - dockerfile: Dockerfile.simulation + - dockerfile: Dockerfile.gazebo repo_name: rosbot-gazebo platforms: linux/amd64 ros_distro: humble diff --git a/Dockerfile.simulation b/Dockerfile.gazebo similarity index 55% rename from Dockerfile.simulation rename to Dockerfile.gazebo index 74ccf8e..79cb433 100644 --- a/Dockerfile.simulation +++ b/Dockerfile.gazebo @@ -1,7 +1,8 @@ ARG ROS_DISTRO=humble ARG PREFIX= -FROM husarnet/ros:${PREFIX}${ROS_DISTRO}-ros-core +## =========================== ROS builder =============================== +FROM husarnet/ros:${PREFIX}${ROS_DISTRO}-ros-base AS ros_builder ARG PREFIX @@ -16,24 +17,24 @@ WORKDIR /ros2_ws COPY ./healthcheck.cpp / # install everything needed -RUN MYDISTRO=${PREFIX:-ros}; MYDISTRO=${MYDISTRO//-/} && \ - apt-get update --fix-missing && apt-get install -y \ +RUN apt-get update --fix-missing && apt-get install -y \ python3-pip \ ros-dev-tools && \ apt-get upgrade -y && \ # Clone source - source "/opt/$MYDISTRO/$ROS_DISTRO/setup.bash" && \ - git clone https://github.com/husarion/rosbot_ros.git /ros2_ws/src && \ + git clone --depth 1 https://github.com/husarion/rosbot_ros.git src && \ vcs import src < src/rosbot/rosbot_hardware.repos && \ vcs import src < src/rosbot/rosbot_simulation.repos && \ # Install dependencies rm -rf /etc/ros/rosdep/sources.list.d/20-default.list && \ rosdep init && \ rosdep update --rosdistro $ROS_DISTRO && \ - rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y && \ - # Create healthcheck package - cd src/ && \ + rosdep install --from-paths src --ignore-src -y + +RUN cd src/ && \ + MYDISTRO=${PREFIX:-ros}; MYDISTRO=${MYDISTRO//-/} && \ source /opt/$MYDISTRO/$ROS_DISTRO/setup.bash && \ + # Create healthcheck package ros2 pkg create healthcheck_pkg --build-type ament_cmake --dependencies rclcpp nav_msgs && \ sed -i '/find_package(nav_msgs REQUIRED)/a \ add_executable(healthcheck_node src/healthcheck.cpp)\n \ @@ -44,27 +45,40 @@ RUN MYDISTRO=${PREFIX:-ros}; MYDISTRO=${MYDISTRO//-/} && \ cd .. && \ # Build colcon build && \ - # make the image smaller - export SUDO_FORCE_REMOVE=yes && \ - apt-get remove -y \ + rm -rf build log + +## =========================== Final Stage =============================== +FROM husarnet/ros:${PREFIX}${ROS_DISTRO}-ros-core + +ARG ROS_DISTRO +ARG PREFIX + +# select bash as default shell +SHELL ["/bin/bash", "-c"] + +ENV IGNITION_VERSION fortress +ENV HUSARION_ROS_BUILD simulation + +WORKDIR /ros2_ws + +COPY --from=ros_builder /ros2_ws /ros2_ws + +RUN apt-get update && apt-get install -y \ + python3-rosdep \ python3-pip \ - ros-dev-tools && \ - apt-get autoremove -y && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -RUN echo $(cat /ros2_ws/src/rosbot_gazebo/package.xml | grep '' | sed -r 's/.*([0-9]+.[0-9]+.[0-9]+)<\/version>/\1/g') > /version.txt - -RUN if [ -f "/ros_entrypoint.sh" ]; then \ - sed -i '/test -f "\/ros2_ws\/install\/setup.bash" && source "\/ros2_ws\/install\/setup.bash"/a \ - ros2 run healthcheck_pkg healthcheck_node &' \ - /ros_entrypoint.sh; \ - else \ - sed -i '/test -f "\/ros2_ws\/install\/setup.bash" && source "\/ros2_ws\/install\/setup.bash"/a \ - ros2 run healthcheck_pkg healthcheck_node &' \ - /vulcanexus_entrypoint.sh; \ - fi - -COPY ./healthcheck.sh / + ros-$ROS_DISTRO-teleop-twist-keyboard && \ + rm -rf /etc/ros/rosdep/sources.list.d/20-default.list && \ + rosdep init && \ + rosdep update --rosdistro $ROS_DISTRO && \ + rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y && \ + apt-get clean && \ + echo $(cat /ros2_ws/src/rosbot_gazebo/package.xml | grep '' | sed -r 's/.*([0-9]+.[0-9]+.[0-9]+)<\/version>/\1/g') > /version.txt && \ + rm -rf src && \ + rm -rf /var/lib/apt/lists/* + +COPY ros_entrypoint.sh / +COPY vulcanexus_entrypoint.sh / +COPY healthcheck.sh / + HEALTHCHECK --interval=7s --timeout=2s --start-period=5s --retries=5 \ - CMD ["/healthcheck.sh"] + CMD ["/healthcheck.sh"] \ No newline at end of file diff --git a/Dockerfile.hardware b/Dockerfile.hardware index d33fe6c..153bf47 100644 --- a/Dockerfile.hardware +++ b/Dockerfile.hardware @@ -1,9 +1,9 @@ ARG ROS_DISTRO=humble ARG PREFIX= -ARG ROSBOT_FW_RELEASE=0.7.0 +ARG ROSBOT_FW_RELEASE=0.8.0 ## ============================ STM32FLASH ================================= # stm32flash needs an older version of glibc (2.28), which is why ubuntu 18.04 was used -FROM ubuntu:18.04 AS stm32flash_builder_and_downloader +FROM ubuntu:18.04 AS stm32flash_builder ARG ROS_DISTRO ARG ROSBOT_FW_RELEASE @@ -26,8 +26,6 @@ RUN echo ros_distro=$ROS_DISTRO firmware_release=$ROSBOT_FW_RELEASE RUN curl -L https://github.com/husarion/rosbot_ros2_firmware/releases/download/$ROSBOT_FW_RELEASE/firmware.bin -o /firmware.bin && \ curl -L https://github.com/husarion/rosbot_ros2_firmware/releases/download/$ROSBOT_FW_RELEASE/firmware.hex -o /firmware.hex -RUN git clone https://github.com/husarion/rosbot_ros.git /ros2_ws/src - ## =========================== Firmware CPU ID ================================ FROM ubuntu:20.04 AS cpu_id_builder @@ -50,37 +48,27 @@ RUN pip3 install -U platformio && \ pio run && \ chmod -x .pio/build/olimex_e407/firmware.bin -## =========================== ROS image =============================== -FROM husarnet/ros:${PREFIX}${ROS_DISTRO}-ros-core + +## =========================== ROS builder =============================== +FROM husarnet/ros:${PREFIX}${ROS_DISTRO}-ros-base AS ros_builder ARG ROS_DISTRO ARG PREFIX SHELL ["/bin/bash", "-c"] -RUN mkdir -p /ros2_ws/src && cd /ros2_ws/src WORKDIR /ros2_ws +RUN mkdir src -# copy firmware built in previous stage and downloaded repository -COPY --from=stm32flash_builder_and_downloader /firmware.bin /root/firmware.bin -COPY --from=stm32flash_builder_and_downloader /firmware.hex /root/firmware.hex -COPY --from=stm32flash_builder_and_downloader /stm32flash/stm32flash /usr/bin/stm32flash -COPY --from=stm32flash_builder_and_downloader /ros2_ws /ros2_ws -COPY --from=cpu_id_builder /read_cpu_id/.pio/build/olimex_e407/firmware.bin /firmware_read_cpu_id.bin COPY ./healthcheck.cpp / RUN apt-get update && apt-get install -y \ git \ python3-pip \ - python3-colcon-common-extensions \ - python3-rosdep \ - python3-vcstool \ python3-sh \ - python3-periphery \ - build-essential \ - ros-$ROS_DISTRO-teleop-twist-keyboard && \ + python3-periphery && \ pip3 install pyserial && \ - MYDISTRO=${PREFIX:-ros}; MYDISTRO=${MYDISTRO//-/} && \ + git clone --depth 1 https://github.com/husarion/rosbot_ros.git src -b humble && \ vcs import src < src/rosbot/rosbot_hardware.repos && \ # it is necessary to remove simulation - otherwise rosdep tries to install dependencies rm -r src/rosbot_gazebo && \ @@ -88,10 +76,13 @@ RUN apt-get update && apt-get install -y \ rm -rf /etc/ros/rosdep/sources.list.d/20-default.list && \ rosdep init && \ rosdep update --rosdistro $ROS_DISTRO && \ - rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y && \ - # Create health check package - cd src/ && \ + rosdep install --from-paths src --ignore-src -y + + +RUN cd src/ && \ + MYDISTRO=${PREFIX:-ros}; MYDISTRO=${MYDISTRO//-/} && \ source /opt/$MYDISTRO/$ROS_DISTRO/setup.bash && \ + # Create health check package ros2 pkg create healthcheck_pkg --build-type ament_cmake --dependencies rclcpp nav_msgs && \ sed -i '/find_package(nav_msgs REQUIRED)/a \ add_executable(healthcheck_node src/healthcheck.cpp)\n \ @@ -101,34 +92,66 @@ RUN apt-get update && apt-get install -y \ mv /healthcheck.cpp /ros2_ws/src/healthcheck_pkg/src/ && \ cd .. && \ # Build - colcon build && \ - # clear ubuntu packages + colcon build --packages-skip \ + ackermann_steering_controller \ + admittance_controller \ + bicycle_steering_controller \ + tricycle_steering_controller \ + effort_controllers \ + force_torque_sensor_broadcaster \ + forward_command_controller \ + gripper_controllers \ + joint_trajectory_controller \ + position_controllers \ + range_sensor_broadcaster \ + ros2_controllers \ + ros2_controllers_test_nodes \ + rqt_joint_trajectory_controller \ + tricycle_controller \ + tricycle_steering_controller \ + velocity_controllers && \ + rm -rf build log + +## =========================== Final Stage =============================== +FROM husarnet/ros:${PREFIX}${ROS_DISTRO}-ros-core + +ARG ROS_DISTRO +ARG PREFIX + +SHELL ["/bin/bash", "-c"] + +WORKDIR /ros2_ws + +COPY --from=ros_builder /ros2_ws /ros2_ws + +RUN apt-get update && apt-get install -y \ + python3-rosdep \ + ros-$ROS_DISTRO-teleop-twist-keyboard && \ + rm -rf /etc/ros/rosdep/sources.list.d/20-default.list && \ + rosdep init && \ + rosdep update --rosdistro $ROS_DISTRO && \ + rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y && \ apt-get clean && \ - apt-get remove -y \ - git \ - python3-colcon-common-extensions \ - python3-rosdep \ - python3-vcstool \ - python3-pip \ - build-essential && \ + echo $(cat /ros2_ws/src/rosbot/package.xml | grep '' | sed -r 's/.*([0-9]+.[0-9]+.[0-9]+)<\/version>/\1/g') >> /version.txt && \ + rm -rf src && \ rm -rf /var/lib/apt/lists/* -RUN echo $(cat /ros2_ws/src/rosbot/package.xml | grep '' | sed -r 's/.*([0-9]+.[0-9]+.[0-9]+)<\/version>/\1/g') >> /version.txt +# copy firmware built in previous stage and downloaded repository +COPY --from=stm32flash_builder /firmware.bin /root/firmware.bin +COPY --from=stm32flash_builder /firmware.hex /root/firmware.hex +COPY --from=stm32flash_builder /stm32flash/stm32flash /usr/bin/stm32flash -RUN if [ -f "/ros_entrypoint.sh" ]; then \ - sed -i '/test -f "\/ros2_ws\/install\/setup.bash" && source "\/ros2_ws\/install\/setup.bash"/a \ - ros2 run healthcheck_pkg healthcheck_node &' \ - /ros_entrypoint.sh; \ - else \ - sed -i '/test -f "\/ros2_ws\/install\/setup.bash" && source "\/ros2_ws\/install\/setup.bash"/a \ - ros2 run healthcheck_pkg healthcheck_node &' \ - /vulcanexus_entrypoint.sh; \ - fi +COPY --from=cpu_id_builder /read_cpu_id/.pio/build/olimex_e407/firmware.bin /firmware_read_cpu_id.bin + +COPY ros_entrypoint.sh / +COPY vulcanexus_entrypoint.sh / +COPY healthcheck.sh / -COPY ./healthcheck.sh / HEALTHCHECK --interval=7s --timeout=2s --start-period=5s --retries=5 \ CMD ["/healthcheck.sh"] +COPY microros_localhost_only.xml / + # copy scripts COPY flash-firmware.py / COPY flash-firmware.py /usr/bin/ diff --git a/demo/.env b/demo/.env deleted file mode 100644 index 4e12be9..0000000 --- a/demo/.env +++ /dev/null @@ -1,12 +0,0 @@ -# ======================================= -# Hardware config -# ======================================= -LIDAR_SERIAL=/dev/ttyUSB0 - -# for RPLIDAR A2M8 (red circle around the sensor): -LIDAR_BAUDRATE=115200 -# for RPLIDAR A2M12 and A3 (violet circle around the sensor): -# LIDAR_BAUDRATE=256000 - -# uncomment for ROSbots with mecanum wheels -# MECANUM=True diff --git a/demo/compose.simulation.yaml b/demo/compose.gazebo.yaml similarity index 50% rename from demo/compose.simulation.yaml rename to demo/compose.gazebo.yaml index 616a95c..8e67483 100644 --- a/demo/compose.simulation.yaml +++ b/demo/compose.gazebo.yaml @@ -1,8 +1,8 @@ -x-net-config: - &net-config - network_mode: host - ipc: host - env_file: net.env +# Quick Start +# +# 1. run `xhost +local:docker && docker compose -f compose.gazebo.yaml up` on the laptop +# 2. open a shell inside a docker container `docker compose -f compose.gazebo.yaml exec -it rosbot bash` +# 2. run `ros2 run teleop_twist_keyboard teleop_twist_keyboard` inside the container x-gpu-config: &gpu-config @@ -20,9 +20,11 @@ x-cpu-config: services: rosbot: - image: husarion/rosbot-gazebo:humble - <<: [ *net-config, *gpu-config] + # image: husarion/rosbot-gazebo:humble + build: + context: ../ + dockerfile: Dockerfile.gazebo + <<: [ *cpu-config] volumes: - /tmp/.X11-unix:/tmp/.X11-unix:rw - - /dev:/dev command: ros2 launch rosbot_gazebo simulation.launch.py mecanum:=${MECANUM:-False} diff --git a/demo/compose.yaml b/demo/compose.yaml index 0226cba..860f4ee 100644 --- a/demo/compose.yaml +++ b/demo/compose.yaml @@ -1,25 +1,20 @@ -x-net-config: - &net-config - network_mode: host - ipc: host - env_file: net.env +# Quick Start +# +# 1. run `docker compose up` on the robot +# 2. run `ROS_DOMAIN_ID=10 ros2 run teleop_twist_keyboard teleop_twist_keyboard` in the robot termianl services: rosbot: - image: husarion/rosbot:humble - <<: *net-config + image: husarion/rosbot:humble-0.10.3-20231128 environment: - - ROS_DOMAIN_ID + - ROS_DOMAIN_ID=10 command: ros2 launch rosbot_bringup bringup.launch.py mecanum:=${MECANUM:-False} - - micro-xrce-agent: - image: husarion/micro-xrce-agent:v2.4.1 - <<: *net-config + micro-ros-agent: + image: husarion/micro-ros-agent:humble-3.1.3-20231122 devices: - ${SERIAL_PORT:?err} environment: - - XRCE_DOMAIN_ID_OVERRIDE=${ROS_DOMAIN_ID} # *** - - SERIAL_PORT - command: MicroXRCEAgent serial -D $SERIAL_PORT serial -b 576000 # -v6 + - ROS_DOMAIN_ID=10 + command: ros2 run micro_ros_agent micro_ros_agent serial -D $SERIAL_PORT serial -b 576000 # -v6 diff --git a/demo/namespace/compose.yaml b/demo/namespace/compose.yaml new file mode 100644 index 0000000..78424ca --- /dev/null +++ b/demo/namespace/compose.yaml @@ -0,0 +1,38 @@ +# Quick Start +# +# 1. run `docker compose up` on the robot +# 2. On the second host in LAN you will see only single ros2 topic: +# $ ros2 topic list +# /parameter_events +# /robot1/cmd_vel +# /rosout +# 3. You can use teleop_twist_keyboard to control the robot in robot1 namespace: +# `ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r __ns:=/robot1` + +services: + + rosbot: + image: husarion/rosbot:humble-ros2-combined-microros + network_mode: host + ipc: host + devices: + - ${SERIAL_PORT:?err} + environment: + - FASTRTPS_DEFAULT_PROFILES_FILE=/shm-only.xml + command: > + ros2 launch rosbot_bringup combined.launch.py + mecanum:=${MECANUM:-False} + serial_port:=$SERIAL_PORT + serial_baudrate:=576000 + namespace:=robot1 + + ros2router: + image: husarnet/ros2router:1.4.0 + network_mode: host + ipc: host + volumes: + - ./filter.yaml:/filter.yaml + environment: + - USE_HUSARNET=FALSE + - ROS_LOCALHOST_ONLY=1 + - ROS_DISTRO diff --git a/demo/namespace/filter.yaml b/demo/namespace/filter.yaml new file mode 100644 index 0000000..a6da4ee --- /dev/null +++ b/demo/namespace/filter.yaml @@ -0,0 +1,5 @@ +allowlist: + - name: "rt/robot1/cmd_vel" + type: "geometry_msgs::msg::dds_::Twist_" +blocklist: [] +builtin-topics: [] \ No newline at end of file diff --git a/demo/net.env b/demo/net.env deleted file mode 100644 index 029bdbe..0000000 --- a/demo/net.env +++ /dev/null @@ -1,17 +0,0 @@ -# ======================================= -# Network config options (uncomment one) -# ======================================= - -# 1. Fast DDS + LAN -# RMW_IMPLEMENTATION=rmw_fastrtps_cpp - -# 2. Cyclone DDS + LAN -RMW_IMPLEMENTATION=rmw_cyclonedds_cpp - -# 3. Fast DDS + VPN -# RMW_IMPLEMENTATION=rmw_fastrtps_cpp -# FASTRTPS_DEFAULT_PROFILES_FILE=/husarnet-fastdds.xml - -# 4. Cyclone DDS + VPN -# RMW_IMPLEMENTATION=rmw_cyclonedds_cpp -# CYCLONEDDS_URI=file:///husarnet-cyclonedds.xml diff --git a/microros_localhost_only.xml b/microros_localhost_only.xml new file mode 100644 index 0000000..d433142 --- /dev/null +++ b/microros_localhost_only.xml @@ -0,0 +1,26 @@ + + + + + + + CustomUdpTransport + UDPv4 + +
127.0.0.1
+
+
+
+ + + + + CustomUdpTransport + + + false + + +
+
\ No newline at end of file diff --git a/ros_entrypoint.sh b/ros_entrypoint.sh new file mode 100755 index 0000000..21341ce --- /dev/null +++ b/ros_entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +output=$(husarnet-dds singleshot) || true +if [[ "$HUSARNET_DDS_DEBUG" == "TRUE" ]]; then + echo "$output" +fi + +# Check if XRCE_DOMAIN_ID_OVERRIDE is unset or empty +if [ -z "$XRCE_DOMAIN_ID_OVERRIDE" ]; then + # If ROS_DOMAIN_ID is set and not empty, set XRCE_DOMAIN_ID_OVERRIDE to its value + if [ -n "$ROS_DOMAIN_ID" ]; then + export XRCE_DOMAIN_ID_OVERRIDE="$ROS_DOMAIN_ID" + fi +fi + +# setup ros environment +source "/opt/ros/$ROS_DISTRO/setup.bash" +source "/ros2_ws/install/setup.bash" + +ros2 run healthcheck_pkg healthcheck_node & + +exec "$@" diff --git a/sync_with_rosbot.sh b/sync_with_rosbot.sh index 2dbd9c5..f4a2738 100755 --- a/sync_with_rosbot.sh +++ b/sync_with_rosbot.sh @@ -3,8 +3,8 @@ # If your ROSbot's IP addr is 10.5.10.64 execute: # ./sync_with_rosbot.sh 10.5.10.64 -sshpass -p "husarion" rsync -vRr ./ husarion@$1:/home/husarion/${PWD##*/} +sshpass -p "husarion" rsync -vRr --delete ./ husarion@$1:/home/husarion/${PWD##*/} -while inotifywait -r -e modify,create,delete,move ./ ; do - sshpass -p "husarion" rsync -vRr ./ husarion@$1:/home/husarion/${PWD##*/} -done +while inotifywait -r -e modify,create,delete,move ./ ; do + sshpass -p "husarion" rsync -vRr --delete ./ husarion@$1:/home/husarion/${PWD##*/} +done \ No newline at end of file diff --git a/vulcanexus_entrypoint.sh b/vulcanexus_entrypoint.sh new file mode 100755 index 0000000..950ae45 --- /dev/null +++ b/vulcanexus_entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +output=$(husarnet-dds singleshot) || true +if [[ "$HUSARNET_DDS_DEBUG" == "TRUE" ]]; then + echo "$output" +fi + +# Check if XRCE_DOMAIN_ID_OVERRIDE is unset or empty +if [ -z "$XRCE_DOMAIN_ID_OVERRIDE" ]; then + # If ROS_DOMAIN_ID is set and not empty, set XRCE_DOMAIN_ID_OVERRIDE to its value + if [ -n "$ROS_DOMAIN_ID" ]; then + export XRCE_DOMAIN_ID_OVERRIDE="$ROS_DOMAIN_ID" + fi +fi + +# setup ros environment +source "/opt/vulcanexus/$ROS_DISTRO/setup.bash" +source "/ros2_ws/install/setup.bash" + +ros2 run healthcheck_pkg healthcheck_node & + +exec "$@"