From e041742508a301ad6bc7f50316bb52aa224f5985 Mon Sep 17 00:00:00 2001 From: rafal-gorecki <126687345+rafal-gorecki@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:21:23 +0200 Subject: [PATCH] Copy params into docker image (#5) * Copy params into docker image * Update service image * Add device and robot namespace * Format * Move files in better dirs --- .github/workflows/build-docker-image.yaml | 11 +-- .gitignore | 3 + .pre-commit-config.yaml | 81 +++++++++++++++++++ Dockerfile | 3 + README.md | 18 ++++- demo/compose.yaml | 9 +-- .../nmea_navsat_params.yaml} | 3 +- demo/nmea_navsat.launch.py | 80 ++++++++++++++++++ 8 files changed, 191 insertions(+), 17 deletions(-) create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml rename demo/{params/nmea_socket_driver.yaml => config/nmea_navsat_params.yaml} (81%) create mode 100644 demo/nmea_navsat.launch.py diff --git a/.github/workflows/build-docker-image.yaml b/.github/workflows/build-docker-image.yaml index 35d25f5..2e790de 100644 --- a/.github/workflows/build-docker-image.yaml +++ b/.github/workflows/build-docker-image.yaml @@ -13,23 +13,20 @@ on: - development - stable target_distro: - description: - In case of "stable" release specify the ROS distro of the existing docker image (eg. + description: In case of "stable" release specify the ROS distro of the existing docker image (eg. humble) type: string default: ardent target_release: - description: - In case of "stable" release specify the version of the existing docker image (eg. + description: In case of "stable" release specify the version of the existing docker image (eg. 1.0.12) type: string default: 0.0.0 target_date: - description: - In case of "stable" release specify the date of the existing docker image in format + description: In case of "stable" release specify the date of the existing docker image in format YYYYMMDD (eg. 20220124) type: string - default: "20131206" + default: '20131206' repository_dispatch: types: [rebuild] pull_request: diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f8dded8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode + +*.pyc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5462d71 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,81 @@ +--- +repos: + # Standard hooks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-added-large-files + # mesh files has to be taken into account + args: [--maxkb=3000] + - id: check-ast + - id: check-case-conflict + - id: check-merge-conflict + - id: check-symlinks + - id: check-xml + - id: check-yaml + - id: debug-statements + - id: destroyed-symlinks + - id: detect-private-key + - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: name-tests-test + - id: mixed-line-ending + - id: trailing-whitespace + + # Python hooks + - repo: https://github.com/asottile/pyupgrade + rev: v3.15.2 + hooks: + - id: pyupgrade + args: [--py36-plus] + + - repo: https://github.com/psf/black + rev: 24.4.0 + hooks: + - id: black + args: [--line-length=99] + + - repo: https://github.com/PyCQA/flake8 + rev: 7.0.0 + hooks: + - id: flake8 + args: ['--ignore=E501,W503'] # ignore too long line and line break before binary operator, + # black checks it + + - repo: https://github.com/PyCQA/isort + rev: 5.13.2 + hooks: + - id: isort + args: [--profile, black] + + # XML + - repo: https://github.com/tier4/pre-commit-hooks-ros + rev: v0.8.0 + hooks: + - id: prettier-package-xml + - id: sort-package-xml + + # YAML + - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt + rev: 0.2.3 + hooks: + - id: yamlfmt + files: ^(?!.*compose)(?!.*ekf\.yaml$).*$ + args: [--mapping, '2', --sequence, '4', --offset, '2', --width, '100'] + + # Copyright + - repo: local + hooks: + - id: ament_copyright + name: ament_copyright + description: Check if copyright notice is available in all files. + entry: ament_copyright + language: system + + # Spellcheck + - repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + args: [--write-changes, --uri-ignore-words-list=ist, -L manuel] + exclude: CHANGELOG\.rst|\.(svg|pyc|drawio)$ diff --git a/Dockerfile b/Dockerfile index b11f243..a6bf7b4 100755 --- a/Dockerfile +++ b/Dockerfile @@ -24,3 +24,6 @@ RUN apt-get update && apt-get install -y \ apt-get clean && \ rm -rf src build && \ rm -rf /var/lib/apt/lists/* + +COPY demo/config/ /config +COPY demo/nmea_navsat.launch.py / diff --git a/README.md b/README.md index 195b3ea..57af9f1 100644 --- a/README.md +++ b/README.md @@ -14,24 +14,26 @@ ROS 2 driver to parse NMEA strings and publish standard ROS 2 NavSatFix message - `~/fix` [*sensor_msgs/msg/NavSatFix*]: GPS position fix reported by the device. This will be published with whatever positional and status data was available even if the device doesn't have a valid fix. Invalid fields may contain NaNs. - `~/heading` [*geometry_msgs/msg/QuaternionStamped*]: stamped orientation of heading. -- `~/time_reference` [*sensor_msgs/msg/TimeReference*]: The timestamp from the GPS device is used as the `time_ref``. +- `~/time_reference` [*sensor_msgs/msg/TimeReference*]: The timestamp from the GPS device is used as the `time_ref``. - `~/vel` [*geometry_msgs/msg/TwistStamped*]: Velocity output from the GPS device. Only published when the device outputs valid velocity information. The driver does not calculate the velocity based on only position fixes. #### Parameters Node GPS parameters: + - `~/time_ref_source` [*string*, default: **'gps'**]: The value to use as the source in the `sensor_msgs/msg/TimeReference`. - `~/useRMC` [*bool*, default: **False**]: Whether to generate position fixes from GGA sentences or RMC sentences. If True, fixes will be generated from RMC. If False, fixes will be generated based on the GGA sentences. Using GGA sentences allows for approximated covariance output while RMC provides velocity information. - `~/frame_id` [*string*, default: **'gps'**]: The`frame_id` for the header of the `sensor_msgs/msg/NavSatFix` and `geometry_msgs/msg/TwistStamped` output messages. Will be resolved with `tf_prefix` if defined. - `~/tf_prefix` [*string*, default: **''**]: Adds prefix to the `frame_id`. `nmea_socket_driver.py` parameters: + - `~/ip` [*string*, default: **'0.0.0.0'**]: The ip of socket server. - `~/port` [*int*, default: **10110**]: The port of socket server. - `~/buffer_size` [*int*, default: **4096**]: Communication buffer. - `~/timeout_sec` [*double*, default: **2**]: Timeout during waiting for packages in the socket. -# Panther Demo +## Panther Demo GPS data in [NMEA](https://en.wikipedia.org/wiki/NMEA_0183) format is forwarded to RPi IP address at port 5000, typically it is `10.15.20.2:5000`. You can make sure the address is correct by typing [http://10.15.20.1](http://10.15.20.1) into your browser (Username: `admin`, Password: `Husarion1`). Navigate to `Services -> GPS -> NMEA -> NMEA forwarding -> Hostname and Port`. Remember that you must be connected to the robot's WIFi network. If changes were needed, finish the configuration by pressing `save & apply` at the bottom of the screen. @@ -47,4 +49,14 @@ cd nmea-gps-docker/demo docker compose up ``` -You should be able to see data on `/panther/fix` topic (`ros2 topic echo /panther/fix`). +You should be able to see data on `/panther/gps/fix` topic (`ros2 topic echo /panther/gps/fix`). + +### Launch Parameters + +Contained within the image is a custom `/nmea_navsat.launch.py`, which is not included in the ROS 2 package for the `nmea_navsat_driver`. This was specifically added to facilitate seamless integration with Husarion robots. The following parameters are included in this launch file: + +| **Parameter** | **Description** | **Default Value** | +| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | +| `params_file` | Path to the parameter file for the nmea_socket_driver node. | `/config/nmea_navsat_params.yaml` | +| `robot_namespace` | Namespace to all launched nodes and use namespace as tf_prefix. This aids in differentiating between multiple robots with the same devices. | `env("ROBOT_NAMESPACE")` (`""` if not specified) | +| `device_namespace` | Namespace for the device, utilized in TF frames and preceding device topics. This aids in differentiating between multiple cameras on the same robot. | `gps` | diff --git a/demo/compose.yaml b/demo/compose.yaml index 4bbe2e9..c19069d 100644 --- a/demo/compose.yaml +++ b/demo/compose.yaml @@ -1,11 +1,8 @@ services: nmea-gps: - image: husarion/nmea-gps:humble-2.0.1-20240209 + image: husarion/nmea-gps:humble-2.0.1-20240617 network_mode: host restart: always - volumes: - - ./params:/params command: > - ros2 run nmea_navsat_driver nmea_socket_driver --ros-args - --params-file /params/nmea_socket_driver.yaml - -r __ns:=/panther + ros2 launch /nmea_navsat.launch.py + robot_namespace:=panther diff --git a/demo/params/nmea_socket_driver.yaml b/demo/config/nmea_navsat_params.yaml similarity index 81% rename from demo/params/nmea_socket_driver.yaml rename to demo/config/nmea_navsat_params.yaml index f20f545..4ddd311 100644 --- a/demo/params/nmea_socket_driver.yaml +++ b/demo/config/nmea_navsat_params.yaml @@ -1,6 +1,7 @@ +--- /**/nmea_navsat_driver: ros__parameters: - ip: "10.15.20.2" + ip: 10.15.20.2 port: 5000 buffer_size: 4096 timeout_sec: 2 diff --git a/demo/nmea_navsat.launch.py b/demo/nmea_navsat.launch.py new file mode 100644 index 0000000..c5206a4 --- /dev/null +++ b/demo/nmea_navsat.launch.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +# Copyright 2024 Husarion sp. z o.o. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import ( + EnvironmentVariable, + LaunchConfiguration, + PythonExpression, +) +from launch_ros.actions import Node + + +def generate_launch_description(): + device_namespace = LaunchConfiguration("device_namespace") + declare_device_namespace_arg = DeclareLaunchArgument( + "device_namespace", + default_value="gps", + description="Namespace for the device, utilized in TF frames and preceding device topics. This aids in differentiating between multiple cameras on the same robot.", + ) + + params_file = LaunchConfiguration("params_file") + declare_params_file_arg = DeclareLaunchArgument( + "params_file", + default_value="/config/nmea_navsat_params.yaml", + description="Path to the parameter file for the nmea_socket_driver node.", + ) + + robot_namespace = LaunchConfiguration("robot_namespace") + declare_robot_namespace_arg = DeclareLaunchArgument( + "robot_namespace", + default_value=EnvironmentVariable("ROBOT_NAMESPACE", default_value=""), + description="Namespace to all launched nodes and use namespace as tf_prefix. This aids in differentiating between multiple robots with the same devices.", + ) + + tf_prefix = PythonExpression( + ["'", robot_namespace, "/' if '", robot_namespace, "' != '' else ''"] + ) + + nmea_driver = Node( + package="nmea_navsat_driver", + executable="nmea_socket_driver", + name=device_namespace, + namespace=robot_namespace, + parameters=[ + { + "frame_id": device_namespace, + "tf_prefix": tf_prefix, + }, + params_file, + ], + remappings=[ + ("fix", "~/fix"), + ("heading", "~/heading"), + ("time_reference", "~/time_reference"), + ("vel", "~/vel"), + ], + ) + + return LaunchDescription( + [ + declare_params_file_arg, + declare_robot_namespace_arg, + declare_device_namespace_arg, + nmea_driver, + ] + )