Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 40620300ed | |||
| a27c7147c3 | |||
| e50d0e2c27 | |||
| 7e1cad1536 | |||
| 44e039beac | |||
| 93e9291e19 | |||
| 6cf51a3b67 | |||
| 48eb4d10fd | |||
| bd531ee9cb | |||
| 02e944d1b1 | |||
| e869d4d023 | |||
| 152451b134 | |||
| 3d692c0083 | |||
| 47274dcb36 | |||
| ecdbe00d07 | |||
| 9d62ca663f | |||
| 08bf9b81bc | |||
| f97df2273b | |||
| 76701e81c0 | |||
| a81b99cd3c | |||
| 31305f1f8d | |||
| 759f77f58a | |||
| f5c6fa19ac | |||
| fc0dc5746c | |||
| d8c1bc3cca | |||
| ae3111229e | |||
| 426fe239a7 | |||
| b506c1d133 | |||
| b66deea825 | |||
| f58a638453 | |||
| 9efe4a8e76 | |||
| 39cb5cf26f | |||
| be405bb64d | |||
| 30895501ed | |||
| fcb8987589 | |||
| 021fb5ba1a | |||
| 98b9fb2122 | |||
| f0c1d0b36d | |||
| 3273b4ba8c | |||
| b4ecf2d46b | |||
| a5b118ad79 | |||
| 2fa19af554 | |||
| 1ace9dd1e3 | |||
| 097bf4f2ca | |||
| ddef31d11a | |||
| dcb52622eb | |||
| b50a0c4496 | |||
| 305373ed09 | |||
| 7348751c89 | |||
| 530a53641e | |||
| 959f2ac4ee | |||
| cf17bb899b | |||
| 049d3995ba | |||
| c6dbf7084e | |||
| 79fa72a8b0 | |||
| b19a0817dc | |||
| a29b104b9d | |||
| e4c9f9b489 | |||
| 6e8320c438 | |||
| 943ce5b06f | |||
| 3b6641c1fb | |||
| 0e07017cc6 | |||
| 06535abad4 | |||
| 926cdec601 | |||
| d8d5d450bb | |||
| 1e82e0115a | |||
| 5cf886315d |
@@ -0,0 +1,13 @@
|
|||||||
|
<!-- ~/.ros2/dds/cyclonedds.xml -->
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<CycloneDDS xmlns="https://cdds.io/config"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="https://cdds.io/config
|
||||||
|
https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd">
|
||||||
|
<Domain Id="any">
|
||||||
|
<Discovery>
|
||||||
|
<ParticipantIndex>auto</ParticipantIndex>
|
||||||
|
<MaxAutoParticipantIndex>1000</MaxAutoParticipantIndex>
|
||||||
|
</Discovery>
|
||||||
|
</Domain>
|
||||||
|
</CycloneDDS>
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# syntax=docker/dockerfile:1.7-labs
|
||||||
|
FROM osrf/ros:jazzy-desktop-full
|
||||||
|
ARG USERNAME=USERNAME
|
||||||
|
ARG USER_UID=1000
|
||||||
|
ARG USER_GID=$USER_UID
|
||||||
|
ARG TARGETARCH
|
||||||
|
|
||||||
|
# Delete user if it exists in container (e.g Ubuntu Noble: ubuntu)
|
||||||
|
RUN if id -u $USER_UID ; then userdel `id -un $USER_UID` ; fi
|
||||||
|
|
||||||
|
# Create the user
|
||||||
|
RUN groupadd --gid $USER_GID $USERNAME \
|
||||||
|
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
|
||||||
|
#
|
||||||
|
# [Optional] Add sudo support. Omit if you don't need to install software after connecting.
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends sudo \
|
||||||
|
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
|
||||||
|
&& chmod 0440 /etc/sudoers.d/$USERNAME \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Make sure the base image is completely up to date
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
apt-get update \
|
||||||
|
&& apt-get upgrade -y \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
|
# C++ development tools
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
cmake \
|
||||||
|
gdb \
|
||||||
|
clang \
|
||||||
|
clang-format \
|
||||||
|
clang-tidy \
|
||||||
|
libboost-all-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Python development tools
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
python3-pip \
|
||||||
|
python3-dev \
|
||||||
|
python3-argcomplete \
|
||||||
|
python3-colcon-common-extensions \
|
||||||
|
python3-colcon-mixin \
|
||||||
|
python3-rosdep \
|
||||||
|
python3-vcstool \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Copy boilerplate project config into workspace so it can be parsed by rosdep.
|
||||||
|
# This will be obscured by the volume mount or the workspace in the devcontainer
|
||||||
|
# Don't include all sources, because the rosdep will re-process on any file change
|
||||||
|
COPY --parents src/**/package.xml src/**/COLCON_IGNORE src/
|
||||||
|
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
apt-get update \
|
||||||
|
&& rosdep update --rosdistro $ROS_DISTRO \
|
||||||
|
&& rosdep install --from-paths src --ignore-src -y \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
|
ENV SHELL=/bin/bash
|
||||||
|
|
||||||
|
# [Optional] Set the default user. Omit if you want to keep the default as root.
|
||||||
|
USER $USERNAME
|
||||||
|
CMD ["/bin/bash"]
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/docker-from-docker:1": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "ghcr.io/devcontainers/features/docker-from-docker@sha256:c2c2cf829505ead8e4892c88c31b6594ae94a2bbb209e16e1fac456c1a3a624e",
|
||||||
|
"integrity": "sha256:c2c2cf829505ead8e4892c88c31b6594ae94a2bbb209e16e1fac456c1a3a624e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "ROS 2 Jazzy",
|
||||||
|
"privileged": true,
|
||||||
|
"remoteUser": "${localEnv:USER}",
|
||||||
|
"build": {
|
||||||
|
"context": "../..",
|
||||||
|
"dockerfile": "Dockerfile.jazzy",
|
||||||
|
"args": {
|
||||||
|
"USERNAME": "${localEnv:USER}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspaceFolder": "/workspaces/agv_pro_ros2",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/docker-from-docker:1": {
|
||||||
|
"version": "latest",
|
||||||
|
"moby": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"ms-python.python",
|
||||||
|
"anthropic.claude-code"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"containerEnv": {
|
||||||
|
"DISPLAY": ":0",
|
||||||
|
"ROS_AUTOMATIC_DISCOVERY_RANGE": "SUBNET",
|
||||||
|
"ROS_DOMAIN_ID": "0",
|
||||||
|
"RMW_IMPLEMENTATION": "rmw_cyclonedds_cpp",
|
||||||
|
"CYCLONEDDS_URI": "/workspaces/agv_pro_ros2/.devcontainer/cyclonedds.xml"
|
||||||
|
},
|
||||||
|
"runArgs": [
|
||||||
|
// "--network=robot-sim",
|
||||||
|
"--network=host",
|
||||||
|
"--pid=host",
|
||||||
|
"--ipc=host",
|
||||||
|
"--group-add=dialout",
|
||||||
|
"-e",
|
||||||
|
"DISPLAY=${env:DISPLAY}"
|
||||||
|
],
|
||||||
|
"mounts": [
|
||||||
|
"source=/dev,target=/dev,type=bind",
|
||||||
|
"source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached",
|
||||||
|
"source=/usr/local/share/ca-certificates,target=/usr/local/share/host-certificates,type=bind,consistency=cached",
|
||||||
|
"source=${localEnv:HOME}/.ssh,target=/home/${localEnv:USER}/.ssh,type=bind,consistency=cached"
|
||||||
|
],
|
||||||
|
"postCreateCommand": "bash .devcontainer/post-create.sh"
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ROSDEP_APT_LIST_FILE="${ROOT_DIR}/.devcontainer/${ROS_DISTRO}/rosdep-apt-packages.txt"
|
||||||
|
|
||||||
|
|
||||||
|
if [[ -f /usr/local/share/host-certificates/AMD_CA.crt ]]; then
|
||||||
|
sudo cp /usr/local/share/host-certificates/AMD_CA.crt /usr/local/share/ca-certificates/
|
||||||
|
sudo update-ca-certificates
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "${ROSDEP_APT_LIST_FILE}" ]]; then
|
||||||
|
echo "Missing ${ROSDEP_APT_LIST_FILE}."
|
||||||
|
echo "Run .devcontainer/refresh-rosdep-cache.sh and rebuild the devcontainer."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmp_packages="$(mktemp)"
|
||||||
|
cleanup() {
|
||||||
|
rm -f "${tmp_packages}"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
sudo apt-get update -qq
|
||||||
|
|
||||||
|
rosdep keys --from-paths src --ignore-src 2>/dev/null \
|
||||||
|
| xargs -r rosdep resolve --rosdistro "${ROS_DISTRO}" --filter-for-installers=apt 2>/dev/null \
|
||||||
|
| sed -e '/^#/d' -e '/^$/d' \
|
||||||
|
| LC_ALL=C sort -u > "${tmp_packages}"
|
||||||
|
|
||||||
|
if ! diff -u <(grep -Ev '^\s*($|#)' "${ROSDEP_APT_LIST_FILE}") "${tmp_packages}" >/dev/null; then
|
||||||
|
echo "rosdep-resolved apt packages differ from ${ROSDEP_APT_LIST_FILE}."
|
||||||
|
echo "Run .devcontainer/refresh-rosdep-cache.sh and rebuild the devcontainer."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "rosdep apt cache is current; no post-create package installation needed."
|
||||||
|
|
||||||
|
if compgen -G "${ROOT_DIR}/src/robotnik/robotnik_simulation/debs/ros-jazzy-*.deb" > /dev/null; then
|
||||||
|
sudo apt-get install -y "${ROOT_DIR}"/src/robotnik/robotnik_simulation/debs/ros-jazzy-*.deb
|
||||||
|
fi
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ROS_DISTRO="${ROS_DISTRO:-jazzy}"
|
||||||
|
CACHE_DIR="${ROOT_DIR}/.devcontainer/${ROS_DISTRO}"
|
||||||
|
APT_LIST_FILE="${CACHE_DIR}/rosdep-apt-packages.txt"
|
||||||
|
|
||||||
|
cd "${ROOT_DIR}"
|
||||||
|
|
||||||
|
mkdir -p "${CACHE_DIR}"
|
||||||
|
|
||||||
|
if [[ ! -f /etc/ros/rosdep/sources.list.d/20-default.list ]]; then
|
||||||
|
sudo rosdep init
|
||||||
|
fi
|
||||||
|
|
||||||
|
rosdep update
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
sudo apt-get update -qq
|
||||||
|
|
||||||
|
tmp_packages="$(mktemp)"
|
||||||
|
cleanup() {
|
||||||
|
rm -f "${tmp_packages}"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
rosdep keys --from-paths src --ignore-src 2>/dev/null \
|
||||||
|
| xargs -r rosdep resolve --rosdistro "${ROS_DISTRO}" --filter-for-installers=apt 2>/dev/null \
|
||||||
|
| sed -e '/^#/d' -e '/^$/d' \
|
||||||
|
| LC_ALL=C sort -u > "${tmp_packages}"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "# Generated by .devcontainer/refresh-rosdep-cache.sh"
|
||||||
|
echo "# apt packages resolved from rosdep keys in src"
|
||||||
|
cat "${tmp_packages}"
|
||||||
|
} > "${APT_LIST_FILE}"
|
||||||
|
|
||||||
|
echo "Updated ${APT_LIST_FILE}"
|
||||||
@@ -5,3 +5,5 @@ install/
|
|||||||
log/
|
log/
|
||||||
/CMakeLists.txt
|
/CMakeLists.txt
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
# Ignore upstream as it is installedls by the upstream.jazzy.repos
|
||||||
|
src/upstream
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
FROM ros:jazzy
|
||||||
|
|
||||||
|
# Create the workspace and copy all source directories into it
|
||||||
|
WORKDIR /ros2_ws
|
||||||
|
ARG TARGETARCH
|
||||||
|
|
||||||
|
COPY src ./src/
|
||||||
|
COPY patches ./patches/
|
||||||
|
COPY upstream.jazzy.repos ./upstream.jazzy.repos
|
||||||
|
|
||||||
|
# Import all upstream repostories
|
||||||
|
RUN mkdir -p src/upstream && vcs import ./src/upstream < ./upstream.jazzy.repos
|
||||||
|
|
||||||
|
# Apply patches to upstream
|
||||||
|
RUN ./patches/apply_patches.sh
|
||||||
|
|
||||||
|
# system deps from frozen rosdep manifest — no rosdep at build or startup
|
||||||
|
# NOTE: There should be a check in your CI that this file is up to date.
|
||||||
|
# Something like:
|
||||||
|
# ./scripts/freeze-rosdep.sh && git diff --exit-code rosdep-packages.txt
|
||||||
|
# COPY rosdep-packages.txt /tmp/rosdep-packages.txt
|
||||||
|
# The --mount=type=cache option caches the apt packages with buildkit
|
||||||
|
# The id-apt-cache-${TARGETARCH} option allows for separate caches for different architectures
|
||||||
|
# this enables parallel builds for different architectures without cache conflicts
|
||||||
|
# RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
# rm -f /etc/apt/apt.conf.d/docker-clean \
|
||||||
|
# && apt-get update \
|
||||||
|
# && xargs -r -a /tmp/rosdep-packages.txt apt-get install -y --no-install-recommends \
|
||||||
|
# && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Make sure the base image is completely up to date
|
||||||
|
# ros:jazzy ships /etc/apt/apt.conf.d/docker-clean which purges downloaded .debs;
|
||||||
|
# remove it so the --mount=type=cache on /var/cache/apt actually retains archives.
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
rm -f /etc/apt/apt.conf.d/docker-clean \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get upgrade -y \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
|
# Install dependencies with rosdep
|
||||||
|
# This will catch anything that wasn't installed via .deb's from the frozen rosdep manifest.
|
||||||
|
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt-cache-${TARGETARCH} \
|
||||||
|
rm -f /etc/apt/apt.conf.d/docker-clean && \
|
||||||
|
apt-get update && \
|
||||||
|
rosdep update && \
|
||||||
|
rosdep install --from-paths src --ignore-src -r -y && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Build the workspace with symlink install
|
||||||
|
# livox_sdk is now an ament_cmake package built by colcon (no manual /usr/local install needed).
|
||||||
|
RUN . /opt/ros/jazzy/setup.sh && \
|
||||||
|
colcon build --symlink-install
|
||||||
|
# Source the overlay on container startup
|
||||||
|
RUN echo "source /opt/ros/jazzy/setup.bash" >> /root/.bashrc && \
|
||||||
|
echo "source /ros2_ws/install/setup.bash" >> /root/.bashrc
|
||||||
|
|
||||||
|
CMD ["bash"]
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# lslidar
|
|
||||||
|
|
||||||
## Description
|
|
||||||
The `lslidar package is a linux ROS2 driver for lslidar M10 ,M10_GPS,M10_P,M10_PLUS and N10.
|
|
||||||
The package is tested on Ubuntu 20.04 with ROS2 FOXY.
|
|
||||||
|
|
||||||
## Compling
|
|
||||||
This is a Catkin package. Make sure the package is on `ROS_PACKAGE_PATH` after cloning the package to your workspace. And the normal procedure for compling a catkin package will work.
|
|
||||||
|
|
||||||
```
|
|
||||||
cd your_work_space
|
|
||||||
colcon build
|
|
||||||
source install/setup.bash
|
|
||||||
ros2 launch lslidar_driver lslidar_launch.py
|
|
||||||
```
|
|
||||||
open new terminal
|
|
||||||
ros2 topic pub -1 /lslidar_order std_msgs/msg/Int8 data:\ 1\ (open radar)
|
|
||||||
ros2 topic pub -1 /lslidar_order std_msgs/msg/Int8 data:\ 0\ (close radar)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ros2 launch lslidar_driver lslidar_launch.py
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that this launch file launches both the driver, which is the only launch file needed to be used.
|
|
||||||
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
|
|
||||||
## Bug Report
|
|
||||||
|
|
||||||
Prefer to open an issue. You can also send an E-mail to honghangli@lslidar.com
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RERTION
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
project(lslidar_driver)
|
|
||||||
|
|
||||||
# Default to C++14
|
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
||||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(libpcap_LIBRARIES -lpcap)
|
|
||||||
|
|
||||||
#set(FastRTPS_INCLUDE_DIR /opt/ros/foxy/include)
|
|
||||||
#set(FastRTPS_LIBRARY_RELEASE /opt/ros/foxy/lib/libfastrtps.so)
|
|
||||||
|
|
||||||
#find_package(Boost REQUIRED COMPONENTS )
|
|
||||||
find_package(Boost REQUIRED thread)
|
|
||||||
find_package(rclcpp REQUIRED)
|
|
||||||
find_package(PCL REQUIRED)
|
|
||||||
find_package(diagnostic_updater REQUIRED)
|
|
||||||
find_package(lslidar_msgs REQUIRED)
|
|
||||||
find_package(std_msgs REQUIRED)
|
|
||||||
find_package(ament_cmake REQUIRED)
|
|
||||||
find_package(pluginlib REQUIRED)
|
|
||||||
find_package(rclpy REQUIRED)
|
|
||||||
find_package(pcl_conversions REQUIRED)
|
|
||||||
find_package(sensor_msgs REQUIRED)
|
|
||||||
#find_package(PCL REQUIRED COMPONENTS common io)
|
|
||||||
|
|
||||||
include_directories(
|
|
||||||
include
|
|
||||||
${PCL_INCLUDE_DIRS}
|
|
||||||
${PCL_COMMON_INCLUDE_DIRS}
|
|
||||||
${Boost_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Node
|
|
||||||
add_executable(lslidar_driver_node src/lslidar_driver_node.cc src/lslidar_driver.cc src/input.cc src/lsiosr.cpp)
|
|
||||||
target_link_libraries(lslidar_driver_node ${rclcpp_LIBRARIES} ${libpcap_LIBRARIES} ${Boost_LIBRARIES} Boost::thread)
|
|
||||||
ament_target_dependencies(lslidar_driver_node rclcpp std_msgs lslidar_msgs sensor_msgs diagnostic_updater pcl_conversions)
|
|
||||||
|
|
||||||
|
|
||||||
install(DIRECTORY launch params rviz
|
|
||||||
DESTINATION share/${PROJECT_NAME})
|
|
||||||
|
|
||||||
install(TARGETS
|
|
||||||
lslidar_driver_node
|
|
||||||
DESTINATION lib/${PROJECT_NAME}
|
|
||||||
)
|
|
||||||
|
|
||||||
ament_export_dependencies(rclcpp pluginlib lslidar_msgs sensor_msgs pcl_conversions)
|
|
||||||
ament_export_include_directories(include ${PCL_COMMON_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
ament_package()
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of lslidar_ch driver.
|
|
||||||
*
|
|
||||||
* The driver is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* The driver is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with the driver. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Input -- base class used to access the data independently of
|
|
||||||
* its source
|
|
||||||
*
|
|
||||||
* InputSocket -- derived class reads live data from the device
|
|
||||||
* via a UDP socket
|
|
||||||
*
|
|
||||||
* InputPCAP -- derived class provides a similar interface from a
|
|
||||||
* PCAP dump
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LSLIDAR_INPUT_H_
|
|
||||||
#define __LSLIDAR_INPUT_H_
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <pcap.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include "rclcpp/rclcpp.hpp"
|
|
||||||
#include <lslidar_msgs/msg/lslidar_packet.hpp>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/file.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sensor_msgs/msg/time_reference.hpp>
|
|
||||||
#include <std_msgs/msg/int8.hpp>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
namespace lslidar_driver
|
|
||||||
{
|
|
||||||
static uint16_t MSOP_DATA_PORT_NUMBER = 2368; // lslidar default data port on PC
|
|
||||||
/**
|
|
||||||
* 从在线的网络数据或离线的网络抓包数据(pcap文件)中提取出lidar的原始数据,即packet数据包
|
|
||||||
* @brief The Input class,
|
|
||||||
*
|
|
||||||
* @param private_nh 一个NodeHandled,用于通过节点传递参数
|
|
||||||
* @param port
|
|
||||||
* @returns 0 if successful,
|
|
||||||
* -1 if end of file
|
|
||||||
* >0 if incomplete packet (is this possible?)
|
|
||||||
*/
|
|
||||||
class Input
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Input(rclcpp::Node* private_nh, uint16_t port);
|
|
||||||
|
|
||||||
virtual ~Input()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &packet) = 0;
|
|
||||||
|
|
||||||
int getRpm(void);
|
|
||||||
int getReturnMode(void);
|
|
||||||
bool getUpdateFlag(void);
|
|
||||||
void clearUpdateFlag(void);
|
|
||||||
void UDP_order(const std_msgs::msg::Int8 msg);
|
|
||||||
void UDP_difop();
|
|
||||||
protected:
|
|
||||||
rclcpp::Node* private_nh_;
|
|
||||||
uint16_t port_;
|
|
||||||
std::string devip_str_;
|
|
||||||
std::string lidar_name;
|
|
||||||
int cur_rpm_;
|
|
||||||
int return_mode_;
|
|
||||||
bool npkt_update_flag_;
|
|
||||||
bool add_multicast;
|
|
||||||
std::string group_ip;
|
|
||||||
int UDP_PORT_NUMBER_DIFOP;
|
|
||||||
int socket_id_difop;
|
|
||||||
int sockfd_;
|
|
||||||
std::string devip_str_difop;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @brief Live lslidar input from socket. */
|
|
||||||
class InputSocket : public Input
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InputSocket(rclcpp::Node* private_nh, uint16_t port = MSOP_DATA_PORT_NUMBER);
|
|
||||||
|
|
||||||
virtual ~InputSocket();
|
|
||||||
|
|
||||||
virtual int getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &packet);
|
|
||||||
|
|
||||||
private:
|
|
||||||
private:
|
|
||||||
|
|
||||||
in_addr devip_;
|
|
||||||
in_addr devip_difop;
|
|
||||||
//struct ip_mreq group;
|
|
||||||
|
|
||||||
};
|
|
||||||
class InputPCAP : public Input
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InputPCAP(rclcpp::Node* private_nh,uint16_t port = MSOP_DATA_PORT_NUMBER, double packet_rate = 0.0,
|
|
||||||
std::string filename="");
|
|
||||||
virtual ~InputPCAP();
|
|
||||||
virtual int getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &pkt);
|
|
||||||
private:
|
|
||||||
|
|
||||||
rclcpp::Rate packet_rate_;
|
|
||||||
std::string filename_;
|
|
||||||
pcap_t *pcap_;
|
|
||||||
bpf_program pcap_packet_filter_;
|
|
||||||
char errbuf_[PCAP_ERRBUF_SIZE];
|
|
||||||
bool empty_;
|
|
||||||
bool read_once_;
|
|
||||||
bool read_fast_;
|
|
||||||
double repeat_delay_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __LSLIDAR_INPUT_H
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
/*******************************************************
|
|
||||||
@company: Copyright (C) 2021, Leishen Intelligent System
|
|
||||||
@product: LSM10_N10
|
|
||||||
@filename: lsiosr.cpp
|
|
||||||
@brief:
|
|
||||||
@version: date: author: comments:
|
|
||||||
@v1.0 22-10-24 li new
|
|
||||||
*******************************************************/
|
|
||||||
#ifndef LSIOSR_H
|
|
||||||
#define LSIOSR_H
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
//波特率
|
|
||||||
#define BAUD_230400 230400
|
|
||||||
#define BAUD_460800 460800
|
|
||||||
#define BAUD_500000 500000
|
|
||||||
#define BAUD_921600 921600
|
|
||||||
|
|
||||||
//奇偶校验位
|
|
||||||
#define PARITY_ODD 'O' //奇数
|
|
||||||
#define PARITY_EVEN 'E' //偶数
|
|
||||||
#define PARITY_NONE 'N' //无奇偶校验位
|
|
||||||
|
|
||||||
//停止位
|
|
||||||
#define STOP_BIT_1 1
|
|
||||||
#define STOP_BIT_2 2
|
|
||||||
|
|
||||||
//数据位
|
|
||||||
#define DATA_BIT_7 7
|
|
||||||
#define DATA_BIT_8 8
|
|
||||||
|
|
||||||
namespace lslidar_driver
|
|
||||||
{
|
|
||||||
class LSIOSR{
|
|
||||||
public:
|
|
||||||
static LSIOSR* instance(std::string name, int speed, int fd = 0);
|
|
||||||
|
|
||||||
~LSIOSR();
|
|
||||||
|
|
||||||
/* 从串口中读取数据 */
|
|
||||||
int read(unsigned char *buffer, int length, int timeout = 30);
|
|
||||||
|
|
||||||
/* 向串口传数据 */
|
|
||||||
int send(const char* buffer, int length, int timeout = 30);
|
|
||||||
|
|
||||||
/* Empty serial port input buffer */
|
|
||||||
void flushinput();
|
|
||||||
|
|
||||||
/* 串口初始化 */
|
|
||||||
int init();
|
|
||||||
|
|
||||||
int close();
|
|
||||||
|
|
||||||
/* 获取串口号 */
|
|
||||||
std::string getPort();
|
|
||||||
|
|
||||||
/* 设置串口号 */
|
|
||||||
int setPortName(std::string name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
LSIOSR(std::string name, int speed, int fd);
|
|
||||||
|
|
||||||
int waitWritable(int millis);
|
|
||||||
int waitReadable(int millis);
|
|
||||||
|
|
||||||
/* 串口配置的函数 */
|
|
||||||
int setOpt(int nBits, uint8_t nEvent, int nStop);
|
|
||||||
|
|
||||||
std::string port_;
|
|
||||||
int baud_rate_;
|
|
||||||
|
|
||||||
int fd_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of lslidar driver.
|
|
||||||
*
|
|
||||||
* The driver is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* The driver is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with the driver. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LSLIDAR_DRIVER_H
|
|
||||||
#define LSLIDAR_DRIVER_H
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include "rclcpp/rclcpp.hpp"
|
|
||||||
#include <thread>
|
|
||||||
#include "diagnostic_updater/diagnostic_updater.hpp"
|
|
||||||
#include "diagnostic_updater/publisher.hpp"
|
|
||||||
#include "lslidar_msgs/msg/lslidar_packet.hpp"
|
|
||||||
#include "std_msgs/msg/byte.hpp"
|
|
||||||
|
|
||||||
#include "sensor_msgs/msg/point_cloud2.hpp"
|
|
||||||
#include "pcl_conversions/pcl_conversions.h"
|
|
||||||
#include "pcl/point_types.h"
|
|
||||||
|
|
||||||
#include "time.h"
|
|
||||||
#include "input.h"
|
|
||||||
#include "lsiosr.h"
|
|
||||||
#include "sensor_msgs/msg/laser_scan.hpp"
|
|
||||||
namespace lslidar_driver {
|
|
||||||
|
|
||||||
struct PointXYZIT {
|
|
||||||
PCL_ADD_POINT4D;
|
|
||||||
uint8_t intensity;
|
|
||||||
double timestamp;
|
|
||||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW // make sure our new allocators are aligned
|
|
||||||
} EIGEN_ALIGN16;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
double degree;
|
|
||||||
double range;
|
|
||||||
double intensity;
|
|
||||||
} ScanPoint;
|
|
||||||
|
|
||||||
class LslidarDriver: public rclcpp::Node {
|
|
||||||
public:
|
|
||||||
LslidarDriver();
|
|
||||||
LslidarDriver(const rclcpp::NodeOptions& options);
|
|
||||||
~LslidarDriver();
|
|
||||||
|
|
||||||
bool initialize();
|
|
||||||
bool polling();
|
|
||||||
|
|
||||||
typedef std::shared_ptr<LslidarDriver> LslidarDriverPtr;
|
|
||||||
typedef std::shared_ptr<const LslidarDriver> LslidarDriverConstPtr;
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint64_t get_gps_stamp(struct tm t);
|
|
||||||
uint8_t N10_CalCRC8(unsigned char * p, int len);
|
|
||||||
bool loadParameters();
|
|
||||||
bool createRosIO();
|
|
||||||
void open_serial();
|
|
||||||
void lidar_difop();
|
|
||||||
void lidar_order(const std_msgs::msg::Int8::SharedPtr msg);
|
|
||||||
void data_processing(unsigned char *packet_bytes,int len);
|
|
||||||
void data_processing_2(unsigned char *packet_bytes,int len);
|
|
||||||
void difop_processing(unsigned char *packet_bytes);
|
|
||||||
void pubScanThread();
|
|
||||||
void recvThread_crc(int &count,int &link_time);
|
|
||||||
int receive_data(unsigned char *packet_bytes);
|
|
||||||
int getScan(std::vector<ScanPoint> &points, rclcpp::Time &scan_time, float &scan_duration);
|
|
||||||
|
|
||||||
boost::thread *pubscan_thread_ ;
|
|
||||||
boost::shared_ptr<Input> msop_input_;
|
|
||||||
boost::mutex mutex_;
|
|
||||||
boost::mutex pubscan_mutex_;
|
|
||||||
boost::condition_variable pubscan_cond_;
|
|
||||||
|
|
||||||
int UDP_PORT_NUMBER;
|
|
||||||
int count_num;
|
|
||||||
int package_points;
|
|
||||||
int data_bits_start;
|
|
||||||
int degree_bits_start;
|
|
||||||
int end_degree_bits_start;
|
|
||||||
int rpm_bits_start;
|
|
||||||
int baud_rate_;
|
|
||||||
int points_size_;
|
|
||||||
int idx = 0;
|
|
||||||
int link_time = 0;
|
|
||||||
|
|
||||||
bool use_gps_ts;
|
|
||||||
bool is_start;
|
|
||||||
bool high_reflection;
|
|
||||||
bool compensation;
|
|
||||||
bool first_compensation = true;
|
|
||||||
bool pubScan;
|
|
||||||
bool pubPointCloud2;
|
|
||||||
|
|
||||||
double min_range;
|
|
||||||
double max_range;
|
|
||||||
double angle_disable_min;
|
|
||||||
double angle_disable_max;
|
|
||||||
double angle_able_min;
|
|
||||||
double angle_able_max;
|
|
||||||
double last_degree = 0.0;
|
|
||||||
double degree_compensation = 0.0;
|
|
||||||
|
|
||||||
uint16_t PACKET_SIZE ;
|
|
||||||
uint64_t sweep_end_time_gps;
|
|
||||||
uint64_t sweep_end_time_hardware;
|
|
||||||
uint64_t sub_second;
|
|
||||||
|
|
||||||
std::string frame_id;
|
|
||||||
std::string interface_selection;
|
|
||||||
std::string scan_topic;
|
|
||||||
std::string lidar_name;
|
|
||||||
std::string serial_port_;
|
|
||||||
std::string dump_file;
|
|
||||||
std::string pointcloud_topic;
|
|
||||||
std::string in_file_name;
|
|
||||||
|
|
||||||
tm pTime;
|
|
||||||
rclcpp::Time pre_time_;
|
|
||||||
rclcpp::Time time_;
|
|
||||||
std::vector<ScanPoint> scan_points_;
|
|
||||||
std::vector<ScanPoint> scan_points_bak_;
|
|
||||||
// Diagnostics updater
|
|
||||||
diagnostic_updater::Updater diagnostics;
|
|
||||||
std::shared_ptr<diagnostic_updater::TopicDiagnostic> diag_topic;
|
|
||||||
double diag_min_freq;
|
|
||||||
double diag_max_freq;
|
|
||||||
rclcpp::Publisher<sensor_msgs::msg::LaserScan>::SharedPtr scan_pub;
|
|
||||||
rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr point_cloud_pub;
|
|
||||||
rclcpp::Subscription<std_msgs::msg::Int8>::SharedPtr difop_switch;
|
|
||||||
LSIOSR * serial_;
|
|
||||||
};
|
|
||||||
typedef PointXYZIT VPoint;
|
|
||||||
typedef pcl::PointCloud<VPoint> VPointCloud;
|
|
||||||
|
|
||||||
} // namespace lslidar_driver
|
|
||||||
POINT_CLOUD_REGISTER_POINT_STRUCT(lslidar_driver::PointXYZIT,
|
|
||||||
(float, x, x)(float, y, y)(float, z, z)(
|
|
||||||
std::uint8_t, intensity,
|
|
||||||
intensity)(double, timestamp, timestamp))
|
|
||||||
#endif // _LSLIDAR_DRIVER_H_
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch_ros.actions import LifecycleNode
|
|
||||||
from launch.substitutions import LaunchConfiguration
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
from launch.actions import DeclareLaunchArgument
|
|
||||||
|
|
||||||
import lifecycle_msgs.msg
|
|
||||||
import os
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
|
|
||||||
driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params','lidar_uart_ros2', 'lsn10p.yaml')
|
|
||||||
|
|
||||||
driver_node = LifecycleNode(package='lslidar_driver',
|
|
||||||
executable='lslidar_driver_node',
|
|
||||||
name='lslidar_driver_node', #设置激光数据topic名称
|
|
||||||
output='screen',
|
|
||||||
emulate_tty=True,
|
|
||||||
namespace='',
|
|
||||||
parameters=[driver_dir],
|
|
||||||
)
|
|
||||||
|
|
||||||
return LaunchDescription([
|
|
||||||
driver_node,
|
|
||||||
])
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch_ros.actions import LifecycleNode
|
|
||||||
from launch.substitutions import LaunchConfiguration
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
from launch.actions import DeclareLaunchArgument
|
|
||||||
|
|
||||||
import lifecycle_msgs.msg
|
|
||||||
import os
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
|
|
||||||
rviz2_config = os.path.join(get_package_share_directory('lslidar_driver'),'rviz','lslidar.rviz')
|
|
||||||
|
|
||||||
rviz2_node = Node(
|
|
||||||
package='rviz2',
|
|
||||||
executable='rviz2',
|
|
||||||
name='rviz2',
|
|
||||||
arguments=['-d',rviz2_config],
|
|
||||||
output='screen')
|
|
||||||
|
|
||||||
return LaunchDescription([
|
|
||||||
rviz2_node,
|
|
||||||
])
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<package format="2">
|
|
||||||
<name>lslidar_driver</name>
|
|
||||||
<version>1.2.0</version>
|
|
||||||
<description>ROS device driver for Leishen lidar.</description>
|
|
||||||
<maintainer email="shaohuashu@lslidar.com">Nick Shu</maintainer>
|
|
||||||
<author>Nick Shu</author>
|
|
||||||
<license>GNU General Public License V3.0</license>
|
|
||||||
|
|
||||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
|
||||||
|
|
||||||
<build_depend>rclcpp</build_depend>
|
|
||||||
<build_depend>std_msgs</build_depend>
|
|
||||||
<build_depend>lslidar_msgs</build_depend>
|
|
||||||
<build_depend>pcl_conversions</build_depend>
|
|
||||||
<build_depend>rclpy</build_depend>
|
|
||||||
<build_depend>libpcap</build_depend>
|
|
||||||
<build_depend>libpcl-all-dev</build_depend>
|
|
||||||
<build_depend>pluginlib</build_depend>
|
|
||||||
<build_depend>sensor_msgs</build_depend>
|
|
||||||
|
|
||||||
<exec_depend>rclcpp</exec_depend>
|
|
||||||
<exec_depend>std_msgs</exec_depend>
|
|
||||||
<exec_depend>lslidar_msgs</exec_depend>
|
|
||||||
<exec_depend>pcl_conversions</exec_depend>
|
|
||||||
<exec_depend>rclpy</exec_depend>
|
|
||||||
<exec_depend>libpcap</exec_depend>
|
|
||||||
<exec_depend>libpcl-all</exec_depend>
|
|
||||||
<exec_depend>pluginlib</exec_depend>
|
|
||||||
<exec_depend>sensor_msgs</exec_depend>
|
|
||||||
|
|
||||||
<depend>diagnostic_updater</depend>
|
|
||||||
<export>
|
|
||||||
<build_type>ament_cmake</build_type>
|
|
||||||
</export>
|
|
||||||
</package>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/lslidar_driver_node:
|
|
||||||
ros__parameters:
|
|
||||||
frame_id: laser_link #激光坐标
|
|
||||||
group_ip: 224.1.1.2
|
|
||||||
add_multicast: false
|
|
||||||
device_ip: 192.168.1.200 #雷达源IP
|
|
||||||
device_ip_difop: 192.168.1.102 #雷达目的ip
|
|
||||||
msop_port: 2368 #雷达目的端口号
|
|
||||||
difop_port: 2369 #雷达源端口号
|
|
||||||
lidar_name: N10_P #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 L10 N10_P
|
|
||||||
angle_disable_min: 0.0 #角度裁剪开始值
|
|
||||||
angle_disable_max: 0.0 #角度裁剪结束值
|
|
||||||
min_range: 0.2 #雷达接收距离最小值
|
|
||||||
max_range: 200.0 #雷达接收距离最大值
|
|
||||||
use_gps_ts: false #雷达是否使用GPS授时
|
|
||||||
scan_topic: /scan #设置激光数据topic名称
|
|
||||||
interface_selection: serial #接口选择:net 为网口,serial 为串口。
|
|
||||||
serial_port_: /dev/agvpro_lidar #串口连接时的串口号
|
|
||||||
high_reflection: false #M10_P雷达需填写该值,若不确定,请联系技术支持。
|
|
||||||
compensation: false #M10系列是否使用角度补偿功能
|
|
||||||
pubScan: true #是否发布scan话题
|
|
||||||
pubPointCloud2: false #是否发布pointcloud2话题
|
|
||||||
pointcloud_topic: /lslidar_point_cloud #设置激光数据topic名称
|
|
||||||
# pcap: /home/ls/1.pcap #雷达是否使用pcap包读取功能
|
|
||||||
# in_file_name: /home/ls/1.txt #雷达是否使用txt文件读取功能
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
Panels:
|
|
||||||
- Class: rviz_common/Displays
|
|
||||||
Help Height: 78
|
|
||||||
Name: Displays
|
|
||||||
Property Tree Widget:
|
|
||||||
Expanded:
|
|
||||||
- /Global Options1
|
|
||||||
- /Status1
|
|
||||||
- /LaserScan1
|
|
||||||
Splitter Ratio: 0.3441176414489746
|
|
||||||
Tree Height: 617
|
|
||||||
- Class: rviz_common/Selection
|
|
||||||
Name: Selection
|
|
||||||
- Class: rviz_common/Tool Properties
|
|
||||||
Expanded:
|
|
||||||
- /2D Goal Pose1
|
|
||||||
- /Publish Point1
|
|
||||||
Name: Tool Properties
|
|
||||||
Splitter Ratio: 0.5886790156364441
|
|
||||||
- Class: rviz_common/Views
|
|
||||||
Expanded:
|
|
||||||
- /Current View1
|
|
||||||
Name: Views
|
|
||||||
Splitter Ratio: 0.5
|
|
||||||
Visualization Manager:
|
|
||||||
Class: ""
|
|
||||||
Displays:
|
|
||||||
- Alpha: 0.5
|
|
||||||
Cell Size: 1
|
|
||||||
Class: rviz_default_plugins/Grid
|
|
||||||
Color: 160; 160; 164
|
|
||||||
Enabled: true
|
|
||||||
Line Style:
|
|
||||||
Line Width: 0.029999999329447746
|
|
||||||
Value: Lines
|
|
||||||
Name: Grid
|
|
||||||
Normal Cell Count: 0
|
|
||||||
Offset:
|
|
||||||
X: 0
|
|
||||||
Y: 0
|
|
||||||
Z: 0
|
|
||||||
Plane: XY
|
|
||||||
Plane Cell Count: 10
|
|
||||||
Reference Frame: <Fixed Frame>
|
|
||||||
Value: true
|
|
||||||
- Alpha: 1
|
|
||||||
Autocompute Intensity Bounds: true
|
|
||||||
Autocompute Value Bounds:
|
|
||||||
Max Value: 10
|
|
||||||
Min Value: -10
|
|
||||||
Value: true
|
|
||||||
Axis: Z
|
|
||||||
Channel Name: intensity
|
|
||||||
Class: rviz_default_plugins/LaserScan
|
|
||||||
Color: 255; 255; 255
|
|
||||||
Color Transformer: Intensity
|
|
||||||
Decay Time: 0
|
|
||||||
Enabled: true
|
|
||||||
Invert Rainbow: false
|
|
||||||
Max Color: 255; 255; 255
|
|
||||||
Max Intensity: 0
|
|
||||||
Min Color: 0; 0; 0
|
|
||||||
Min Intensity: 0
|
|
||||||
Name: LaserScan
|
|
||||||
Position Transformer: XYZ
|
|
||||||
Selectable: true
|
|
||||||
Size (Pixels): 3
|
|
||||||
Size (m): 0.009999999776482582
|
|
||||||
Style: Flat Squares
|
|
||||||
Topic:
|
|
||||||
Depth: 5
|
|
||||||
Durability Policy: Volatile
|
|
||||||
Filter size: 10
|
|
||||||
History Policy: Keep Last
|
|
||||||
Reliability Policy: Reliable
|
|
||||||
Value: scan
|
|
||||||
Use Fixed Frame: true
|
|
||||||
Use rainbow: true
|
|
||||||
Value: true
|
|
||||||
Enabled: true
|
|
||||||
Global Options:
|
|
||||||
Background Color: 48; 48; 48
|
|
||||||
Fixed Frame: laser_link
|
|
||||||
Frame Rate: 30
|
|
||||||
Name: root
|
|
||||||
Tools:
|
|
||||||
- Class: rviz_default_plugins/Interact
|
|
||||||
Hide Inactive Objects: true
|
|
||||||
- Class: rviz_default_plugins/MoveCamera
|
|
||||||
- Class: rviz_default_plugins/Select
|
|
||||||
- Class: rviz_default_plugins/FocusCamera
|
|
||||||
- Class: rviz_default_plugins/Measure
|
|
||||||
Line color: 128; 128; 0
|
|
||||||
- Class: rviz_default_plugins/SetInitialPose
|
|
||||||
Covariance x: 0.25
|
|
||||||
Covariance y: 0.25
|
|
||||||
Covariance yaw: 0.06853891909122467
|
|
||||||
Topic:
|
|
||||||
Depth: 5
|
|
||||||
Durability Policy: Volatile
|
|
||||||
History Policy: Keep Last
|
|
||||||
Reliability Policy: Reliable
|
|
||||||
Value: /initialpose
|
|
||||||
- Class: rviz_default_plugins/SetGoal
|
|
||||||
Topic:
|
|
||||||
Depth: 5
|
|
||||||
Durability Policy: Volatile
|
|
||||||
History Policy: Keep Last
|
|
||||||
Reliability Policy: Reliable
|
|
||||||
Value: /goal_pose
|
|
||||||
- Class: rviz_default_plugins/PublishPoint
|
|
||||||
Single click: true
|
|
||||||
Topic:
|
|
||||||
Depth: 5
|
|
||||||
Durability Policy: Volatile
|
|
||||||
History Policy: Keep Last
|
|
||||||
Reliability Policy: Reliable
|
|
||||||
Value: /clicked_point
|
|
||||||
Transformation:
|
|
||||||
Current:
|
|
||||||
Class: rviz_default_plugins/TF
|
|
||||||
Value: true
|
|
||||||
Views:
|
|
||||||
Current:
|
|
||||||
Class: rviz_default_plugins/Orbit
|
|
||||||
Distance: 3.635173797607422
|
|
||||||
Enable Stereo Rendering:
|
|
||||||
Stereo Eye Separation: 0.05999999865889549
|
|
||||||
Stereo Focal Distance: 1
|
|
||||||
Swap Stereo Eyes: false
|
|
||||||
Value: false
|
|
||||||
Focal Point:
|
|
||||||
X: 0
|
|
||||||
Y: 0
|
|
||||||
Z: 0
|
|
||||||
Focal Shape Fixed Size: true
|
|
||||||
Focal Shape Size: 0.05000000074505806
|
|
||||||
Invert Z Axis: false
|
|
||||||
Name: Current View
|
|
||||||
Near Clip Distance: 0.009999999776482582
|
|
||||||
Pitch: 0.8653978705406189
|
|
||||||
Target Frame: <Fixed Frame>
|
|
||||||
Value: Orbit (rviz)
|
|
||||||
Yaw: 3.095397710800171
|
|
||||||
Saved: ~
|
|
||||||
Window Geometry:
|
|
||||||
Displays:
|
|
||||||
collapsed: false
|
|
||||||
Height: 846
|
|
||||||
Hide Left Dock: false
|
|
||||||
Hide Right Dock: false
|
|
||||||
QMainWindow State: 000000ff00000000fd000000040000000000000156000002f4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002f4000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002f4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002f4000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d0065010000000000000450000000000000000000000292000002f400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
|
|
||||||
Selection:
|
|
||||||
collapsed: false
|
|
||||||
Tool Properties:
|
|
||||||
collapsed: false
|
|
||||||
Views:
|
|
||||||
collapsed: false
|
|
||||||
Width: 1283
|
|
||||||
X: 406
|
|
||||||
Y: 152
|
|
||||||
@@ -1,398 +0,0 @@
|
|||||||
#include "lslidar_driver/input.h"
|
|
||||||
|
|
||||||
extern volatile sig_atomic_t flag;
|
|
||||||
namespace lslidar_driver
|
|
||||||
{
|
|
||||||
static const size_t packet_size_input = 400;
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
// Input base class implementation
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/** @brief constructor
|
|
||||||
*
|
|
||||||
* @param private_nh ROS private handle for calling node.
|
|
||||||
* @param port UDP port number.
|
|
||||||
*/
|
|
||||||
Input::Input(rclcpp::Node *private_nh, uint16_t port) : private_nh_(private_nh), port_(port) {
|
|
||||||
npkt_update_flag_ = false;
|
|
||||||
cur_rpm_ = 0;
|
|
||||||
return_mode_ = 1;
|
|
||||||
devip_str_difop = std::string("192.168.1.200");
|
|
||||||
devip_str_ = std::string("192.168.1.102");
|
|
||||||
lidar_name = std::string("M10");
|
|
||||||
add_multicast = false;
|
|
||||||
group_ip = std::string("224.1.1.2");
|
|
||||||
UDP_PORT_NUMBER_DIFOP = 2369;
|
|
||||||
|
|
||||||
|
|
||||||
private_nh->declare_parameter<std::string>("device_ip","192.168.1.102");
|
|
||||||
private_nh->declare_parameter<std::string>("device_ip_difop","192.168.1.200");
|
|
||||||
private_nh->declare_parameter<bool>("add_multicast",false);
|
|
||||||
private_nh->declare_parameter<std::string>("group_ip","224.1.1.2");
|
|
||||||
private_nh->declare_parameter<int>("difop_port",2369);
|
|
||||||
|
|
||||||
|
|
||||||
private_nh->get_parameter("lidar_name", lidar_name);
|
|
||||||
private_nh->get_parameter("device_ip", devip_str_);
|
|
||||||
private_nh->get_parameter("add_multicast", add_multicast);
|
|
||||||
private_nh->get_parameter("group_ip", group_ip);
|
|
||||||
private_nh->get_parameter("difop_port", UDP_PORT_NUMBER_DIFOP);
|
|
||||||
private_nh->get_parameter("device_ip_difop", devip_str_difop);
|
|
||||||
|
|
||||||
if (!devip_str_.empty())
|
|
||||||
RCLCPP_INFO(private_nh->get_logger(), "[driver][input] accepting packets from IP address: %s port: %d",
|
|
||||||
devip_str_.c_str(),port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief constructor
|
|
||||||
*
|
|
||||||
* @param private_nh ROS private handle for calling node.
|
|
||||||
* @param port UDP port number
|
|
||||||
*/
|
|
||||||
InputSocket::InputSocket(rclcpp::Node *private_nh, uint16_t port) : Input(private_nh, port) {
|
|
||||||
sockfd_ = -1;
|
|
||||||
|
|
||||||
if (!devip_str_.empty()) {
|
|
||||||
inet_aton(devip_str_.c_str(), &devip_);
|
|
||||||
inet_aton(devip_str_difop.c_str(), &devip_difop);
|
|
||||||
}
|
|
||||||
|
|
||||||
RCLCPP_INFO(private_nh_->get_logger(), "[driver][socket] Opening UDP socket: port %d", port);
|
|
||||||
sockfd_ = socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
if (sockfd_ == -1) {
|
|
||||||
perror("socket"); // TODO: ROS_ERROR errno
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int opt = 1;
|
|
||||||
if (setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (const void *) &opt, sizeof(opt))) {
|
|
||||||
perror("setsockopt error!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockaddr_in my_addr; // my address information
|
|
||||||
memset(&my_addr, 0, sizeof(my_addr)); // initialize to zeros
|
|
||||||
my_addr.sin_family = AF_INET; // host byte order
|
|
||||||
my_addr.sin_port = htons(port); // port in network byte order
|
|
||||||
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill in my IP
|
|
||||||
|
|
||||||
if (bind(sockfd_, (sockaddr * ) & my_addr, sizeof(sockaddr)) == -1) {
|
|
||||||
perror("bind"); // TODO: ROS_ERROR errno
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add_multicast) {
|
|
||||||
struct ip_mreq group;
|
|
||||||
group.imr_multiaddr.s_addr = inet_addr(group_ip.c_str());
|
|
||||||
group.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
||||||
|
|
||||||
if (setsockopt(sockfd_, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &group, sizeof(group)) < 0) {
|
|
||||||
perror("Adding multicast group error ");
|
|
||||||
close(sockfd_);
|
|
||||||
exit(1);
|
|
||||||
} else
|
|
||||||
printf("Adding multicast group...OK.\n");
|
|
||||||
}
|
|
||||||
if (fcntl(sockfd_, F_SETFL, O_NONBLOCK | FASYNC) < 0) {
|
|
||||||
perror("non-block");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief destructor */
|
|
||||||
InputSocket::~InputSocket(void) {
|
|
||||||
(void) close(sockfd_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Input::UDP_difop()
|
|
||||||
{
|
|
||||||
sockaddr_in server_sai;
|
|
||||||
server_sai.sin_family = AF_INET; // IPV4 协议族
|
|
||||||
server_sai.sin_port = htons(UDP_PORT_NUMBER_DIFOP);
|
|
||||||
server_sai.sin_addr.s_addr = inet_addr(devip_str_.c_str());
|
|
||||||
for (int k = 0; k < 10; k++)
|
|
||||||
{
|
|
||||||
unsigned char data[188]= {0x00};
|
|
||||||
data[0] = 0xA5;
|
|
||||||
data[1] = 0x5A;
|
|
||||||
data[2] = 0x55;
|
|
||||||
data[184] = 0x08;
|
|
||||||
data[185] = 0x01;
|
|
||||||
data[186] = 0xFA;
|
|
||||||
data[187] = 0xFB;
|
|
||||||
int rtn = sendto(sockfd_, data, 188, 0, (struct sockaddr *)&server_sai, sizeof(struct sockaddr));
|
|
||||||
if (rtn < 0) printf("start scan error !\n");
|
|
||||||
else return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Input::UDP_order(const std_msgs::msg::Int8 msg)
|
|
||||||
{
|
|
||||||
int i = msg.data;
|
|
||||||
sockaddr_in server_sai;
|
|
||||||
server_sai.sin_family = AF_INET; // IPV4 协议族
|
|
||||||
server_sai.sin_port = htons(UDP_PORT_NUMBER_DIFOP);
|
|
||||||
server_sai.sin_addr.s_addr = inet_addr(devip_str_.c_str());
|
|
||||||
int rtn = 0;
|
|
||||||
for (int k = 0; k < 10; k++)
|
|
||||||
{
|
|
||||||
unsigned char data[188]= {0x00};
|
|
||||||
data[0] = 0xA5;
|
|
||||||
data[1] = 0x5A;
|
|
||||||
data[2] = 0x55;
|
|
||||||
data[186] = 0xFA;
|
|
||||||
data[187] = 0xFB;
|
|
||||||
if(lidar_name == "M10" || lidar_name == "M10_GPS" || lidar_name == "M10_P"){
|
|
||||||
if (i <= 1){ //雷达启停
|
|
||||||
data[184] = 0x01;
|
|
||||||
data[185] = char(i);
|
|
||||||
}
|
|
||||||
else if (i == 2){ //雷达点云不滤波
|
|
||||||
data[181] = 0x0A;
|
|
||||||
data[184] = 0x06;
|
|
||||||
data[185] = 0x01;
|
|
||||||
}
|
|
||||||
else if (i == 3){ //雷达点云正常滤波
|
|
||||||
data[181] = 0x0B;
|
|
||||||
data[184] = 0x06;
|
|
||||||
data[185] = 0x01;
|
|
||||||
}
|
|
||||||
else if (i == 4){ //雷达近距离滤波
|
|
||||||
data[181] = 0x0C;
|
|
||||||
data[184] = 0x06;
|
|
||||||
data[185] = 0x01;
|
|
||||||
}
|
|
||||||
else if (i == 100){ //接收设备包
|
|
||||||
data[184] = 0x08;
|
|
||||||
data[185] = 0x01;
|
|
||||||
}
|
|
||||||
else return;
|
|
||||||
}
|
|
||||||
else if (lidar_name == "M10_PLUS"){
|
|
||||||
data[184] = 0x0A;
|
|
||||||
data[185] = 0x01;
|
|
||||||
if(i == 5) {
|
|
||||||
data[141] = 0x01;
|
|
||||||
data[142] = 0x2c;
|
|
||||||
}
|
|
||||||
else if(i == 6) {
|
|
||||||
data[141] = 0x01;
|
|
||||||
data[142] = 0x68;
|
|
||||||
}
|
|
||||||
else if(i == 8) {
|
|
||||||
data[141] = 0x01;
|
|
||||||
data[142] = 0xe0;
|
|
||||||
}
|
|
||||||
else if(i == 10) {
|
|
||||||
data[141] = 0x02;
|
|
||||||
data[142] = 0x58;
|
|
||||||
}
|
|
||||||
else if(i == 12) {
|
|
||||||
data[141] = 0x02;
|
|
||||||
data[142] = 0xd0;
|
|
||||||
}
|
|
||||||
else if(i == 15) {
|
|
||||||
data[141] = 0x03;
|
|
||||||
data[142] = 0x84;
|
|
||||||
}
|
|
||||||
else if(i == 20) {
|
|
||||||
data[141] = 0x04;
|
|
||||||
data[142] = 0xb0;
|
|
||||||
}
|
|
||||||
else if(i <= 1) {
|
|
||||||
data[184] = 0x01;
|
|
||||||
data[185] = char(i);
|
|
||||||
}
|
|
||||||
else if(i == 100) { //接收设备包
|
|
||||||
data[184] = 0x08;
|
|
||||||
data[185] = 0x01;
|
|
||||||
}
|
|
||||||
else return;
|
|
||||||
}
|
|
||||||
else if(lidar_name == "N10"){
|
|
||||||
if(i <= 1){
|
|
||||||
data[185] = char(i);
|
|
||||||
data[184] = 0x01;
|
|
||||||
}
|
|
||||||
else if(i>=6 && i<=12){
|
|
||||||
data[172] = char(i);
|
|
||||||
data[184] = 0x0a;
|
|
||||||
data[185] = 0X01;
|
|
||||||
}
|
|
||||||
else return;
|
|
||||||
}
|
|
||||||
rtn = sendto(sockfd_, data, 188, 0, (struct sockaddr *)&server_sai, sizeof(struct sockaddr));
|
|
||||||
if (rtn < 0)
|
|
||||||
{
|
|
||||||
printf("start scan error !\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (i == 1)
|
|
||||||
usleep(3000000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int InputSocket::getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &packet)
|
|
||||||
{
|
|
||||||
int q = 0;
|
|
||||||
struct pollfd fds[1];
|
|
||||||
fds[0].fd = sockfd_;
|
|
||||||
fds[0].events = POLLIN;
|
|
||||||
static const int POLL_TIMEOUT = 2000; // one second (in msec)
|
|
||||||
|
|
||||||
sockaddr_in sender_address{};
|
|
||||||
socklen_t sender_address_len = sizeof(sender_address);
|
|
||||||
while (flag == 1)
|
|
||||||
{
|
|
||||||
// poll() until input available
|
|
||||||
do {
|
|
||||||
int retval = poll(fds, 1, POLL_TIMEOUT);
|
|
||||||
if (retval < 0) // poll() error?
|
|
||||||
{
|
|
||||||
if (errno != EINTR)
|
|
||||||
RCLCPP_ERROR(private_nh_->get_logger(), "[driver][socket] poll() error: %s", strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (retval == 0) // poll() timeout?
|
|
||||||
{
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(), "lslidar poll() timeout, port: %d",port_);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((fds[0].revents & POLLERR) || (fds[0].revents & POLLHUP) || (fds[0].revents & POLLNVAL)) // device error?
|
|
||||||
{
|
|
||||||
RCLCPP_ERROR(private_nh_->get_logger(),"poll() reports lslidar error");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} while ((fds[0].revents & POLLIN) == 0);
|
|
||||||
|
|
||||||
// Receive packets that should now be available from the
|
|
||||||
// socket using a blocking read.
|
|
||||||
ssize_t nbytes = recvfrom(sockfd_, &packet->data[0], packet_size_input, 0,
|
|
||||||
(sockaddr *)&sender_address, &sender_address_len);
|
|
||||||
// ROS_DEBUG_STREAM("incomplete lslidar packet read: "
|
|
||||||
// << nbytes << " bytes");
|
|
||||||
q = (int)nbytes;
|
|
||||||
if (nbytes < 0)
|
|
||||||
{
|
|
||||||
if (errno != EWOULDBLOCK)
|
|
||||||
{
|
|
||||||
perror("recvfail");
|
|
||||||
RCLCPP_ERROR(private_nh_->get_logger(),"recvfail");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((size_t)nbytes <= packet_size_input || (size_t)nbytes >= 50)
|
|
||||||
{
|
|
||||||
|
|
||||||
// read successful,
|
|
||||||
// if packet is not from the lidar scanner we selected by IP,
|
|
||||||
// continue otherwise we are done
|
|
||||||
if (devip_str_ != "" && sender_address.sin_addr.s_addr != devip_.s_addr)
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
break; // done
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (flag == 0)
|
|
||||||
{
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
InputPCAP::InputPCAP(rclcpp::Node *private_nh, uint16_t port, double packet_rate, std::string filename) : Input(private_nh, port),
|
|
||||||
packet_rate_(packet_rate),
|
|
||||||
filename_(filename)
|
|
||||||
{
|
|
||||||
pcap_ = NULL;
|
|
||||||
empty_ = true;
|
|
||||||
read_once_ = false;
|
|
||||||
read_fast_ = false;
|
|
||||||
repeat_delay_ = 0.0;
|
|
||||||
private_nh->get_parameter("read_once", read_once_);
|
|
||||||
private_nh->get_parameter("read_fast", read_fast_);
|
|
||||||
private_nh->get_parameter("repeat_delay", repeat_delay_);
|
|
||||||
|
|
||||||
if (read_once_)
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"Read input file only once.");
|
|
||||||
if (read_fast_)
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"Read input file as quickly as possible.");
|
|
||||||
if (repeat_delay_ > 0.0)
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"Delay %.3f seconds before repeating input file.", repeat_delay_);
|
|
||||||
|
|
||||||
RCLCPP_INFO(private_nh_->get_logger(),"Opening PCAP file %s",filename_.c_str());
|
|
||||||
if ((pcap_ = pcap_open_offline(filename_.c_str(), errbuf_)) == NULL)
|
|
||||||
{
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"Error opening lslidar socket dump file.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::stringstream filter;
|
|
||||||
if (devip_str_ != "")
|
|
||||||
{
|
|
||||||
filter << "src host " << devip_str_ << "&&";
|
|
||||||
}
|
|
||||||
filter << "udp dst port " << port;
|
|
||||||
pcap_compile(pcap_, &pcap_packet_filter_, filter.str().c_str(), 1, PCAP_NETMASK_UNKNOWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputPCAP::~InputPCAP(void)
|
|
||||||
{
|
|
||||||
pcap_close(pcap_);
|
|
||||||
}
|
|
||||||
|
|
||||||
int InputPCAP::getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &pkt)
|
|
||||||
{
|
|
||||||
struct pcap_pkthdr *header;
|
|
||||||
const u_char *pkt_data;
|
|
||||||
while (flag == 1)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
if ((res = pcap_next_ex(pcap_, &header, &pkt_data)) >= 0)
|
|
||||||
{
|
|
||||||
// skip packets not for the correct port and from the selected IP address
|
|
||||||
if (!devip_str_.empty() && (0 == pcap_offline_filter(&pcap_packet_filter_, header, pkt_data)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (read_fast_ == false)
|
|
||||||
packet_rate_.sleep();
|
|
||||||
mempcpy(&pkt->data[0], pkt_data + 42, packet_size_input);
|
|
||||||
empty_ = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (empty_)
|
|
||||||
{
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"Error %d reading lslidar packet: %s", res, pcap_geterr(pcap_));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (read_once_)
|
|
||||||
{
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"end of file reached -- done reading.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (repeat_delay_ > 0.0)
|
|
||||||
{
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"end of file reached -- delaying %.3f seconds.", repeat_delay_);
|
|
||||||
usleep(rint(repeat_delay_ * 1000000.0));
|
|
||||||
}
|
|
||||||
RCLCPP_WARN(private_nh_->get_logger(),"replayding lsliar dump file");
|
|
||||||
|
|
||||||
pcap_close(pcap_);
|
|
||||||
pcap_ = pcap_open_offline(filename_.c_str(), errbuf_);
|
|
||||||
empty_ = true;
|
|
||||||
}
|
|
||||||
if (flag == 0)
|
|
||||||
{
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
@@ -1,400 +0,0 @@
|
|||||||
/*******************************************************
|
|
||||||
@company: Copyright (C) 2022, Leishen Intelligent System
|
|
||||||
@product: LSM10 and N10
|
|
||||||
@filename: lsiosr.cpp
|
|
||||||
@brief:
|
|
||||||
@version: date: author: comments:
|
|
||||||
@v1.0 21-2-4 yao new
|
|
||||||
*******************************************************/
|
|
||||||
#include "lslidar_driver/lsiosr.h"
|
|
||||||
|
|
||||||
namespace lslidar_driver {
|
|
||||||
|
|
||||||
LSIOSR * LSIOSR::instance(std::string name, int speed, int fd)
|
|
||||||
{
|
|
||||||
static LSIOSR obj(name, speed, fd);
|
|
||||||
return &obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
LSIOSR::LSIOSR(std::string port, int baud_rate, int fd):port_(port), baud_rate_(baud_rate), fd_(fd)
|
|
||||||
{
|
|
||||||
printf("port = %s, baud_rate = %d\n", port.c_str(), baud_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
LSIOSR::~LSIOSR()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
/* 串口配置的函数 */
|
|
||||||
int LSIOSR::setOpt(int nBits, uint8_t nEvent, int nStop)
|
|
||||||
{
|
|
||||||
struct termios newtio, oldtio;
|
|
||||||
/*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/
|
|
||||||
if (tcgetattr(fd_, &oldtio) != 0)
|
|
||||||
{
|
|
||||||
perror("SetupSerial 1");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
bzero(&newtio, sizeof(newtio));
|
|
||||||
/*步骤一,设置字符大小*/
|
|
||||||
newtio.c_cflag |= CLOCAL; //如果设置,modem 的控制线将会被忽略。如果没有设置,则 open()函数会阻塞直到载波检测线宣告 modem 处于摘机状态为止。
|
|
||||||
newtio.c_cflag |= CREAD; //使端口能读取输入的数据
|
|
||||||
/*设置每个数据的位数*/
|
|
||||||
switch (nBits)
|
|
||||||
{
|
|
||||||
case 7:
|
|
||||||
newtio.c_cflag |= CS7;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
newtio.c_cflag |= CS8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*设置奇偶校验位*/
|
|
||||||
switch (nEvent)
|
|
||||||
{
|
|
||||||
case 'O': //奇数
|
|
||||||
newtio.c_iflag |= (INPCK | ISTRIP);
|
|
||||||
newtio.c_cflag |= PARENB; //使能校验,如果不设PARODD则是偶校验
|
|
||||||
newtio.c_cflag |= PARODD; //奇校验
|
|
||||||
break;
|
|
||||||
case 'E': //偶数
|
|
||||||
newtio.c_iflag |= (INPCK | ISTRIP);
|
|
||||||
newtio.c_cflag |= PARENB;
|
|
||||||
newtio.c_cflag &= ~PARODD;
|
|
||||||
break;
|
|
||||||
case 'N': //无奇偶校验位
|
|
||||||
newtio.c_cflag &= ~PARENB;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*设置波特率*/
|
|
||||||
switch (baud_rate_)
|
|
||||||
{
|
|
||||||
case 230400:
|
|
||||||
cfsetispeed(&newtio, B230400);
|
|
||||||
cfsetospeed(&newtio, B230400);
|
|
||||||
break;
|
|
||||||
case 460800:
|
|
||||||
cfsetispeed(&newtio, B460800);
|
|
||||||
cfsetospeed(&newtio, B460800);
|
|
||||||
break;
|
|
||||||
case 500000:
|
|
||||||
cfsetispeed(&newtio, B500000);
|
|
||||||
cfsetospeed(&newtio, B500000);
|
|
||||||
break;
|
|
||||||
case 921600:
|
|
||||||
cfsetispeed(&newtio, B921600);
|
|
||||||
cfsetospeed(&newtio, B921600);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cfsetispeed(&newtio, B460800);
|
|
||||||
cfsetospeed(&newtio, B460800);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 设置停止位
|
|
||||||
* 设置停止位的位数, 如果设置,则会在每帧后产生两个停止位, 如果没有设置,则产生一个
|
|
||||||
* 停止位。一般都是使用一位停止位。需要两位停止位的设备已过时了。
|
|
||||||
* */
|
|
||||||
if (nStop == 1)
|
|
||||||
newtio.c_cflag &= ~CSTOPB;
|
|
||||||
else if (nStop == 2)
|
|
||||||
newtio.c_cflag |= CSTOPB;
|
|
||||||
/*设置等待时间和最小接收字符*/
|
|
||||||
newtio.c_cc[VTIME] = 0;
|
|
||||||
newtio.c_cc[VMIN] = 0;
|
|
||||||
/*处理未接收字符*/
|
|
||||||
tcflush(fd_, TCIFLUSH);
|
|
||||||
/*激活新配置*/
|
|
||||||
if ((tcsetattr(fd_, TCSANOW, &newtio)) != 0)
|
|
||||||
{
|
|
||||||
perror("serial set error");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LSIOSR::flushinput() {
|
|
||||||
tcflush(fd_, TCIFLUSH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 从串口中读取数据 */
|
|
||||||
int LSIOSR::read(unsigned char *buffer, int length, int timeout)
|
|
||||||
{
|
|
||||||
memset(buffer, 0, length);
|
|
||||||
|
|
||||||
int totalBytesRead = 0;
|
|
||||||
int rc;
|
|
||||||
int unlink = 0;
|
|
||||||
unsigned char* pb = buffer;
|
|
||||||
|
|
||||||
if (timeout > 0)
|
|
||||||
{
|
|
||||||
rc = waitReadable(timeout);
|
|
||||||
if (rc <= 0)
|
|
||||||
{
|
|
||||||
return (rc == 0) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int retry = 3;
|
|
||||||
while (length > 0)
|
|
||||||
{
|
|
||||||
rc = ::read(fd_, pb, (size_t)length);
|
|
||||||
|
|
||||||
if (rc > 0)
|
|
||||||
{
|
|
||||||
length -= rc;
|
|
||||||
pb += rc;
|
|
||||||
totalBytesRead += rc;
|
|
||||||
|
|
||||||
if (length == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (rc < 0)
|
|
||||||
{
|
|
||||||
printf("error \n");
|
|
||||||
retry--;
|
|
||||||
if (retry <= 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unlink++;
|
|
||||||
rc = waitReadable(20);
|
|
||||||
if(unlink > 10)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (rc <= 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = ::read(fd_, pb, (size_t)length);
|
|
||||||
|
|
||||||
if (rc > 0)
|
|
||||||
{
|
|
||||||
totalBytesRead += rc;
|
|
||||||
}
|
|
||||||
else if ((rc < 0) && (errno != EINTR) && (errno != EAGAIN))
|
|
||||||
{
|
|
||||||
printf("read error\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalBytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LSIOSR::waitReadable(int millis)
|
|
||||||
{
|
|
||||||
if (fd_ < 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int serial = fd_;
|
|
||||||
|
|
||||||
fd_set fdset;
|
|
||||||
struct timeval tv;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
while (millis > 0)
|
|
||||||
{
|
|
||||||
if (millis < 5000)
|
|
||||||
{
|
|
||||||
tv.tv_usec = millis % 1000 * 1000;
|
|
||||||
tv.tv_sec = millis / 1000;
|
|
||||||
|
|
||||||
millis = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
tv.tv_sec = 5;
|
|
||||||
|
|
||||||
millis -= 5000;
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&fdset);
|
|
||||||
FD_SET(serial, &fdset);
|
|
||||||
|
|
||||||
rc = select(serial + 1, &fdset, NULL, NULL, &tv);
|
|
||||||
if (rc > 0)
|
|
||||||
{
|
|
||||||
rc = (FD_ISSET(serial, &fdset)) ? 1 : -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (rc < 0)
|
|
||||||
{
|
|
||||||
rc = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int LSIOSR::waitWritable(int millis)
|
|
||||||
{
|
|
||||||
if (fd_ < 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int serial = fd_;
|
|
||||||
|
|
||||||
fd_set fdset;
|
|
||||||
struct timeval tv;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
while (millis > 0)
|
|
||||||
{
|
|
||||||
if (millis < 5000)
|
|
||||||
{
|
|
||||||
tv.tv_usec = millis % 1000 * 1000;
|
|
||||||
tv.tv_sec = millis / 1000;
|
|
||||||
|
|
||||||
millis = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
tv.tv_sec = 5;
|
|
||||||
|
|
||||||
millis -= 5000;
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&fdset);
|
|
||||||
FD_SET(serial, &fdset);
|
|
||||||
|
|
||||||
rc = select(serial + 1, NULL, &fdset, NULL, &tv);
|
|
||||||
if (rc > 0)
|
|
||||||
{
|
|
||||||
rc = (FD_ISSET(serial, &fdset)) ? 1 : -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (rc < 0)
|
|
||||||
{
|
|
||||||
rc = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 向串口中发送数据 */
|
|
||||||
int LSIOSR::send(const char* buffer, int length, int timeout)
|
|
||||||
{
|
|
||||||
if (fd_ < 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((buffer == 0) || (length <= 0))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalBytesWrite = 0;
|
|
||||||
int rc;
|
|
||||||
char* pb = (char*)buffer;
|
|
||||||
|
|
||||||
|
|
||||||
if (timeout > 0)
|
|
||||||
{
|
|
||||||
rc = waitWritable(timeout);
|
|
||||||
if (rc <= 0)
|
|
||||||
{
|
|
||||||
return (rc == 0) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int retry = 3;
|
|
||||||
while (length > 0)
|
|
||||||
{
|
|
||||||
rc = write(fd_, pb, (size_t)length);
|
|
||||||
if (rc > 0)
|
|
||||||
{
|
|
||||||
length -= rc;
|
|
||||||
pb += rc;
|
|
||||||
totalBytesWrite += rc;
|
|
||||||
|
|
||||||
if (length == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
retry--;
|
|
||||||
if (retry <= 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = waitWritable(50);
|
|
||||||
if (rc <= 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = write(fd_, pb, (size_t)length);
|
|
||||||
if (rc > 0)
|
|
||||||
{
|
|
||||||
totalBytesWrite += rc;
|
|
||||||
}
|
|
||||||
else if ((rc < 0) && (errno != EINTR) && (errno != EAGAIN))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return totalBytesWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LSIOSR::init()
|
|
||||||
{
|
|
||||||
int error_code = 0;
|
|
||||||
|
|
||||||
fd_ = open(port_.c_str(), O_RDWR|O_NOCTTY|O_NDELAY);
|
|
||||||
if (0 < fd_)
|
|
||||||
{
|
|
||||||
error_code = 0;
|
|
||||||
setOpt(DATA_BIT_8, PARITY_NONE, STOP_BIT_1);//设置串口参数
|
|
||||||
//printf("open_port %s OK !\n", port_.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error_code = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LSIOSR::close()
|
|
||||||
{
|
|
||||||
::close(fd_);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LSIOSR::getPort()
|
|
||||||
{
|
|
||||||
return port_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LSIOSR::setPortName(std::string name)
|
|
||||||
{
|
|
||||||
port_ = name;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of lslidar driver.
|
|
||||||
*
|
|
||||||
* The driver is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* The driver is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with the driver. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "rclcpp/rclcpp.hpp"
|
|
||||||
#include "lslidar_driver/lslidar_driver.h"
|
|
||||||
|
|
||||||
using namespace lslidar_driver;
|
|
||||||
volatile sig_atomic_t flag = 1;
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
rclcpp::init(argc, argv);
|
|
||||||
auto node = std::make_shared<lslidar_driver::LslidarDriver>();
|
|
||||||
|
|
||||||
while (rclcpp::ok() && node->polling()) {
|
|
||||||
rclcpp::spin_some(node);
|
|
||||||
}
|
|
||||||
//rclcpp::spin(node);
|
|
||||||
rclcpp::shutdown();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
|
||||||
project(lslidar_msgs)
|
|
||||||
|
|
||||||
# Default to C99
|
|
||||||
if(NOT CMAKE_C_STANDARD)
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Default to C++14
|
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
||||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# find dependencies
|
|
||||||
find_package(ament_cmake REQUIRED)
|
|
||||||
find_package(std_msgs REQUIRED)
|
|
||||||
find_package(sensor_msgs REQUIRED)
|
|
||||||
find_package(builtin_interfaces REQUIRED)
|
|
||||||
find_package(rosidl_default_generators REQUIRED)
|
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
find_package(ament_lint_auto REQUIRED)
|
|
||||||
ament_lint_auto_find_test_dependencies()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
rosidl_generate_interfaces(lslidar_msgs
|
|
||||||
"msg/LslidarDifop.msg"
|
|
||||||
"msg/LslidarPacket.msg"
|
|
||||||
"msg/LslidarPoint.msg"
|
|
||||||
"msg/LslidarScan.msg"
|
|
||||||
"msg/LslidarSweep.msg"
|
|
||||||
DEPENDENCIES builtin_interfaces std_msgs
|
|
||||||
)
|
|
||||||
|
|
||||||
ament_package()
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
int64 temperature
|
|
||||||
int64 rpm
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# Raw Leishen LIDAR packet.
|
|
||||||
|
|
||||||
builtin_interfaces/Time stamp # packet timestamp
|
|
||||||
uint8[2000] data # packet contents
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Time when the point is captured
|
|
||||||
float32 time
|
|
||||||
|
|
||||||
# Converted distance in the sensor frame
|
|
||||||
float64 x
|
|
||||||
float64 y
|
|
||||||
float64 z
|
|
||||||
|
|
||||||
# Raw measurement from Leishen M10
|
|
||||||
float64 azimuth
|
|
||||||
float64 distance
|
|
||||||
float64 intensity
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Altitude of all the points within this scan
|
|
||||||
float64 altitude
|
|
||||||
|
|
||||||
# The valid points in this scan sorted by azimuth
|
|
||||||
# from 0 to 359.99
|
|
||||||
LslidarPoint[] points
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
std_msgs/Header header
|
|
||||||
|
|
||||||
# The 0th scan is at the bottom
|
|
||||||
LslidarScan[16] scans
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
版本变更
|
|
||||||
/***************************************************************
|
|
||||||
初始版本: LSLIDAR_M10_N10_V2.5.0_221104_ROS2
|
|
||||||
变更内容:
|
|
||||||
1.实现M10/M10_P/M10_PLUS/N10/M10_GPS网口和串口传输数据生成点云功能
|
|
||||||
2.实现点云角度裁剪和距离过滤功能
|
|
||||||
3.可以通过lslidar_order话题控制雷达启停
|
|
||||||
4.支持读取pcap包
|
|
||||||
|
|
||||||
更改日期: 2022-11-04
|
|
||||||
***************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
初始版本: LSLIDAR_M10_N10_V2.5.0_221104_ROS2
|
|
||||||
变更版本:LSLIDAR_M10_N10_V2.5.1_221130_ROS2
|
|
||||||
变更内容:
|
|
||||||
1.新增L10雷达。
|
|
||||||
2.针对M10_P雷达出现的点云问题进行紧急修复。
|
|
||||||
3.针对M10和M10_GPS雷达在最近出货雷达出现的点云问题进行紧急修复。
|
|
||||||
4.修复循环索取新内存导致机器卡死bug。
|
|
||||||
5.更新M10_P和M10_PLUS雷达协议。
|
|
||||||
6.修复角度值分配错误问题。
|
|
||||||
|
|
||||||
更改日期: 2022-11-30
|
|
||||||
***************************************************************/
|
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
初始版本: LSLIDAR_M10_N10_V2.5.1_221130_ROS2
|
|
||||||
变更版本:LSLIDAR_M10_N10_V2.5.2_230110_ROS2
|
|
||||||
变更内容:
|
|
||||||
1.修复驱动串口读取时包头检测漏洞。
|
|
||||||
2.更新M10系列的角度补偿方法。
|
|
||||||
3.修复发现的点角度不连续bug。
|
|
||||||
4.添加可选择是否发布pointcloud2话题。
|
|
||||||
5.添加可选择是否发布scan话题。
|
|
||||||
6.兼容ROS2的humble版本
|
|
||||||
7.兼容双回波雷达
|
|
||||||
8.添加txt文件读取方法
|
|
||||||
更改日期: 2023-01-10
|
|
||||||
***************************************************************/
|
|
||||||
|
Before Width: | Height: | Size: 6.5 KiB |
@@ -1,6 +1,10 @@
|
|||||||
# AGV_Pro
|
# AGV_Pro
|
||||||
ROS2 packages for AGV_Pro
|
ROS2 packages for AGV_Pro
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
> Software environment for Jetson Orin Nano
|
> Software environment for Jetson Orin Nano
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -41,7 +45,7 @@ source ~/agv_pro_ros2/install/local_setup.bash
|
|||||||
# Update to new version
|
# Update to new version
|
||||||
|
|
||||||
```
|
```
|
||||||
cd ~/myagv_ros2/src
|
cd ~/agv_pro_ros2/src
|
||||||
|
|
||||||
git pull
|
git pull
|
||||||
|
|
||||||
@@ -49,4 +53,6 @@ cd ..
|
|||||||
|
|
||||||
colcon build
|
colcon build
|
||||||
```
|
```
|
||||||
|
# User manual
|
||||||
|
|
||||||
|
[myagvPro_docs](https://github.com/elephantrobotics/myagvPro_docs/tree/main/MYAGV_PRO_EN/6-SDKDevelopment/6.2-ApplicationBaseROS2)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# TODO
|
||||||
|
|
||||||
|
Need to patch src/upstream/slam_gmapping/include/slam_gmapping/slam_gmapping.h
|
||||||
|
|
||||||
|
#include "tf2_geometry_msgs/tf2_geometry_msgs.h"
|
||||||
|
#include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
#ifndef AGV_PRO_DRIVER_H
|
|
||||||
#define AGV_PRO_DRIVER_H
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include "serial_driver/serial_driver.hpp"
|
|
||||||
|
|
||||||
#include "rclcpp/rclcpp.hpp"
|
|
||||||
|
|
||||||
#include <nav_msgs/msg/odometry.hpp>
|
|
||||||
#include <std_msgs/msg/float32.hpp>
|
|
||||||
#include <sensor_msgs/msg/imu.hpp>
|
|
||||||
#include <tf2_ros/transform_broadcaster.h>
|
|
||||||
#include <tf2/LinearMath/Quaternion.h>
|
|
||||||
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
|
|
||||||
|
|
||||||
#define RECEIVE_DATA_SIZE 14 //The length of the data sent by the esp32
|
|
||||||
|
|
||||||
extern std::array<double, 36> odom_pose_covariance;
|
|
||||||
extern std::array<double, 36> odom_twist_covariance;
|
|
||||||
|
|
||||||
class AGV_PRO : public rclcpp::Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AGV_PRO(std::string node_name);
|
|
||||||
~AGV_PRO();
|
|
||||||
private:
|
|
||||||
void Control();
|
|
||||||
void print_hex(const std::string& label, const std::vector<uint8_t>& data, std::optional<size_t> override_size = std::nullopt);
|
|
||||||
void send_serial_frame(const std::vector<uint8_t>& frame, bool debug);
|
|
||||||
void is_power_on();
|
|
||||||
void set_auto_report();
|
|
||||||
bool readData();
|
|
||||||
void publisherOdom(double dt);
|
|
||||||
void publisherVoltage();
|
|
||||||
void cmdCallback(const geometry_msgs::msg::Twist::SharedPtr msg);
|
|
||||||
std::vector<uint8_t> build_serial_frame(uint8_t cmd_id, const std::vector<uint8_t>& payload);
|
|
||||||
std::vector<uint8_t> read_serial_response(const std::vector<uint8_t>& expected_header, size_t payload_size, double timeout_sec);
|
|
||||||
|
|
||||||
std::string frame_id_of_odometry_;
|
|
||||||
std::string child_frame_id_of_odometry_;
|
|
||||||
std::string frame_id_of_imu_;
|
|
||||||
std::string name_space_;
|
|
||||||
std::string device_name_;
|
|
||||||
|
|
||||||
double x= 0.0;
|
|
||||||
double y= 0.0;
|
|
||||||
double theta= 0.0;
|
|
||||||
|
|
||||||
double vx= 0.0;
|
|
||||||
double vy= 0.0;
|
|
||||||
double vtheta= 0.0;
|
|
||||||
|
|
||||||
double linearX = 0.0;
|
|
||||||
double linearY = 0.0;
|
|
||||||
double angularZ = 0.0;
|
|
||||||
|
|
||||||
int is_poweron_status = 0;
|
|
||||||
int poweron_status = 0;
|
|
||||||
|
|
||||||
uint8_t motor_status = 0;
|
|
||||||
uint8_t motor_error = 0;
|
|
||||||
uint8_t enable_status = 0;
|
|
||||||
|
|
||||||
float battery_voltage = 0.0f;
|
|
||||||
|
|
||||||
rclcpp::Time currentTime, lastTime;
|
|
||||||
rclcpp::TimerBase::SharedPtr control_timer_;
|
|
||||||
rclcpp::Publisher<nav_msgs::msg::Odometry>::SharedPtr pub_odom;
|
|
||||||
rclcpp::Publisher<sensor_msgs::msg::Imu>::SharedPtr pub_imu;
|
|
||||||
rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr pub_voltage;
|
|
||||||
rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr cmd_sub;
|
|
||||||
|
|
||||||
std::unique_ptr<tf2_ros::TransformBroadcaster> odomBroadcaster;
|
|
||||||
std::shared_ptr<drivers::serial_driver::SerialDriver> serial_driver_;
|
|
||||||
std::shared_ptr<drivers::common::IoContext> io_context_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,464 +0,0 @@
|
|||||||
#include "agv_pro_base/agv_pro_driver.h"
|
|
||||||
|
|
||||||
std::array<double, 36> odom_pose_covariance = {
|
|
||||||
{1e-9, 0, 0, 0, 0, 0,
|
|
||||||
0, 1e-3, 1e-9, 0, 0, 0,
|
|
||||||
0, 0, 1e6, 0, 0, 0,
|
|
||||||
0, 0, 0, 1e6, 0, 0,
|
|
||||||
0, 0, 0, 0, 1e6, 0,
|
|
||||||
0, 0, 0, 0, 0, 1e-9} };
|
|
||||||
|
|
||||||
std::array<double, 36> odom_twist_covariance = {
|
|
||||||
{1e-9, 0, 0, 0, 0, 0,
|
|
||||||
0, 1e-3, 1e-9, 0, 0, 0,
|
|
||||||
0, 0, 1e6, 0, 0, 0,
|
|
||||||
0, 0, 0, 1e6, 0, 0,
|
|
||||||
0, 0, 0, 0, 1e6, 0,
|
|
||||||
0, 0, 0, 0, 0, 1e-9} };
|
|
||||||
|
|
||||||
uint16_t crc16_ibm(const uint8_t* data, size_t length) {
|
|
||||||
uint16_t crc = 0xFFFF;
|
|
||||||
for (size_t i = 0; i < length; ++i) {
|
|
||||||
crc ^= static_cast<uint16_t>(data[i]);
|
|
||||||
for (int j = 0; j < 8; ++j) {
|
|
||||||
if (crc & 0x0001)
|
|
||||||
crc = (crc >> 1) ^ 0xA001;
|
|
||||||
else
|
|
||||||
crc = crc >> 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> AGV_PRO::build_serial_frame(uint8_t cmd_id, const std::vector<uint8_t>& payload)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> frame(RECEIVE_DATA_SIZE, 0x00);
|
|
||||||
frame[0] = 0xFE;
|
|
||||||
frame[1] = 0xFE;
|
|
||||||
frame[2] = 0x0B;
|
|
||||||
frame[3] = cmd_id;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < payload.size() && i < 8; ++i) {
|
|
||||||
frame[4 + i] = payload[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t crc = crc16_ibm(frame.data(), 12);
|
|
||||||
frame[12] = (crc >> 8) & 0xff;
|
|
||||||
frame[13] = crc & 0xff;
|
|
||||||
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::print_hex(const std::string& label, const std::vector<uint8_t>& data, std::optional<size_t> override_size) {
|
|
||||||
std::stringstream ss;
|
|
||||||
for (auto b : data) {
|
|
||||||
ss << std::hex << std::uppercase << std::setfill('0') << std::setw(2)
|
|
||||||
<< static_cast<int>(b) << " ";
|
|
||||||
}
|
|
||||||
size_t len = override_size.value_or(data.size());
|
|
||||||
RCLCPP_INFO(this->get_logger(), "%s (%zu bytes): [%s]", label.c_str(), len, ss.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::send_serial_frame(const std::vector<uint8_t>& frame, bool debug)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
auto port = serial_driver_->port();
|
|
||||||
size_t bytes_transmit_size = port->send(frame);
|
|
||||||
if (debug) {
|
|
||||||
print_hex("Sent", frame, bytes_transmit_size);
|
|
||||||
}
|
|
||||||
} catch (const std::exception &ex) {
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "Error Transmiting from serial port: %s", ex.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> AGV_PRO::read_serial_response(const std::vector<uint8_t>& expected_header, size_t payload_size, double timeout_sec)
|
|
||||||
{
|
|
||||||
auto port = serial_driver_->port();
|
|
||||||
std::vector<uint8_t> sliding_buf;
|
|
||||||
uint8_t byte = 0;
|
|
||||||
|
|
||||||
rclcpp::Time start_time = this->now();
|
|
||||||
rclcpp::Duration timeout = rclcpp::Duration::from_seconds(timeout_sec);
|
|
||||||
|
|
||||||
while ((this->now() - start_time) < timeout) {
|
|
||||||
std::vector<uint8_t> temp_buf(1);
|
|
||||||
if (port->receive(temp_buf) == 1) {
|
|
||||||
byte = temp_buf[0];
|
|
||||||
sliding_buf.push_back(byte);
|
|
||||||
|
|
||||||
if (sliding_buf.size() > expected_header.size()) {
|
|
||||||
sliding_buf.erase(sliding_buf.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sliding_buf == expected_header) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sliding_buf != expected_header) {
|
|
||||||
RCLCPP_WARN(this->get_logger(), "Timeout waiting for header");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t remain_len = payload_size + 2;
|
|
||||||
std::vector<uint8_t> remain_buf(remain_len);
|
|
||||||
if (port->receive(remain_buf) != remain_len) {
|
|
||||||
RCLCPP_WARN(this->get_logger(), "Timeout or incomplete data payload");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> full_buf = expected_header;
|
|
||||||
full_buf.insert(full_buf.end(), remain_buf.begin(), remain_buf.end());
|
|
||||||
|
|
||||||
return full_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::is_power_on(){
|
|
||||||
auto power_query_frame = build_serial_frame(0x12, {});
|
|
||||||
send_serial_frame(power_query_frame,true);
|
|
||||||
|
|
||||||
const std::vector<uint8_t> expected_header = {0xFE, 0xFE, 0x0B, 0x12};
|
|
||||||
auto power_query_response = read_serial_response(expected_header, 8, 1.0);
|
|
||||||
|
|
||||||
print_hex("recv_buf", power_query_response);
|
|
||||||
|
|
||||||
if (power_query_response.size() != 14) return;
|
|
||||||
|
|
||||||
uint16_t received_crc = (power_query_response[12] << 8) | power_query_response[13];
|
|
||||||
uint16_t computed_crc = crc16_ibm(power_query_response.data(), 12);
|
|
||||||
if (received_crc != computed_crc) {
|
|
||||||
RCLCPP_WARN(this->get_logger(), "CRC mismatch: received=0x%04X, expected=0x%04X", received_crc, computed_crc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_poweron_status = static_cast<int8_t>(power_query_response[4]);
|
|
||||||
RCLCPP_INFO(this->get_logger(), "is_poweron_status: %d", is_poweron_status);
|
|
||||||
|
|
||||||
if (is_poweron_status == 0){
|
|
||||||
auto status_query_frame = build_serial_frame(0x10, {});
|
|
||||||
send_serial_frame(status_query_frame,true);
|
|
||||||
|
|
||||||
rclcpp::sleep_for(std::chrono::milliseconds(1000));// Sleep for 1000 milliseconds to allow the device enough time to process the previous command
|
|
||||||
|
|
||||||
const std::vector<uint8_t> expected_header = {0xFE, 0xFE, 0x0B, 0x10};
|
|
||||||
auto status_query_response = read_serial_response(expected_header, 8, 5.0);// Read the serial response with the specified expected header, payload size, and timeout of 5 seconds
|
|
||||||
print_hex("recv_buf", status_query_response);
|
|
||||||
|
|
||||||
if (status_query_response.size() != 14) return;
|
|
||||||
|
|
||||||
uint16_t received_crc = (status_query_response[12] << 8) | status_query_response[13];
|
|
||||||
uint16_t computed_crc = crc16_ibm(status_query_response.data(), 12);
|
|
||||||
if (received_crc != computed_crc) {
|
|
||||||
RCLCPP_WARN(this->get_logger(), "CRC mismatch: received=0x%04X, expected=0x%04X", received_crc, computed_crc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int poweron_status = static_cast<int8_t>(status_query_response[4]);
|
|
||||||
std::string status_msg;
|
|
||||||
|
|
||||||
switch (poweron_status) {
|
|
||||||
case 1:
|
|
||||||
status_msg = "Motor is operating normally.";
|
|
||||||
RCLCPP_INFO(this->get_logger(), "power_status: %d, %s", poweron_status, status_msg.c_str());
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
status_msg = "Emergency stop button is not released.";
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "power_status: %d, %s", poweron_status, status_msg.c_str());
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
status_msg = "Battery voltage is below 19.5V.";
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "power_status: %d, %s", poweron_status, status_msg.c_str());
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
status_msg = "CAN initialization error.";
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "power_status: %d, %s", poweron_status, status_msg.c_str());
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
status_msg = "Motor initialization error.";
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "power_status: %d, %s", poweron_status, status_msg.c_str());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
RCLCPP_WARN(this->get_logger(), "power_status: %d, Unknown power status code", poweron_status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Motor is operating normally.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::set_auto_report(){
|
|
||||||
auto frame = build_serial_frame(0x23, {0x01});
|
|
||||||
send_serial_frame(frame,true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::cmdCallback(const geometry_msgs::msg::Twist::SharedPtr msg)
|
|
||||||
{
|
|
||||||
linearX = std::clamp(msg->linear.x, -1.5, 1.5);
|
|
||||||
linearY = std::clamp(msg->linear.y, -1.0, 1.0);
|
|
||||||
angularZ = std::clamp(msg->angular.z, -1.0, 1.0);
|
|
||||||
|
|
||||||
int16_t x_send = static_cast<int16_t>(linearX * 100);
|
|
||||||
int16_t y_send = static_cast<int16_t>(linearY * 100);
|
|
||||||
int16_t rot_send = static_cast<int16_t>(angularZ * 100);
|
|
||||||
|
|
||||||
uint8_t buf[14] = { 0xfe,0xfe,0x0b,0x21 };
|
|
||||||
|
|
||||||
buf[4] = (x_send >> 8) & 0xff;
|
|
||||||
buf[5] = x_send & 0xff;
|
|
||||||
buf[6] = (y_send >> 8) & 0xff;
|
|
||||||
buf[7] = y_send & 0xff;
|
|
||||||
buf[8] = (rot_send >> 8) & 0xff;
|
|
||||||
buf[9] = rot_send & 0xff;
|
|
||||||
buf[10] = 0x00;
|
|
||||||
buf[11] = 0x00;
|
|
||||||
|
|
||||||
uint16_t crc = crc16_ibm(buf, 12);
|
|
||||||
buf[12] = (crc >> 8) & 0xff;
|
|
||||||
buf[13] = crc & 0xff;
|
|
||||||
|
|
||||||
std::vector<uint8_t> data_vec(buf, buf + sizeof(buf));
|
|
||||||
|
|
||||||
auto port = serial_driver_->port();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
port->send(data_vec);
|
|
||||||
// print_hex("Sent", data_vec);//debug
|
|
||||||
}
|
|
||||||
catch(const std::exception &ex)
|
|
||||||
{
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "Error Transmiting from serial port:%s",ex.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AGV_PRO::readData()
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> buf_header(1);
|
|
||||||
std::vector<uint8_t> buf_length(1);
|
|
||||||
std::vector<uint8_t> data_buf(RECEIVE_DATA_SIZE-3);
|
|
||||||
|
|
||||||
auto port = serial_driver_->port();
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
size_t ret = port->receive(buf_header);
|
|
||||||
if (ret != 1 || buf_header[0] != 0xfe) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = port->receive(buf_header);
|
|
||||||
if (ret == 1 && buf_header[0] == 0xfe) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ret = port->receive(buf_length);
|
|
||||||
|
|
||||||
if (buf_length[0] != 0x0b) {
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "The received length is incorrect:%u", buf_length[0]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = port->receive(data_buf);
|
|
||||||
if (ret != data_buf.size())
|
|
||||||
{
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "Failed to receive full payload");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> recv_buf;
|
|
||||||
recv_buf.push_back(0xFE);
|
|
||||||
recv_buf.push_back(0xFE);
|
|
||||||
recv_buf.push_back(0x0B);
|
|
||||||
recv_buf.insert(recv_buf.end(), data_buf.begin(), data_buf.end());
|
|
||||||
|
|
||||||
// print_hex("recv_buf", recv_buf); //debug
|
|
||||||
|
|
||||||
if (recv_buf[3] != 0x25) {
|
|
||||||
// RCLCPP_WARN(this->get_logger(), "Command error:0x%02X", recv_buf[2]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t received_crc = recv_buf[13] | (recv_buf[12] << 8);
|
|
||||||
uint16_t computed_crc = crc16_ibm(recv_buf.data(), 12);
|
|
||||||
|
|
||||||
if (received_crc != computed_crc) {
|
|
||||||
RCLCPP_WARN(this->get_logger(), "CRC error: received 0x%04X, calculated 0x%04X", received_crc, computed_crc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vx = static_cast<double>(static_cast<int8_t>(recv_buf[4])) * 0.01;
|
|
||||||
vy = static_cast<double>(static_cast<int8_t>(recv_buf[5])) * 0.01;
|
|
||||||
vtheta = static_cast<double>(static_cast<int8_t>(recv_buf[6])) * 0.01;
|
|
||||||
|
|
||||||
motor_status = recv_buf[7];
|
|
||||||
motor_error = recv_buf[8];
|
|
||||||
battery_voltage = static_cast<float>(recv_buf[9]) / 10.0f;
|
|
||||||
enable_status = recv_buf[10];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::publisherVoltage()
|
|
||||||
{
|
|
||||||
std_msgs::msg::Float32 voltage_msg,voltage_backup_msg;
|
|
||||||
voltage_msg.data = battery_voltage;
|
|
||||||
pub_voltage->publish(voltage_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::publisherOdom(double dt)
|
|
||||||
{
|
|
||||||
currentTime = this->get_clock()->now();
|
|
||||||
|
|
||||||
double delta_x = (vx * cos(theta) - vy * sin(theta)) * dt;
|
|
||||||
double delta_y = (vx * sin(theta) + vy * cos(theta)) * dt;
|
|
||||||
double delta_th = vtheta * dt;
|
|
||||||
|
|
||||||
x += delta_x;
|
|
||||||
y += delta_y;
|
|
||||||
theta += delta_th;
|
|
||||||
|
|
||||||
geometry_msgs::msg::TransformStamped odom_trans;
|
|
||||||
odom_trans.header.stamp = currentTime;
|
|
||||||
odom_trans.header.frame_id = frame_id_of_odometry_;
|
|
||||||
odom_trans.child_frame_id = child_frame_id_of_odometry_;
|
|
||||||
|
|
||||||
tf2::Quaternion quat;
|
|
||||||
quat.setRPY(0.0, 0.0, theta);
|
|
||||||
geometry_msgs::msg::Quaternion odom_quat = tf2::toMsg(quat);
|
|
||||||
|
|
||||||
odom_trans.transform.translation.x = x;
|
|
||||||
odom_trans.transform.translation.y = y;
|
|
||||||
odom_trans.transform.translation.z = 0.0;
|
|
||||||
odom_trans.transform.rotation = odom_quat;
|
|
||||||
|
|
||||||
odomBroadcaster->sendTransform(odom_trans);
|
|
||||||
|
|
||||||
nav_msgs::msg::Odometry odom;
|
|
||||||
odom.header.stamp = currentTime;
|
|
||||||
odom.header.frame_id = frame_id_of_odometry_;
|
|
||||||
odom.child_frame_id = child_frame_id_of_odometry_;
|
|
||||||
|
|
||||||
odom.pose.pose.position.x = x;
|
|
||||||
odom.pose.pose.position.y = y;
|
|
||||||
odom.pose.pose.position.z = 0.0;
|
|
||||||
odom.pose.pose.orientation = odom_quat;
|
|
||||||
odom.pose.covariance = odom_pose_covariance;
|
|
||||||
|
|
||||||
odom.twist.twist.linear.x = vx;
|
|
||||||
odom.twist.twist.linear.y = vy;
|
|
||||||
odom.twist.twist.angular.z = vtheta;
|
|
||||||
odom.twist.covariance = odom_twist_covariance;
|
|
||||||
|
|
||||||
pub_odom->publish(odom);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGV_PRO::Control()
|
|
||||||
{
|
|
||||||
if (true == readData())
|
|
||||||
{
|
|
||||||
currentTime = this->get_clock()->now();
|
|
||||||
double dt = 0.0;
|
|
||||||
if (lastTime.nanoseconds() != 0) {
|
|
||||||
dt = (currentTime - lastTime).seconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTime = currentTime;
|
|
||||||
publisherOdom(dt);
|
|
||||||
// RCLCPP_INFO(this->get_logger(), "dt:%f", dt);
|
|
||||||
publisherVoltage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AGV_PRO::AGV_PRO(std::string node_name):rclcpp::Node(node_name)
|
|
||||||
{
|
|
||||||
this->declare_parameter<std::string>("port_name","/dev/agvpro_controller");
|
|
||||||
this->declare_parameter<std::string>("odometry.frame_id", "odom");
|
|
||||||
this->declare_parameter<std::string>("odometry.child_frame_id", "base_footprint");
|
|
||||||
this->declare_parameter<std::string>("imu.frame_id", "imu_link");
|
|
||||||
this->declare_parameter<std::string>("namespace", "");
|
|
||||||
|
|
||||||
this->get_parameter_or<std::string>("port_name",device_name_,std::string("/dev/agvpro_controller"));
|
|
||||||
this->get_parameter_or<std::string>("odometry.frame_id",frame_id_of_odometry_,std::string("odom"));
|
|
||||||
this->get_parameter_or<std::string>("odometry.child_frame_id",child_frame_id_of_odometry_,std::string("base_footprint"));
|
|
||||||
this->get_parameter_or<std::string>("imu.frame_id",frame_id_of_imu_,std::string("imu_link"));
|
|
||||||
this->get_parameter_or<std::string>("namespace",name_space_,std::string(""));
|
|
||||||
|
|
||||||
if (name_space_ != "") {
|
|
||||||
frame_id_of_odometry_ = name_space_ + "/" + frame_id_of_odometry_;
|
|
||||||
child_frame_id_of_odometry_ = name_space_ + "/" + child_frame_id_of_odometry_;
|
|
||||||
frame_id_of_imu_ = name_space_ + "/" + frame_id_of_imu_;
|
|
||||||
}
|
|
||||||
|
|
||||||
odomBroadcaster = std::make_unique<tf2_ros::TransformBroadcaster>(this);
|
|
||||||
pub_imu = this->create_publisher<sensor_msgs::msg::Imu>("imu", 20);
|
|
||||||
pub_odom = this->create_publisher<nav_msgs::msg::Odometry>("odom", 50);
|
|
||||||
pub_voltage = create_publisher<std_msgs::msg::Float32>("voltage", 10);
|
|
||||||
cmd_sub = this->create_subscription<geometry_msgs::msg::Twist>(
|
|
||||||
"/cmd_vel", 10, std::bind(&AGV_PRO::cmdCallback, this, std::placeholders::_1));
|
|
||||||
|
|
||||||
lastTime = this->get_clock()->now();
|
|
||||||
|
|
||||||
drivers::serial_driver::SerialPortConfig config(
|
|
||||||
1000000,
|
|
||||||
drivers::serial_driver::FlowControl::NONE,
|
|
||||||
drivers::serial_driver::Parity::NONE,
|
|
||||||
drivers::serial_driver::StopBits::ONE
|
|
||||||
);
|
|
||||||
|
|
||||||
try{
|
|
||||||
io_context_ = std::make_shared<drivers::common::IoContext>(1);
|
|
||||||
serial_driver_ = std::make_shared<drivers::serial_driver::SerialDriver>(*io_context_);
|
|
||||||
serial_driver_->init_port(device_name_, config);
|
|
||||||
serial_driver_->port()->open();
|
|
||||||
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Serial port initialized successfully");
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Using device: %s", serial_driver_->port().get()->device_name().c_str());
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Baud_rate: %d", config.get_baud_rate());
|
|
||||||
|
|
||||||
AGV_PRO::is_power_on();
|
|
||||||
AGV_PRO::set_auto_report();
|
|
||||||
}
|
|
||||||
catch (const std::exception &ex){
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "Failed to initialize serial port: %s", ex.what());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
control_timer_ = this->create_wall_timer(
|
|
||||||
std::chrono::milliseconds(20),
|
|
||||||
std::bind(&AGV_PRO::Control, this)
|
|
||||||
);
|
|
||||||
RCLCPP_INFO(this->get_logger(), "Control timer started");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
AGV_PRO::~AGV_PRO()
|
|
||||||
{
|
|
||||||
std::array<uint8_t, 14> buf = {
|
|
||||||
0xFE, 0xFE, 0x0b, 0x22,
|
|
||||||
0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
uint16_t crc = crc16_ibm(buf.data(), 12);
|
|
||||||
buf[12] = (crc >> 8) & 0xff;
|
|
||||||
buf[13] = crc & 0xff;
|
|
||||||
|
|
||||||
std::vector<uint8_t> data_vec(buf.begin(), buf.end());
|
|
||||||
|
|
||||||
auto port = serial_driver_->port();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
port->send(data_vec);
|
|
||||||
}
|
|
||||||
catch(const std::exception &ex)
|
|
||||||
{
|
|
||||||
RCLCPP_ERROR(this->get_logger(), "Error Transmiting from serial port:%s",ex.what());
|
|
||||||
}
|
|
||||||
|
|
||||||
serial_driver_->port()->close();
|
|
||||||
RCLCPP_INFO(this->get_logger(),"Shutting down");
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import os
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch_ros.actions import Node,PushRosNamespace
|
|
||||||
from launch.actions import DeclareLaunchArgument,IncludeLaunchDescription
|
|
||||||
from launch.substitutions import Command,LaunchConfiguration,PythonExpression
|
|
||||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
|
|
||||||
port_name_arg = LaunchConfiguration('port_name',default='/dev/agvpro_controller')
|
|
||||||
namespace = LaunchConfiguration('namespace', default='')
|
|
||||||
|
|
||||||
urdf_file = os.path.join(
|
|
||||||
get_package_share_directory('agv_pro_description'),
|
|
||||||
'urdf',
|
|
||||||
'agv_pro.urdf'
|
|
||||||
)
|
|
||||||
|
|
||||||
robot_description_content = Command([
|
|
||||||
'xacro ',
|
|
||||||
urdf_file,
|
|
||||||
' namespace:=',
|
|
||||||
PythonExpression(['"', namespace, '" + "/" if "', namespace, '" != "" else ""']),
|
|
||||||
])
|
|
||||||
|
|
||||||
return LaunchDescription([
|
|
||||||
DeclareLaunchArgument(
|
|
||||||
'port_name',
|
|
||||||
default_value=port_name_arg,
|
|
||||||
description='port name, e.g. ttyACM0'),
|
|
||||||
|
|
||||||
DeclareLaunchArgument(
|
|
||||||
'namespace',
|
|
||||||
default_value='',
|
|
||||||
description='Namespace for nodes'),
|
|
||||||
|
|
||||||
PushRosNamespace(namespace),
|
|
||||||
|
|
||||||
Node(
|
|
||||||
package='agv_pro_base',
|
|
||||||
executable='agv_pro_node',
|
|
||||||
name='agv_pro_node',
|
|
||||||
output='screen',
|
|
||||||
parameters=[{
|
|
||||||
'port_name': port_name_arg,
|
|
||||||
'namespace': namespace,
|
|
||||||
}],
|
|
||||||
remappings=[('cmd_vel', '/cmd_vel')]
|
|
||||||
),
|
|
||||||
|
|
||||||
Node(
|
|
||||||
package='joint_state_publisher',
|
|
||||||
executable='joint_state_publisher',
|
|
||||||
name='joint_state_publisher'
|
|
||||||
),
|
|
||||||
|
|
||||||
Node(
|
|
||||||
package='robot_state_publisher',
|
|
||||||
executable='robot_state_publisher',
|
|
||||||
name='robot_state_publisher',
|
|
||||||
parameters=[{'robot_description': robot_description_content}],
|
|
||||||
output='screen'
|
|
||||||
),
|
|
||||||
|
|
||||||
IncludeLaunchDescription(
|
|
||||||
PythonLaunchDescriptionSource([os.path.join(
|
|
||||||
get_package_share_directory('lslidar_driver'),'launch'),
|
|
||||||
'/lsn10p_launch.py'])
|
|
||||||
)
|
|
||||||
])
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<robot name="AGV pro" xmlns:xacro="http://www.ros.org/wiki/xacro">
|
|
||||||
|
|
||||||
<xacro:arg name="namespace" default=""/>
|
|
||||||
<xacro:property name="namespace" value="$(arg namespace)"/>
|
|
||||||
|
|
||||||
<link name="${namespace}base_footprint"/>
|
|
||||||
|
|
||||||
<joint name="${namespace}base_joint" type="fixed">
|
|
||||||
<parent link="${namespace}base_footprint"/>
|
|
||||||
<child link="${namespace}base_link" />
|
|
||||||
<origin xyz="0 0 0.020" rpy="0 0 0"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="${namespace}base_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0076254 -0.00023134 0.06693" rpy="0 0 0" />
|
|
||||||
<mass value="19.236" />
|
|
||||||
<inertia ixx="0.14436" ixy="0.0012037" ixz="0.0019458"
|
|
||||||
iyy="0.24191" iyz="0.0044629"
|
|
||||||
izz="0.33755" />
|
|
||||||
</inertial>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0"
|
|
||||||
rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<link name="${namespace}right_rear_wheel_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<mass value="0.21659" />
|
|
||||||
<inertia ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07"
|
|
||||||
iyy="0.00097519" iyz="-2.3635E-07"
|
|
||||||
izz="0.00051178" />
|
|
||||||
</inertial>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0"
|
|
||||||
rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_rb_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0"
|
|
||||||
rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_rb_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="${namespace}right_rear_wheel_joint" type="continuous">
|
|
||||||
<origin xyz="-0.171806101587598 -0.179900399999999 0.0518836514526621" rpy="0 0 0" />
|
|
||||||
<parent link="${namespace}base_link" />
|
|
||||||
<child link="${namespace}right_rear_wheel_link" />
|
|
||||||
<axis xyz="0 1 0" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="${namespace}right_front_wheel_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="6.6563E-05 -0.019725 8.3836E-05" rpy="0 0 0" />
|
|
||||||
<mass value="0.21659122149244" />
|
|
||||||
<inertia ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07"
|
|
||||||
iyy="0.00097519" iyz="-2.3635E-07"
|
|
||||||
izz="0.00051178" />
|
|
||||||
</inertial>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_rf_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_rf_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="${namespace}right_front_wheel_joint" type="continuous">
|
|
||||||
<origin xyz="-0.17181 0.1799 0.051884"
|
|
||||||
rpy="0 0 0" />
|
|
||||||
<parent link="${namespace}base_link" />
|
|
||||||
<child link="${namespace}right_front_wheel_link" />
|
|
||||||
<axis xyz="0 1 0" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="${namespace}left_front_wheel_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="1.4671E-06 -0.019803 4.3218E-06" rpy="0 0 0" />
|
|
||||||
<mass value="0.3015" />
|
|
||||||
<inertia ixx="0.00052475" ixy="-2.2533E-07" ixz="-4.1904E-07"
|
|
||||||
iyy="0.00099948" iyz="7.5332E-08"
|
|
||||||
izz="0.00052362" />
|
|
||||||
</inertial>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_lf_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_lf_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="${namespace}left_front_wheel_joint" type="continuous">
|
|
||||||
<origin xyz="0.17128 0.1799 0.052"
|
|
||||||
rpy="0 0 0" />
|
|
||||||
<parent link="${namespace}base_link" />
|
|
||||||
<child link="${namespace}left_front_wheel_link" />
|
|
||||||
<axis xyz="0 1 0" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="${namespace}left_rear_wheel_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-2.4454E-06 0.019725 -4.3121E-06" rpy="0 0 0" />
|
|
||||||
<mass value="0.29613" />
|
|
||||||
<inertia ixx="0.00051227" ixy="-2.0628E-07" ixz="-4.9074E-07"
|
|
||||||
iyy="0.0009752" iyz="1.173E-07"
|
|
||||||
izz="0.00051131" />
|
|
||||||
</inertial>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_lb_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/wheel_lb_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="${namespace}left_rear_wheel_joint" type="continuous">
|
|
||||||
<origin xyz="0.17128 -0.1799 0.052" rpy="0 0 0" />
|
|
||||||
<parent link="${namespace}base_link" />
|
|
||||||
<child link="${namespace}left_rear_wheel_link" />
|
|
||||||
<axis xyz="0 1 0" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="${namespace}laser_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0035142 -2.8248E-05 0.0010013" rpy="0 0 0" />
|
|
||||||
<mass value="0.049095" />
|
|
||||||
<inertia ixx="2.0572E-05" ixy="8.5013E-08" ixz="2.0871E-07" iyy="2.0483E-05"
|
|
||||||
iyz="-4.2154E-09"
|
|
||||||
izz="3.4612E-05" />
|
|
||||||
</inertial>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="${namespace}lidar_joint" type="fixed">
|
|
||||||
<origin xyz="0.17891 0 0.20928" rpy="0 0 0" />
|
|
||||||
<parent link="${namespace}base_link" />
|
|
||||||
<child link="${namespace}laser_link" />
|
|
||||||
</joint>
|
|
||||||
</robot>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
controller_manager:
|
|
||||||
ros__parameters:
|
|
||||||
update_rate: 100
|
|
||||||
|
|
||||||
joint_state_broadcaster:
|
|
||||||
type: joint_state_broadcaster/JointStateBroadcaster
|
|
||||||
|
|
||||||
diff_drive_controller:
|
|
||||||
type: diff_drive_controller/DiffDriveController
|
|
||||||
left_wheel_names: ["left_front_wheel_joint", "left_rear_wheel_joint"]
|
|
||||||
right_wheel_names: ["right_front_wheel_joint", "right_rear_wheel_joint"]
|
|
||||||
|
|
||||||
wheel_separation: 0.36
|
|
||||||
wheel_radius: 0.05
|
|
||||||
|
|
||||||
base_frame_id: base_link
|
|
||||||
use_stamped_vel: false
|
|
||||||
publish_rate: 50
|
|
||||||
|
|
||||||
enable_odom_tf: true
|
|
||||||
odom_frame_id: odom
|
|
||||||
pose_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03]
|
|
||||||
twist_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
controller_manager:
|
|
||||||
ros__parameters:
|
|
||||||
update_rate: 100 # 控制器更新频率 (Hz)
|
|
||||||
use_sim_time: true # 使用仿真时间
|
|
||||||
|
|
||||||
# 定义关节状态广播器
|
|
||||||
fishbot_joint_state_broadcaster:
|
|
||||||
type: joint_state_broadcaster/JointStateBroadcaster
|
|
||||||
use_sim_time: true
|
|
||||||
|
|
||||||
# 定义全向驱动控制器
|
|
||||||
fishbot_omni_drive_controller:
|
|
||||||
type: omni_drive_controller/OmniDriveController
|
|
||||||
|
|
||||||
# 四轮全向控制器配置
|
|
||||||
fishbot_omni_drive_controller:
|
|
||||||
ros__parameters:
|
|
||||||
front_left_wheel_joint: front_left_wheel_joint
|
|
||||||
front_right_wheel_joint: front_right_wheel_joint
|
|
||||||
rear_left_wheel_joint: rear_left_wheel_joint
|
|
||||||
rear_right_wheel_joint: rear_right_wheel_joint
|
|
||||||
wheel_separation: 0.36 # 轮距
|
|
||||||
wheel_diameter: 0.1 # 轮子直径
|
|
||||||
publish_rate: 50.0 # 发布频率
|
|
||||||
odom_frame_id: odom
|
|
||||||
base_frame_id: base_link
|
|
||||||
pose_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03]
|
|
||||||
twist_covariance_diagonal: [0.001, 0.001, 99999.0, 99999.0, 99999.0, 0.03]
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch.substitutions import LaunchConfiguration
|
|
||||||
from launch.actions import DeclareLaunchArgument
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
|
|
||||||
import xacro
|
|
||||||
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
|
|
||||||
# Check if we're told to use sim time
|
|
||||||
use_sim_time = LaunchConfiguration('use_sim_time')
|
|
||||||
|
|
||||||
# Process the URDF file
|
|
||||||
pkg_path = os.path.join(get_package_share_directory('agv_pro_gazebo'))
|
|
||||||
xacro_file = os.path.join(pkg_path,'urdf','agv_pro.xacro')
|
|
||||||
robot_description_config = xacro.process_file(xacro_file)
|
|
||||||
|
|
||||||
# Create a robot_state_publisher node
|
|
||||||
params = {'robot_description': robot_description_config.toxml(), 'use_sim_time': use_sim_time}
|
|
||||||
node_robot_state_publisher = Node(
|
|
||||||
package='robot_state_publisher',
|
|
||||||
executable='robot_state_publisher',
|
|
||||||
output='screen',
|
|
||||||
parameters=[params]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Launch!
|
|
||||||
return LaunchDescription([
|
|
||||||
DeclareLaunchArgument(
|
|
||||||
'use_sim_time',
|
|
||||||
default_value='false',
|
|
||||||
description='Use sim time if true'),
|
|
||||||
|
|
||||||
node_robot_state_publisher
|
|
||||||
])
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import os
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
from launch.conditions import IfCondition
|
|
||||||
from launch.substitutions import LaunchConfiguration
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
|
|
||||||
use_rviz = LaunchConfiguration('use_rviz', default='true')
|
|
||||||
rviz_config_dir = os.path.join(
|
|
||||||
get_package_share_directory('agv_pro_gazebo'),
|
|
||||||
'rviz',
|
|
||||||
'agvpro_display.rviz')
|
|
||||||
|
|
||||||
urdf_file = os.path.join(
|
|
||||||
get_package_share_directory('agv_pro_gazebo'),
|
|
||||||
'urdf',
|
|
||||||
'agv_pro.urdf'
|
|
||||||
)
|
|
||||||
|
|
||||||
with open(urdf_file, 'r') as file:
|
|
||||||
robot_description_content = file.read()
|
|
||||||
|
|
||||||
return LaunchDescription([
|
|
||||||
|
|
||||||
Node(
|
|
||||||
package='joint_state_publisher',
|
|
||||||
executable='joint_state_publisher',
|
|
||||||
name='joint_state_publisher'
|
|
||||||
),
|
|
||||||
|
|
||||||
Node(
|
|
||||||
package='robot_state_publisher',
|
|
||||||
executable='robot_state_publisher',
|
|
||||||
name='robot_state_publisher',
|
|
||||||
parameters=[{'robot_description': robot_description_content}]
|
|
||||||
),
|
|
||||||
|
|
||||||
Node(
|
|
||||||
package='rviz2',
|
|
||||||
executable='rviz2',
|
|
||||||
name='rviz2',
|
|
||||||
arguments=['-d', rviz_config_dir],
|
|
||||||
condition=IfCondition(use_rviz),
|
|
||||||
output='screen')
|
|
||||||
|
|
||||||
])
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import os
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch.actions import IncludeLaunchDescription
|
|
||||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
|
||||||
from launch.substitutions import Command
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
from launch_ros.parameter_descriptions import ParameterValue
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
pkg_name = 'agv_pro_gazebo'
|
|
||||||
pkg_dir = get_package_share_directory(pkg_name)
|
|
||||||
xacro_file = os.path.join(pkg_dir, 'urdf', 'agv_pro.xacro')
|
|
||||||
world_file = os.path.join(pkg_dir, 'worlds', 'empty.world')
|
|
||||||
rviz_config = os.path.join(pkg_dir, 'rviz', 'agvpro_display.rviz')
|
|
||||||
|
|
||||||
robot_description_content = ParameterValue(
|
|
||||||
Command(['xacro ', xacro_file]),
|
|
||||||
value_type=str
|
|
||||||
)
|
|
||||||
robot_description = {'robot_description': robot_description_content}
|
|
||||||
|
|
||||||
return LaunchDescription([
|
|
||||||
# Launch Gazebo
|
|
||||||
IncludeLaunchDescription(
|
|
||||||
PythonLaunchDescriptionSource(
|
|
||||||
os.path.join(get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')
|
|
||||||
),
|
|
||||||
launch_arguments={'world': world_file}.items()
|
|
||||||
),
|
|
||||||
|
|
||||||
# Spawn robot into Gazebo
|
|
||||||
Node(
|
|
||||||
package='gazebo_ros',
|
|
||||||
executable='spawn_entity.py',
|
|
||||||
arguments=['-topic', 'robot_description',
|
|
||||||
'-entity', 'agv_pro'],
|
|
||||||
output='screen'
|
|
||||||
),
|
|
||||||
|
|
||||||
# State publisher
|
|
||||||
Node(
|
|
||||||
package='robot_state_publisher',
|
|
||||||
executable='robot_state_publisher',
|
|
||||||
name='robot_state_publisher',
|
|
||||||
output='screen',
|
|
||||||
parameters=[robot_description]
|
|
||||||
),
|
|
||||||
|
|
||||||
Node(
|
|
||||||
package='joint_state_publisher',
|
|
||||||
executable='joint_state_publisher',
|
|
||||||
name='joint_state_publisher',
|
|
||||||
output='screen',
|
|
||||||
),
|
|
||||||
|
|
||||||
# Optional: RViz
|
|
||||||
Node(
|
|
||||||
package='rviz2',
|
|
||||||
executable='rviz2',
|
|
||||||
name='rviz2',
|
|
||||||
output='screen',
|
|
||||||
arguments=['-d', rviz_config],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import os
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch.actions import IncludeLaunchDescription, ExecuteProcess
|
|
||||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
|
||||||
from launch.substitutions import Command, LaunchConfiguration, PathJoinSubstitution
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
pkg_name = 'agv_pro_description'
|
|
||||||
|
|
||||||
# Paths
|
|
||||||
pkg_dir = get_package_share_directory(pkg_name)
|
|
||||||
xacro_file = os.path.join(pkg_dir, 'urdf', 'agv_pro.xacro')
|
|
||||||
world_file = os.path.join(pkg_dir, 'worlds', 'empty.world') # 创建一个空 world 即可
|
|
||||||
rviz_config = os.path.join(pkg_dir, 'rviz', 'agvpro_display.rviz')
|
|
||||||
|
|
||||||
robot_description_content = Command(['xacro ', xacro_file])
|
|
||||||
robot_description = {'robot_description': robot_description_content}
|
|
||||||
|
|
||||||
return LaunchDescription([
|
|
||||||
|
|
||||||
# Start Gazebo with empty world
|
|
||||||
IncludeLaunchDescription(
|
|
||||||
PythonLaunchDescriptionSource(
|
|
||||||
[os.path.join(get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')]
|
|
||||||
),
|
|
||||||
launch_arguments={'world': world_file}.items()
|
|
||||||
),
|
|
||||||
|
|
||||||
# Spawn robot into Gazebo
|
|
||||||
Node(
|
|
||||||
package='gazebo_ros',
|
|
||||||
executable='spawn_entity.py',
|
|
||||||
arguments=['-topic', 'robot_description',
|
|
||||||
'-entity', 'agv_pro'],
|
|
||||||
output='screen'
|
|
||||||
),
|
|
||||||
|
|
||||||
# Robot state publisher
|
|
||||||
Node(
|
|
||||||
package='robot_state_publisher',
|
|
||||||
executable='robot_state_publisher',
|
|
||||||
name='robot_state_publisher',
|
|
||||||
output='screen',
|
|
||||||
parameters=[robot_description]
|
|
||||||
),
|
|
||||||
|
|
||||||
# Optionally publish joint states if not using controllers
|
|
||||||
Node(
|
|
||||||
package='joint_state_publisher',
|
|
||||||
executable='joint_state_publisher',
|
|
||||||
name='joint_state_publisher',
|
|
||||||
output='screen',
|
|
||||||
),
|
|
||||||
Node(
|
|
||||||
package='controller_manager',
|
|
||||||
executable='spawner',
|
|
||||||
arguments=['joint_state_broadcaster'],
|
|
||||||
output='screen',
|
|
||||||
),
|
|
||||||
|
|
||||||
# RViz (optional, visualize TF & model)
|
|
||||||
Node(
|
|
||||||
package='rviz2',
|
|
||||||
executable='rviz2',
|
|
||||||
name='rviz2',
|
|
||||||
output='screen',
|
|
||||||
arguments=['-d', rviz_config],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import os
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
return LaunchDescription([
|
|
||||||
Node(
|
|
||||||
package='teleop_twist_keyboard',
|
|
||||||
executable='teleop_twist_keyboard',
|
|
||||||
name='teleop_keyboard',
|
|
||||||
output='screen',
|
|
||||||
prefix='xterm -e', # 或 'gnome-terminal --' 替换为你的终端命令
|
|
||||||
remappings=[
|
|
||||||
('/cmd_vel', '/diff_drive_controller/cmd_vel_unstamped')
|
|
||||||
]
|
|
||||||
)
|
|
||||||
])
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import os
|
|
||||||
from launch import LaunchDescription
|
|
||||||
from launch.actions import IncludeLaunchDescription
|
|
||||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
|
||||||
from launch_ros.actions import Node
|
|
||||||
from launch.substitutions import Command
|
|
||||||
from ament_index_python.packages import get_package_share_directory
|
|
||||||
|
|
||||||
def generate_launch_description():
|
|
||||||
pkg_dir = get_package_share_directory('agv_pro_description')
|
|
||||||
xacro_file = os.path.join(pkg_dir, 'urdf', 'minimal_robot.xacro')
|
|
||||||
world_file = os.path.join(pkg_dir, 'worlds', 'empty.world')
|
|
||||||
|
|
||||||
robot_description = {'robot_description': Command(['xacro ', xacro_file])}
|
|
||||||
|
|
||||||
return LaunchDescription([
|
|
||||||
IncludeLaunchDescription(
|
|
||||||
PythonLaunchDescriptionSource(
|
|
||||||
os.path.join(get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')
|
|
||||||
),
|
|
||||||
launch_arguments={'world': world_file}.items()
|
|
||||||
),
|
|
||||||
Node(
|
|
||||||
package='robot_state_publisher',
|
|
||||||
executable='robot_state_publisher',
|
|
||||||
parameters=[robot_description],
|
|
||||||
output='screen'
|
|
||||||
),
|
|
||||||
Node(
|
|
||||||
package='gazebo_ros',
|
|
||||||
executable='spawn_entity.py',
|
|
||||||
arguments=['-topic', 'robot_description', '-entity', 'minimal_bot'],
|
|
||||||
output='screen'
|
|
||||||
)
|
|
||||||
])
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="agv_pro">
|
|
||||||
|
|
||||||
<!-- Gazebo-specific properties -->
|
|
||||||
<xacro:property name="wheel_damping" value="0.1"/>
|
|
||||||
<xacro:property name="wheel_axis" value="0 1 0"/>
|
|
||||||
|
|
||||||
<!-- Base footprint -->
|
|
||||||
<link name="base_footprint"/>
|
|
||||||
|
|
||||||
<joint name="base_joint" type="fixed">
|
|
||||||
<parent link="base_footprint"/>
|
|
||||||
<child link="base_link" />
|
|
||||||
<origin xyz="0 0 0.020" rpy="0 0 0"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="base_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0076254 -0.00023134 0.06693" rpy="0 0 0" />
|
|
||||||
<mass value="19.236" />
|
|
||||||
<inertia ixx="0.14436" ixy="0.0012037" ixz="0.0019458" iyy="0.24191" iyz="0.0044629" izz="0.33755" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_description)/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_description)/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<!-- Gazebo plugin for control -->
|
|
||||||
<gazebo>
|
|
||||||
<plugin name="gazebo_ros2_control" filename="libgazebo_ros2_control.so"/>
|
|
||||||
</gazebo>
|
|
||||||
|
|
||||||
<gazebo reference="base_link">
|
|
||||||
<material>Gazebo/White</material>
|
|
||||||
<mu1>1.0</mu1>
|
|
||||||
<mu2>1.0</mu2>
|
|
||||||
<kp>100000.0</kp>
|
|
||||||
<kd>1.0</kd>
|
|
||||||
</gazebo>
|
|
||||||
|
|
||||||
<!-- Include wheel macros -->
|
|
||||||
<xacro:include filename="$(find agv_pro_description)/urdf/parts/wheel_macro.xacro"/>
|
|
||||||
<xacro:include filename="$(find agv_pro_description)/urdf/parts/gazebo_control_plugin.xacro"/>
|
|
||||||
<!-- Add all four wheels using macro -->
|
|
||||||
<xacro:wheel name="right_rear_wheel" mesh="file://$(find agv_pro_description)/meshes/wheel_rb_link.stl" origin_xyz="-0.1718 -0.1799 0.05188" origin_rpy="0 0 0" mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07" iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
|
|
||||||
<xacro:wheel name="right_front_wheel" mesh="file://$(find agv_pro_description)/meshes/wheel_rf_link.stl" origin_xyz="-0.17181 0.1799 0.051884" origin_rpy="0 0 0" mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07" iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
|
|
||||||
<xacro:wheel name="left_front_wheel" mesh="file://$(find agv_pro_description)/meshes/wheel_lf_link.stl" origin_xyz="0.17128 0.1799 0.052" origin_rpy="0 0 0" mass="0.3015" ixx="0.00052475" ixy="-2.2533E-07" ixz="-4.1904E-07" iyy="0.00099948" iyz="7.5332E-08" izz="0.00052362"/>
|
|
||||||
|
|
||||||
<xacro:wheel name="left_rear_wheel" mesh="file://$(find agv_pro_description)/meshes/wheel_lb_link.stl" origin_xyz="0.17128 -0.1799 0.052" origin_rpy="0 0 0" mass="0.29613" ixx="0.00051227" ixy="-2.0628E-07" ixz="-4.9074E-07" iyy="0.0009752" iyz="1.173E-07" izz="0.00051131"/>
|
|
||||||
|
|
||||||
<!-- Lidar -->
|
|
||||||
<link name="laser_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0035142 -2.8248E-05 0.0010013" rpy="0 0 0" />
|
|
||||||
<mass value="0.049095" />
|
|
||||||
<inertia ixx="2.0572E-05" ixy="8.5013E-08" ixz="2.0871E-07" iyy="2.0483E-05" iyz="-4.2154E-09" izz="3.4612E-05" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_description)/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_description)/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="lidar_joint" type="fixed">
|
|
||||||
<origin xyz="0.17891 0 0.20928" rpy="0 0 0" />
|
|
||||||
<parent link="base_link" />
|
|
||||||
<child link="laser_link" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<!-- ros2_control tag -->
|
|
||||||
<ros2_control name="AGVHardware" type="system">
|
|
||||||
<hardware>
|
|
||||||
<plugin>gazebo_ros2_control/GazeboSystem</plugin>
|
|
||||||
</hardware>
|
|
||||||
|
|
||||||
<joint name="right_rear_wheel_joint">
|
|
||||||
<command_interface name="velocity"/>
|
|
||||||
<state_interface name="position"/>
|
|
||||||
<state_interface name="velocity"/>
|
|
||||||
</joint>
|
|
||||||
<joint name="right_front_wheel_joint">
|
|
||||||
<command_interface name="velocity"/>
|
|
||||||
<state_interface name="position"/>
|
|
||||||
<state_interface name="velocity"/>
|
|
||||||
</joint>
|
|
||||||
<joint name="left_front_wheel_joint">
|
|
||||||
<command_interface name="velocity"/>
|
|
||||||
<state_interface name="position"/>
|
|
||||||
<state_interface name="velocity"/>
|
|
||||||
</joint>
|
|
||||||
<joint name="left_rear_wheel_joint">
|
|
||||||
<command_interface name="velocity"/>
|
|
||||||
<state_interface name="position"/>
|
|
||||||
<state_interface name="velocity"/>
|
|
||||||
</joint>
|
|
||||||
</ros2_control>
|
|
||||||
|
|
||||||
</robot>
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="agv_pro">
|
|
||||||
|
|
||||||
<!-- Define vehicle dimensions -->
|
|
||||||
<xacro:property name="vehicle_width" value="0.36"/> <!-- 车辆宽度 -->
|
|
||||||
<xacro:property name="wheel_radius" value="0.05"/> <!-- 轮子半径 -->
|
|
||||||
|
|
||||||
<!-- Gazebo-specific properties -->
|
|
||||||
<xacro:property name="wheel_damping" value="0.1"/>
|
|
||||||
<xacro:property name="wheel_axis" value="0 1 0"/>
|
|
||||||
|
|
||||||
<!-- Base footprint -->
|
|
||||||
<link name="base_footprint"/>
|
|
||||||
|
|
||||||
<joint name="base_joint" type="fixed">
|
|
||||||
<parent link="base_footprint"/>
|
|
||||||
<child link="base_link" />
|
|
||||||
<origin xyz="0 0 0.020" rpy="0 0 0"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="base_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0076254 -0.00023134 0.06693" rpy="0 0 0" />
|
|
||||||
<mass value="19.236" />
|
|
||||||
<inertia ixx="0.14436" ixy="0.0012037" ixz="0.0019458" iyy="0.24191" iyz="0.0044629" izz="0.33755" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_gazebo)/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name=""/>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_gazebo)/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<!-- Include wheel macros & controller definitions -->
|
|
||||||
<xacro:include filename="$(find agv_pro_gazebo)/urdf/parts/wheel_macro.xacro"/>
|
|
||||||
|
|
||||||
<!-- Wheels definition -->
|
|
||||||
<!-- Right Rear Wheel -->
|
|
||||||
<xacro:wheel name="right_rear_wheel" mesh="file://$(find agv_pro_gazebo)/meshes/wheel_rb_link.stl" origin_xyz="-0.1718 -0.1799 0.05188" origin_rpy="0 0 0" mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07" iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
|
|
||||||
<!-- Right Front Wheel -->
|
|
||||||
<xacro:wheel name="right_front_wheel" mesh="file://$(find agv_pro_gazebo)/meshes/wheel_rf_link.stl" origin_xyz="-0.17181 0.1799 0.051884" origin_rpy="0 0 0" mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07" iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
|
|
||||||
<!-- Left Front Wheel -->
|
|
||||||
<xacro:wheel name="left_front_wheel" mesh="file://$(find agv_pro_gazebo)/meshes/wheel_lf_link.stl" origin_xyz="0.17128 0.1799 0.052" origin_rpy="0 0 0" mass="0.3015" ixx="0.00052475" ixy="-2.2533E-07" ixz="-4.1904E-07" iyy="0.00099948" iyz="7.5332E-08" izz="0.00052362"/>
|
|
||||||
|
|
||||||
<!-- Left Rear Wheel -->
|
|
||||||
<xacro:wheel name="left_rear_wheel" mesh="file://$(find agv_pro_gazebo)/meshes/wheel_lb_link.stl" origin_xyz="0.17128 -0.1799 0.052" origin_rpy="0 0 0" mass="0.29613" ixx="0.00051227" ixy="-2.0628E-07" ixz="-4.9074E-07" iyy="0.0009752" iyz="1.173E-07" izz="0.00051131"/>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Lidar definition -->
|
|
||||||
<link name="laser_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0035142 -2.8248E-05 0.0010013" rpy="0 0 0" />
|
|
||||||
<mass value="0.049095" />
|
|
||||||
<inertia ixx="2.0572E-05" ixy="8.5013E-08" ixz="2.0871E-07" iyy="2.0483E-05" iyz="-4.2154E-09" izz="3.4612E-05" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_gazebo)/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name=""/>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="file://$(find agv_pro_gazebo)/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="lidar_joint" type="fixed">
|
|
||||||
<origin xyz="0.17891 0 0.20928" rpy="0 0 0" />
|
|
||||||
<parent link="base_link" />
|
|
||||||
<child link="laser_link" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<!-- Include ros2_controller.xacro to define controllers -->
|
|
||||||
<xacro:include filename="$(find agv_pro_gazebo)/urdf/parts/gazebo_control_plugin.xacro"/>
|
|
||||||
<xacro:include filename="$(find agv_pro_gazebo)/urdf/ros2_controller.xacro"/>
|
|
||||||
<xacro:ros2_controller/>
|
|
||||||
<xacro:gazebo_control_plugin/>
|
|
||||||
</robot>
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="agv_pro">
|
|
||||||
|
|
||||||
<xacro:property name="wheel_axis" value="0 1 0"/>
|
|
||||||
<xacro:property name="wheel_damping" value="0.1"/>
|
|
||||||
|
|
||||||
<!-- Macro: wheel with Gazebo plugin -->
|
|
||||||
<xacro:macro name="wheel" params="name mesh origin_xyz origin_rpy mass ixx ixy ixz iyy iyz izz">
|
|
||||||
<link name="${name}_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<mass value="${mass}" />
|
|
||||||
<inertia ixx="${ixx}" ixy="${ixy}" ixz="${ixz}" iyy="${iyy}" iyz="${iyz}" izz="${izz}" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="${mesh}" />
|
|
||||||
</geometry>
|
|
||||||
<material name=""><color rgba="1 1 1 1"/></material>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="${mesh}" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
<joint name="${name}_joint" type="continuous">
|
|
||||||
<origin xyz="${origin_xyz}" rpy="${origin_rpy}"/>
|
|
||||||
<parent link="base_link"/>
|
|
||||||
<child link="${name}_link"/>
|
|
||||||
<axis xyz="${wheel_axis}"/>
|
|
||||||
<dynamics damping="${wheel_damping}"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<transmission name="${name}_trans">
|
|
||||||
<type>transmission_interface/SimpleTransmission</type>
|
|
||||||
<actuator name="${name}_motor">
|
|
||||||
<mechanicalReduction>1</mechanicalReduction>
|
|
||||||
</actuator>
|
|
||||||
<joint name="${name}_joint">
|
|
||||||
<hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
|
|
||||||
</joint>
|
|
||||||
</transmission>
|
|
||||||
|
|
||||||
<gazebo reference="${name}_link">
|
|
||||||
<mu1>0.8</mu1>
|
|
||||||
<mu2>0.8</mu2>
|
|
||||||
<kp>100000.0</kp>
|
|
||||||
<kd>1.0</kd>
|
|
||||||
<material>Gazebo/Grey</material>
|
|
||||||
</gazebo>
|
|
||||||
</xacro:macro>
|
|
||||||
|
|
||||||
<!-- Base links -->
|
|
||||||
<link name="base_footprint"/>
|
|
||||||
|
|
||||||
<joint name="base_joint" type="fixed">
|
|
||||||
<parent link="base_footprint"/>
|
|
||||||
<child link="base_link"/>
|
|
||||||
<origin xyz="0 0 0.020" rpy="0 0 0"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="base_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0076254 -0.00023134 0.06693" rpy="0 0 0" />
|
|
||||||
<mass value="19.236" />
|
|
||||||
<inertia ixx="0.14436" ixy="0.0012037" ixz="0.0019458"
|
|
||||||
iyy="0.24191" iyz="0.0044629" izz="0.33755"/>
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/base_link.stl"/>
|
|
||||||
</geometry>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/base_link.stl"/>
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<!-- Gazebo plugin for ros2_control -->
|
|
||||||
<gazebo>
|
|
||||||
<plugin name="gazebo_ros2_control" filename="libgazebo_ros2_control.so"/>
|
|
||||||
</gazebo>
|
|
||||||
|
|
||||||
<!-- Wheels -->
|
|
||||||
<xacro:wheel name="right_rear_wheel"
|
|
||||||
mesh="package://agv_pro_description/meshes/wheel_rb_link.stl"
|
|
||||||
origin_xyz="-0.1718 -0.1799 0.05188" origin_rpy="0 0 0"
|
|
||||||
mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07"
|
|
||||||
iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
|
|
||||||
<xacro:wheel name="right_front_wheel"
|
|
||||||
mesh="package://agv_pro_description/meshes/wheel_rf_link.stl"
|
|
||||||
origin_xyz="-0.17181 0.1799 0.051884" origin_rpy="0 0 0"
|
|
||||||
mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07"
|
|
||||||
iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
|
|
||||||
<xacro:wheel name="left_front_wheel"
|
|
||||||
mesh="package://agv_pro_description/meshes/wheel_lf_link.stl"
|
|
||||||
origin_xyz="0.17128 0.1799 0.052" origin_rpy="0 0 0"
|
|
||||||
mass="0.3015" ixx="0.00052475" ixy="-2.2533E-07" ixz="-4.1904E-07"
|
|
||||||
iyy="0.00099948" iyz="7.5332E-08" izz="0.00052362"/>
|
|
||||||
|
|
||||||
<xacro:wheel name="left_rear_wheel"
|
|
||||||
mesh="package://agv_pro_description/meshes/wheel_lb_link.stl"
|
|
||||||
origin_xyz="0.17128 -0.1799 0.052" origin_rpy="0 0 0"
|
|
||||||
mass="0.29613" ixx="0.00051227" ixy="-2.0628E-07" ixz="-4.9074E-07"
|
|
||||||
iyy="0.0009752" iyz="1.173E-07" izz="0.00051131"/>
|
|
||||||
|
|
||||||
<!-- Lidar -->
|
|
||||||
<link name="laser_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0035142 -2.8248E-05 0.0010013" rpy="0 0 0"/>
|
|
||||||
<mass value="0.049095"/>
|
|
||||||
<inertia ixx="2.0572E-05" ixy="8.5013E-08" ixz="2.0871E-07"
|
|
||||||
iyy="2.0483E-05" iyz="-4.2154E-09" izz="3.4612E-05"/>
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/laser_link.stl"/>
|
|
||||||
</geometry>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0"/>
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="package://agv_pro_description/meshes/laser_link.stl"/>
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="lidar_joint" type="fixed">
|
|
||||||
<origin xyz="0.17891 0 0.20928" rpy="0 0 0"/>
|
|
||||||
<parent link="base_link"/>
|
|
||||||
<child link="laser_link"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
</robot>
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<robot xmlns:xacro="http://ros.org/wiki/xacro" name="agv_pro">
|
|
||||||
|
|
||||||
<!-- Gazebo-specific properties -->
|
|
||||||
<xacro:property name="wheel_damping" value="0.1"/>
|
|
||||||
<xacro:property name="wheel_axis" value="0 1 0"/>
|
|
||||||
|
|
||||||
<!-- Base footprint -->
|
|
||||||
<link name="base_footprint"/>
|
|
||||||
|
|
||||||
<joint name="base_joint" type="fixed">
|
|
||||||
<parent link="base_footprint"/>
|
|
||||||
<child link="base_link" />
|
|
||||||
<origin xyz="0 0 0.020" rpy="0 0 0"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<link name="base_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0076254 -0.00023134 0.06693" rpy="0 0 0" />
|
|
||||||
<mass value="19.236" />
|
|
||||||
<inertia ixx="0.14436" ixy="0.0012037" ixz="0.0019458" iyy="0.24191" iyz="0.0044629" izz="0.33755" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="model://agv_pro_description/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="model://agv_pro_description/meshes/base_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<gazebo reference="base_link">
|
|
||||||
<material>Gazebo/White</material>
|
|
||||||
<mu1>1.0</mu1>
|
|
||||||
<mu2>1.0</mu2>
|
|
||||||
<kp>100000.0</kp>
|
|
||||||
<kd>1.0</kd>
|
|
||||||
</gazebo>
|
|
||||||
|
|
||||||
<!-- Include wheel macros & plugin -->
|
|
||||||
<xacro:include filename="$(find agv_pro_description)/urdf/parts/wheel_macro.xacro"/>
|
|
||||||
<xacro:include filename="$(find agv_pro_description)/urdf/parts/gazebo_control_plugin.xacro"/>
|
|
||||||
|
|
||||||
<!-- All four wheels with corrected mesh paths -->
|
|
||||||
<xacro:wheel name="right_rear_wheel" mesh="model://agv_pro_description/meshes/wheel_rb_link.stl" origin_xyz="-0.1718 -0.1799 0.05188" origin_rpy="0 0 0" mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07" iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
<xacro:wheel name="right_front_wheel" mesh="model://agv_pro_description/meshes/wheel_rf_link.stl" origin_xyz="-0.17181 0.1799 0.051884" origin_rpy="0 0 0" mass="0.21659" ixx="0.00051181" ixy="2.1577E-08" ixz="2.538E-07" iyy="0.00097519" iyz="-2.3635E-07" izz="0.00051178"/>
|
|
||||||
<xacro:wheel name="left_front_wheel" mesh="model://agv_pro_description/meshes/wheel_lf_link.stl" origin_xyz="0.17128 0.1799 0.052" origin_rpy="0 0 0" mass="0.3015" ixx="0.00052475" ixy="-2.2533E-07" ixz="-4.1904E-07" iyy="0.00099948" iyz="7.5332E-08" izz="0.00052362"/>
|
|
||||||
<xacro:wheel name="left_rear_wheel" mesh="model://agv_pro_description/meshes/wheel_lb_link.stl" origin_xyz="0.17128 -0.1799 0.052" origin_rpy="0 0 0" mass="0.29613" ixx="0.00051227" ixy="-2.0628E-07" ixz="-4.9074E-07" iyy="0.0009752" iyz="1.173E-07" izz="0.00051131"/>
|
|
||||||
|
|
||||||
<!-- Lidar -->
|
|
||||||
<link name="laser_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="-0.0035142 -2.8248E-05 0.0010013" rpy="0 0 0" />
|
|
||||||
<mass value="0.049095" />
|
|
||||||
<inertia ixx="2.0572E-05" ixy="8.5013E-08" ixz="2.0871E-07" iyy="2.0483E-05" iyz="-4.2154E-09" izz="3.4612E-05" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="model://agv_pro_description/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
<material name="">
|
|
||||||
<color rgba="1 1 1 1" />
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="model://agv_pro_description/meshes/laser_link.stl" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="lidar_joint" type="fixed">
|
|
||||||
<origin xyz="0.17891 0 0.20928" rpy="0 0 0" />
|
|
||||||
<parent link="base_link" />
|
|
||||||
<child link="laser_link" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<!-- 插件调用 -->
|
|
||||||
<xacro:gazebo_control_plugin/>
|
|
||||||
|
|
||||||
</robot>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
|
|
||||||
<xacro:macro name="gazebo_control_plugin">
|
|
||||||
<gazebo>
|
|
||||||
<!-- 使用全向控制插件 -->
|
|
||||||
<plugin filename="libgazebo_ros_planar_move.so" name="mecanum_drive_controller">
|
|
||||||
<ros>
|
|
||||||
<remapping>cmd_vel:=/cmd_vel</remapping>
|
|
||||||
<remapping>odom:=/odom</remapping>
|
|
||||||
</ros>
|
|
||||||
|
|
||||||
<!-- 配置全向控制 -->
|
|
||||||
<frontLeftJoint>front_left_wheel_joint</frontLeftJoint> <!-- 前左轮 -->
|
|
||||||
<frontRightJoint>front_right_wheel_joint</frontRightJoint> <!-- 前右轮 -->
|
|
||||||
<rearLeftJoint>rear_left_wheel_joint</rearLeftJoint> <!-- 后左轮 -->
|
|
||||||
<rearRightJoint>rear_right_wheel_joint</rearRightJoint> <!-- 后右轮 -->
|
|
||||||
<wheelDiameter>0.1</wheelDiameter> <!-- 轮子直径 -->
|
|
||||||
<wheelSeparation>0.36</wheelSeparation> <!-- 轮距(车辆宽度) -->
|
|
||||||
|
|
||||||
<torque>20</torque> <!-- 轮子扭矩 -->
|
|
||||||
<topicName>cmd_vel</topicName> <!-- 控制命令话题 -->
|
|
||||||
<odometryFrame>odom</odometryFrame> <!-- 里程计坐标系 -->
|
|
||||||
<odometryTopic>odom</odometryTopic> <!-- 里程计话题 -->
|
|
||||||
<robotBaseFrame>base_footprint</robotBaseFrame> <!-- 机器人基础坐标系 -->
|
|
||||||
<publishOdomTF>true</publishOdomTF> <!-- 发布里程计变换 -->
|
|
||||||
</plugin>
|
|
||||||
</gazebo>
|
|
||||||
</xacro:macro>
|
|
||||||
</robot>
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<robot xmlns:xacro="http://ros.org/wiki/xacro">
|
|
||||||
|
|
||||||
<xacro:macro name="wheel" params="name mesh origin_xyz origin_rpy mass ixx ixy ixz iyy iyz izz">
|
|
||||||
|
|
||||||
<link name="${name}_link">
|
|
||||||
<inertial>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<mass value="${mass}" />
|
|
||||||
<inertia ixx="${ixx}" ixy="${ixy}" ixz="${ixz}" iyy="${iyy}" iyz="${iyz}" izz="${izz}" />
|
|
||||||
</inertial>
|
|
||||||
<visual>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="${mesh}" />
|
|
||||||
</geometry>
|
|
||||||
<material name="gray">
|
|
||||||
<color rgba="0.3 0.3 0.3 1"/>
|
|
||||||
</material>
|
|
||||||
</visual>
|
|
||||||
<collision>
|
|
||||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
|
||||||
<geometry>
|
|
||||||
<mesh filename="${mesh}" />
|
|
||||||
</geometry>
|
|
||||||
</collision>
|
|
||||||
</link>
|
|
||||||
|
|
||||||
<joint name="${name}_joint" type="continuous">
|
|
||||||
<origin xyz="${origin_xyz}" rpy="${origin_rpy}" />
|
|
||||||
<parent link="base_link" />
|
|
||||||
<child link="${name}_link" />
|
|
||||||
<axis xyz="0 1 0"/>
|
|
||||||
<dynamics damping="0.1"/>
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<!-- Correct transmission for ROS2 -->
|
|
||||||
<transmission name="${name}_trans">
|
|
||||||
<type>transmission_interface/SimpleTransmission</type>
|
|
||||||
<joint name="${name}_joint">
|
|
||||||
<hardwareInterface>hardware_interface/velocity</hardwareInterface>
|
|
||||||
</joint>
|
|
||||||
<actuator name="${name}_motor">
|
|
||||||
<mechanicalReduction>1</mechanicalReduction>
|
|
||||||
<hardwareInterface>hardware_interface/velocity</hardwareInterface>
|
|
||||||
</actuator>
|
|
||||||
</transmission>
|
|
||||||
|
|
||||||
<gazebo reference="${name}_link">
|
|
||||||
<mu1>0.8</mu1>
|
|
||||||
<mu2>0.8</mu2>
|
|
||||||
<kp>100000.0</kp>
|
|
||||||
<kd>1.0</kd>
|
|
||||||
<material>Gazebo/Black</material>
|
|
||||||
</gazebo>
|
|
||||||
|
|
||||||
</xacro:macro>
|
|
||||||
</robot>
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
|
|
||||||
<xacro:macro name="ros2_controller">
|
|
||||||
<ros2_control name="FishBotGazeboSystem" type="system">
|
|
||||||
<hardware>
|
|
||||||
<plugin>gazebo_ros2_control/GazeboSystem</plugin>
|
|
||||||
</hardware>
|
|
||||||
|
|
||||||
<!-- 配置所有轮子的控制接口 -->
|
|
||||||
<joint name="front_left_wheel_joint">
|
|
||||||
<command_interface name="position" />
|
|
||||||
<command_interface name="velocity" />
|
|
||||||
<command_interface name="effort" />
|
|
||||||
<state_interface name="position" />
|
|
||||||
<state_interface name="velocity" />
|
|
||||||
<state_interface name="effort" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<joint name="front_right_wheel_joint">
|
|
||||||
<command_interface name="position" />
|
|
||||||
<command_interface name="velocity" />
|
|
||||||
<command_interface name="effort" />
|
|
||||||
<state_interface name="position" />
|
|
||||||
<state_interface name="velocity" />
|
|
||||||
<state_interface name="effort" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<joint name="rear_left_wheel_joint">
|
|
||||||
<command_interface name="position" />
|
|
||||||
<command_interface name="velocity" />
|
|
||||||
<command_interface name="effort" />
|
|
||||||
<state_interface name="position" />
|
|
||||||
<state_interface name="velocity" />
|
|
||||||
<state_interface name="effort" />
|
|
||||||
</joint>
|
|
||||||
|
|
||||||
<joint name="rear_right_wheel_joint">
|
|
||||||
<command_interface name="position" />
|
|
||||||
<command_interface name="velocity" />
|
|
||||||
<command_interface name="effort" />
|
|
||||||
<state_interface name="position" />
|
|
||||||
<state_interface name="velocity" />
|
|
||||||
<state_interface name="effort" />
|
|
||||||
</joint>
|
|
||||||
</ros2_control>
|
|
||||||
<gazebo>
|
|
||||||
<plugin filename="libgazebo_ros2_control.so" name="gazebo_ros2_control">
|
|
||||||
<parameters>$(find agv_pro_gazebo)/config/agv_control.yaml</parameters>
|
|
||||||
<ros>
|
|
||||||
<remapping>/omni_drive_controller/cmd_vel:=/cmd_vel</remapping>
|
|
||||||
<remapping>/omni_drive_controller/odom:=/odom</remapping>
|
|
||||||
</ros>
|
|
||||||
</plugin>
|
|
||||||
</gazebo>
|
|
||||||
</xacro:macro>
|
|
||||||
</robot>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
<sdf version="1.6">
|
|
||||||
<world name="empty_world">
|
|
||||||
<include>
|
|
||||||
<uri>model://ground_plane</uri>
|
|
||||||
</include>
|
|
||||||
<include>
|
|
||||||
<uri>model://sun</uri>
|
|
||||||
</include>
|
|
||||||
</world>
|
|
||||||
</sdf>
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
services:
|
||||||
|
agv_pro:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
platforms:
|
||||||
|
- linux/amd64
|
||||||
|
- linux/arm64
|
||||||
|
image: agv_pro_ros2
|
||||||
|
container_name: agv_pro_ros2
|
||||||
|
network_mode: host
|
||||||
|
ipc: host
|
||||||
|
devices:
|
||||||
|
- "/dev/agvpro_controller:/dev/agvpro_controller"
|
||||||
|
group_add:
|
||||||
|
- dialout
|
||||||
|
environment:
|
||||||
|
- ROS_DOMAIN_ID=0
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
command: bash
|
||||||
@@ -1,524 +0,0 @@
|
|||||||
version: 2.1
|
|
||||||
|
|
||||||
_commands:
|
|
||||||
common_commands: &common_commands
|
|
||||||
ccache_stats:
|
|
||||||
description: "CCache Stats"
|
|
||||||
parameters:
|
|
||||||
workspace:
|
|
||||||
type: string
|
|
||||||
when:
|
|
||||||
type: string
|
|
||||||
default: on_success
|
|
||||||
steps:
|
|
||||||
- run:
|
|
||||||
name: CCache Stats
|
|
||||||
working_directory: << parameters.workspace >>
|
|
||||||
environment:
|
|
||||||
CCACHE_DIR: << parameters.workspace >>/.ccache
|
|
||||||
command: |
|
|
||||||
ccache -s # show stats
|
|
||||||
ccache -z # zero stats
|
|
||||||
ccache -V # show version
|
|
||||||
ccache -p # show config
|
|
||||||
when: << parameters.when >>
|
|
||||||
restore_from_cache:
|
|
||||||
description: "Restore From Cache"
|
|
||||||
parameters:
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
workspace:
|
|
||||||
type: string
|
|
||||||
steps:
|
|
||||||
- restore_cache:
|
|
||||||
name: Restore Cache << parameters.key >>
|
|
||||||
keys:
|
|
||||||
- "<< parameters.key >>-v13\
|
|
||||||
-{{ arch }}\
|
|
||||||
-{{ .Branch }}\
|
|
||||||
-{{ .Environment.CIRCLE_PR_NUMBER }}\
|
|
||||||
-{{ checksum \"<< parameters.workspace >>/lockfile.txt\" }}"
|
|
||||||
- "<< parameters.key >>-v13\
|
|
||||||
-{{ arch }}\
|
|
||||||
-main\
|
|
||||||
-<no value>\
|
|
||||||
-{{ checksum \"<< parameters.workspace >>/lockfile.txt\" }}"
|
|
||||||
save_to_cache:
|
|
||||||
description: "Save To Cache"
|
|
||||||
parameters:
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
workspace:
|
|
||||||
type: string
|
|
||||||
path:
|
|
||||||
type: string
|
|
||||||
when:
|
|
||||||
type: string
|
|
||||||
default: on_success
|
|
||||||
steps:
|
|
||||||
- save_cache:
|
|
||||||
name: Save Cache << parameters.key >>
|
|
||||||
key: "<< parameters.key >>-v13\
|
|
||||||
-{{ arch }}\
|
|
||||||
-{{ .Branch }}\
|
|
||||||
-{{ .Environment.CIRCLE_PR_NUMBER }}\
|
|
||||||
-{{ checksum \"<< parameters.workspace >>/lockfile.txt\" }}\
|
|
||||||
-{{ epoch }}"
|
|
||||||
paths:
|
|
||||||
- << parameters.path >>/.ccache
|
|
||||||
- << parameters.path >>/build
|
|
||||||
- << parameters.path >>/install
|
|
||||||
- << parameters.path >>/log
|
|
||||||
- << parameters.path >>/test_results
|
|
||||||
when: << parameters.when >>
|
|
||||||
install_dependencies:
|
|
||||||
description: "Install Dependencies"
|
|
||||||
parameters:
|
|
||||||
underlay:
|
|
||||||
type: string
|
|
||||||
workspace:
|
|
||||||
type: string
|
|
||||||
steps:
|
|
||||||
- run:
|
|
||||||
name: Install Dependencies | << parameters.workspace >>
|
|
||||||
working_directory: << parameters.workspace >>
|
|
||||||
command: |
|
|
||||||
. << parameters.underlay >>/install/setup.sh
|
|
||||||
AMENT_PREFIX_PATH=$(echo "$AMENT_PREFIX_PATH" | \
|
|
||||||
sed -e 's|:/opt/ros/'$ROS_DISTRO'$||')
|
|
||||||
if [ "$AMENT_PREFIX_PATH" == "/opt/ros/$ROS_DISTRO" ]
|
|
||||||
then
|
|
||||||
unset AMENT_PREFIX_PATH
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat << parameters.underlay >>/lockfile.txt > lockfile.txt
|
|
||||||
vcs export --exact << parameters.underlay >>/src | \
|
|
||||||
(echo vcs_export && cat) >> lockfile.txt
|
|
||||||
sha256sum $PWD/lockfile.txt >> lockfile.txt
|
|
||||||
|
|
||||||
apt-get update
|
|
||||||
rosdep update --rosdistro $ROS_DISTRO
|
|
||||||
dependencies=$(
|
|
||||||
rosdep install -q -y \
|
|
||||||
--from-paths src \
|
|
||||||
--ignore-src \
|
|
||||||
--skip-keys " \
|
|
||||||
slam_toolbox \
|
|
||||||
" \
|
|
||||||
--verbose | \
|
|
||||||
awk '$1 ~ /^resolution\:/' | \
|
|
||||||
awk -F'[][]' '{print $2}' | \
|
|
||||||
tr -d \, | xargs -n1 | sort -u | xargs)
|
|
||||||
dpkg --list dpkg $dependencies | \
|
|
||||||
(echo workspace_dependencies && cat) >> lockfile.txt
|
|
||||||
sha256sum $PWD/lockfile.txt >> lockfile.txt
|
|
||||||
setup_workspace:
|
|
||||||
description: "Setup Workspace"
|
|
||||||
parameters:
|
|
||||||
underlay:
|
|
||||||
type: string
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
workspace:
|
|
||||||
type: string
|
|
||||||
mixins:
|
|
||||||
type: string
|
|
||||||
build:
|
|
||||||
default: true
|
|
||||||
type: boolean
|
|
||||||
steps:
|
|
||||||
- store_artifacts:
|
|
||||||
path: << parameters.workspace >>/lockfile.txt
|
|
||||||
- restore_from_cache:
|
|
||||||
key: << parameters.key >>
|
|
||||||
workspace: << parameters.workspace >>
|
|
||||||
- when:
|
|
||||||
condition: << parameters.build >>
|
|
||||||
steps:
|
|
||||||
- ccache_stats:
|
|
||||||
workspace: << parameters.workspace >>
|
|
||||||
when: always
|
|
||||||
- run:
|
|
||||||
name: Build Workspace | << parameters.workspace >>
|
|
||||||
working_directory: << parameters.workspace >>
|
|
||||||
environment:
|
|
||||||
CCACHE_DIR: << parameters.workspace >>/.ccache
|
|
||||||
command: |
|
|
||||||
colcon cache lock
|
|
||||||
|
|
||||||
BUILD_UNFINISHED=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-skip-build-finished \
|
|
||||||
| xargs)
|
|
||||||
echo BUILD_UNFINISHED: $BUILD_UNFINISHED
|
|
||||||
|
|
||||||
BUILD_FAILED=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-select-build-failed \
|
|
||||||
| xargs)
|
|
||||||
echo BUILD_FAILED: $BUILD_FAILED
|
|
||||||
|
|
||||||
BUILD_INVALID=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-select-cache-invalid \
|
|
||||||
--packages-select-cache-key build \
|
|
||||||
| xargs)
|
|
||||||
echo BUILD_INVALID: $BUILD_INVALID
|
|
||||||
|
|
||||||
BUILD_PACKAGES=""
|
|
||||||
if [ -n "$BUILD_UNFINISHED" ] || \
|
|
||||||
[ -n "$BUILD_FAILED" ] || \
|
|
||||||
[ -n "$BUILD_INVALID" ]
|
|
||||||
then
|
|
||||||
BUILD_PACKAGES=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-above \
|
|
||||||
$BUILD_UNFINISHED \
|
|
||||||
$BUILD_FAILED \
|
|
||||||
$BUILD_INVALID \
|
|
||||||
| xargs)
|
|
||||||
fi
|
|
||||||
echo BUILD_PACKAGES: $BUILD_PACKAGES
|
|
||||||
|
|
||||||
colcon clean packages --yes \
|
|
||||||
--packages-select ${BUILD_PACKAGES} \
|
|
||||||
--base-select install
|
|
||||||
|
|
||||||
. << parameters.underlay >>/install/setup.sh
|
|
||||||
colcon build \
|
|
||||||
--packages-select ${BUILD_PACKAGES} \
|
|
||||||
--mixin << parameters.mixins >>
|
|
||||||
- ccache_stats:
|
|
||||||
workspace: << parameters.workspace >>
|
|
||||||
when: always
|
|
||||||
- save_to_cache:
|
|
||||||
key: << parameters.key >>
|
|
||||||
path: << parameters.workspace >>
|
|
||||||
workspace: << parameters.workspace >>
|
|
||||||
when: always
|
|
||||||
- run:
|
|
||||||
name: Copy Build Logs
|
|
||||||
working_directory: << parameters.workspace >>
|
|
||||||
command: cp -rH log/latest_build log/build
|
|
||||||
when: always
|
|
||||||
- store_artifacts:
|
|
||||||
path: << parameters.workspace >>/log/build
|
|
||||||
test_workspace:
|
|
||||||
description: "Test Workspace"
|
|
||||||
parameters:
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
workspace:
|
|
||||||
type: string
|
|
||||||
cache_test:
|
|
||||||
type: boolean
|
|
||||||
steps:
|
|
||||||
- run:
|
|
||||||
name: Test Workspace | << parameters.workspace >>
|
|
||||||
working_directory: << parameters.workspace >>
|
|
||||||
command: |
|
|
||||||
TEST_UNPASSED=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-skip-test-passed \
|
|
||||||
| xargs)
|
|
||||||
echo TEST_UNPASSED: $TEST_UNPASSED
|
|
||||||
|
|
||||||
TEST_FAILURES=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-select-test-failures \
|
|
||||||
| xargs)
|
|
||||||
echo TEST_FAILURES: $TEST_FAILURES
|
|
||||||
|
|
||||||
TEST_INVALID=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-select-cache-invalid \
|
|
||||||
--packages-select-cache-key test \
|
|
||||||
| xargs)
|
|
||||||
echo TEST_INVALID: $TEST_INVALID
|
|
||||||
|
|
||||||
TEST_PACKAGES=""
|
|
||||||
if [ -n "$TEST_UNPASSED" ] || \
|
|
||||||
[ -n "$TEST_FAILURES" ] || \
|
|
||||||
[ -n "$TEST_INVALID" ]
|
|
||||||
then
|
|
||||||
TEST_PACKAGES=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-above \
|
|
||||||
$TEST_UNPASSED \
|
|
||||||
$TEST_FAILURES \
|
|
||||||
$TEST_INVALID)
|
|
||||||
fi
|
|
||||||
if ( ! << parameters.cache_test >> )
|
|
||||||
then
|
|
||||||
TEST_PACKAGES=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only)
|
|
||||||
fi
|
|
||||||
TEST_PACKAGES=$(
|
|
||||||
echo $TEST_PACKAGES \
|
|
||||||
| circleci tests split \
|
|
||||||
--split-by=timings \
|
|
||||||
--timings-type=classname \
|
|
||||||
--show-counts \
|
|
||||||
| xargs)
|
|
||||||
echo TEST_PACKAGES: $TEST_PACKAGES
|
|
||||||
|
|
||||||
colcon clean packages --yes \
|
|
||||||
--packages-select ${TEST_PACKAGES} \
|
|
||||||
--base-select test_result
|
|
||||||
colcon clean packages --yes \
|
|
||||||
--packages-select ${TEST_PACKAGES} \
|
|
||||||
--base-select build \
|
|
||||||
--clean-match \
|
|
||||||
"*.gcda"
|
|
||||||
|
|
||||||
. install/setup.sh
|
|
||||||
set -o xtrace
|
|
||||||
colcon test \
|
|
||||||
--packages-select ${TEST_PACKAGES}
|
|
||||||
colcon test-result \
|
|
||||||
--verbose
|
|
||||||
- when:
|
|
||||||
condition: << parameters.cache_test >>
|
|
||||||
steps:
|
|
||||||
- save_to_cache:
|
|
||||||
key: << parameters.key >>
|
|
||||||
path: << parameters.workspace >>
|
|
||||||
workspace: << parameters.workspace >>
|
|
||||||
when: always
|
|
||||||
- run:
|
|
||||||
name: Copy Test Logs
|
|
||||||
working_directory: << parameters.workspace >>
|
|
||||||
command: cp -rH log/latest_test log/test
|
|
||||||
when: always
|
|
||||||
- store_artifacts:
|
|
||||||
path: << parameters.workspace >>/log/test
|
|
||||||
- store_artifacts:
|
|
||||||
path: << parameters.workspace >>/test_results
|
|
||||||
- run:
|
|
||||||
name: Prepare Test Results
|
|
||||||
working_directory: << parameters.workspace >>
|
|
||||||
command: find test_results -name "Test.xml" -type f -delete
|
|
||||||
when: always
|
|
||||||
- store_test_results:
|
|
||||||
path: << parameters.workspace >>/test_results
|
|
||||||
|
|
||||||
_steps:
|
|
||||||
pre_checkout: &pre_checkout
|
|
||||||
run:
|
|
||||||
name: Pre Checkout
|
|
||||||
command: |
|
|
||||||
mkdir -p $ROS_WS/src && cd $ROS_WS
|
|
||||||
ln -s /opt/ros/$ROS_DISTRO install
|
|
||||||
|
|
||||||
echo $CACHE_NONCE | \
|
|
||||||
(echo cache_nonce && cat) >> lockfile.txt
|
|
||||||
sha256sum $PWD/lockfile.txt >> lockfile.txt
|
|
||||||
|
|
||||||
TZ=utc stat -c '%y' /ros_entrypoint.sh | \
|
|
||||||
(echo ros_entrypoint && cat) >> lockfile.txt
|
|
||||||
sha256sum $PWD/lockfile.txt >> lockfile.txt
|
|
||||||
|
|
||||||
rm -rf $OVERLAY_WS/*
|
|
||||||
on_checkout: &on_checkout
|
|
||||||
checkout:
|
|
||||||
path: src/navigation2
|
|
||||||
post_checkout: &post_checkout
|
|
||||||
run:
|
|
||||||
name: Post Checkout
|
|
||||||
command: |
|
|
||||||
cp $OVERLAY_WS/src/navigation2/.circleci/defaults.yaml $COLCON_DEFAULTS_FILE
|
|
||||||
if ! cmp \
|
|
||||||
$OVERLAY_WS/src/navigation2/tools/underlay.repos \
|
|
||||||
$UNDERLAY_WS/underlay.repos >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
echo "Importing Underlay"
|
|
||||||
cp $OVERLAY_WS/src/navigation2/tools/underlay.repos \
|
|
||||||
$UNDERLAY_WS/underlay.repos
|
|
||||||
vcs import $UNDERLAY_WS/src \
|
|
||||||
< $UNDERLAY_WS/underlay.repos
|
|
||||||
fi
|
|
||||||
install_underlay_dependencies: &install_underlay_dependencies
|
|
||||||
install_dependencies:
|
|
||||||
underlay: /opt/ros_ws
|
|
||||||
workspace: /opt/underlay_ws
|
|
||||||
setup_underlay_workspace: &setup_underlay_workspace
|
|
||||||
setup_workspace: &setup_workspace_underlay
|
|
||||||
key: underlay_ws
|
|
||||||
underlay: /opt/ros_ws
|
|
||||||
workspace: /opt/underlay_ws
|
|
||||||
mixins: ${UNDERLAY_MIXINS}
|
|
||||||
restore_underlay_workspace: &restore_underlay_workspace
|
|
||||||
setup_workspace:
|
|
||||||
<<: *setup_workspace_underlay
|
|
||||||
build: false
|
|
||||||
install_overlay_dependencies: &install_overlay_dependencies
|
|
||||||
install_dependencies:
|
|
||||||
underlay: /opt/underlay_ws
|
|
||||||
workspace: /opt/overlay_ws
|
|
||||||
setup_overlay_workspace: &setup_overlay_workspace
|
|
||||||
setup_workspace: &setup_workspace_overlay
|
|
||||||
key: overlay_ws
|
|
||||||
underlay: /opt/underlay_ws
|
|
||||||
workspace: /opt/overlay_ws
|
|
||||||
mixins: ${OVERLAY_MIXINS}
|
|
||||||
restore_overlay_workspace: &restore_overlay_workspace
|
|
||||||
setup_workspace:
|
|
||||||
<<: *setup_workspace_overlay
|
|
||||||
build: false
|
|
||||||
test_overlay_workspace: &test_overlay_workspace
|
|
||||||
test_workspace:
|
|
||||||
key: overlay_ws
|
|
||||||
workspace: /opt/overlay_ws
|
|
||||||
cache_test: << parameters.cache_test >>
|
|
||||||
collect_overlay_coverage: &collect_overlay_coverage
|
|
||||||
run:
|
|
||||||
name: Collect Code Coverage
|
|
||||||
working_directory: /opt/overlay_ws
|
|
||||||
command: src/navigation2/tools/code_coverage_report.bash ci
|
|
||||||
when: always
|
|
||||||
upload_overlay_coverage: &upload_overlay_coverage
|
|
||||||
run:
|
|
||||||
name: Upload Code Coverage
|
|
||||||
working_directory: /opt/overlay_ws
|
|
||||||
command: |
|
|
||||||
curl -s https://codecov.io/bash > codecov
|
|
||||||
codecov_version=$(grep -o 'VERSION=\"[0-9\.]*\"' codecov | cut -d'"' -f2)
|
|
||||||
shasum -a 512 -c <(curl -s "https://raw.githubusercontent.com/codecov/codecov-bash/${codecov_version}/SHA512SUM" | grep -w "codecov")
|
|
||||||
bash codecov \
|
|
||||||
-f "lcov/total_coverage.info" \
|
|
||||||
-R "src/navigation2" \
|
|
||||||
-n "$RMW_IMPLEMENTATION" \
|
|
||||||
-Z || echo 'Codecov upload failed'
|
|
||||||
when: always
|
|
||||||
|
|
||||||
commands:
|
|
||||||
<<: *common_commands
|
|
||||||
checkout_source:
|
|
||||||
description: "Checkout Source"
|
|
||||||
steps:
|
|
||||||
- *pre_checkout
|
|
||||||
- *on_checkout
|
|
||||||
- *post_checkout
|
|
||||||
setup_dependencies:
|
|
||||||
description: "Setup Dependencies"
|
|
||||||
steps:
|
|
||||||
- *install_underlay_dependencies
|
|
||||||
- *setup_underlay_workspace
|
|
||||||
- *install_overlay_dependencies
|
|
||||||
build_source:
|
|
||||||
description: "Build Source"
|
|
||||||
steps:
|
|
||||||
- *setup_overlay_workspace
|
|
||||||
restore_build:
|
|
||||||
description: "Restore Build"
|
|
||||||
steps:
|
|
||||||
- checkout_source
|
|
||||||
- *install_underlay_dependencies
|
|
||||||
- *restore_underlay_workspace
|
|
||||||
- *install_overlay_dependencies
|
|
||||||
- *restore_overlay_workspace
|
|
||||||
test_build:
|
|
||||||
description: "Test Build"
|
|
||||||
parameters:
|
|
||||||
cache_test:
|
|
||||||
type: boolean
|
|
||||||
steps:
|
|
||||||
- *test_overlay_workspace
|
|
||||||
report_coverage:
|
|
||||||
description: "Report Coverage"
|
|
||||||
steps:
|
|
||||||
- *collect_overlay_coverage
|
|
||||||
- *upload_overlay_coverage
|
|
||||||
|
|
||||||
_environments:
|
|
||||||
common_environment: &common_environment
|
|
||||||
ROS_WS: "/opt/ros_ws"
|
|
||||||
UNDERLAY_WS: "/opt/underlay_ws"
|
|
||||||
OVERLAY_WS: "/opt/overlay_ws"
|
|
||||||
UNDERLAY_MIXINS: "release ccache lld"
|
|
||||||
CCACHE_LOGFILE: "/tmp/ccache.log"
|
|
||||||
CCACHE_MAXSIZE: "200M"
|
|
||||||
MAKEFLAGS: "-j 2 -l 2 "
|
|
||||||
COLCON_DEFAULTS_FILE: "/tmp/defaults.yaml"
|
|
||||||
RCUTILS_LOGGING_BUFFERED_STREAM: "0"
|
|
||||||
RCUTILS_LOGGING_USE_STDOUT: "0"
|
|
||||||
DEBIAN_FRONTEND: "noninteractive"
|
|
||||||
PYTHONUNBUFFERED: "1"
|
|
||||||
|
|
||||||
executors:
|
|
||||||
release_exec:
|
|
||||||
docker:
|
|
||||||
- image: ghcr.io/ros-navigation/navigation2:humble
|
|
||||||
resource_class: large
|
|
||||||
working_directory: /opt/overlay_ws
|
|
||||||
environment:
|
|
||||||
<<: *common_environment
|
|
||||||
CACHE_NONCE: "Release"
|
|
||||||
OVERLAY_MIXINS: "release ccache coverage-gcc lld"
|
|
||||||
|
|
||||||
_jobs:
|
|
||||||
job_test: &job_test
|
|
||||||
parameters:
|
|
||||||
cache_test:
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
rmw:
|
|
||||||
default: "rmw_cyclonedds_cpp"
|
|
||||||
type: string
|
|
||||||
parallelism: 1
|
|
||||||
environment:
|
|
||||||
RMW_IMPLEMENTATION: << parameters.rmw >>
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release_build: &release_build
|
|
||||||
executor: release_exec
|
|
||||||
steps:
|
|
||||||
- checkout_source
|
|
||||||
- setup_dependencies
|
|
||||||
- build_source
|
|
||||||
release_test: &release_test
|
|
||||||
<<: *job_test
|
|
||||||
executor: release_exec
|
|
||||||
steps:
|
|
||||||
- restore_build
|
|
||||||
- test_build:
|
|
||||||
cache_test: << parameters.cache_test >>
|
|
||||||
- report_coverage
|
|
||||||
|
|
||||||
workflows:
|
|
||||||
version: 2
|
|
||||||
build_and_test:
|
|
||||||
jobs:
|
|
||||||
- release_build
|
|
||||||
- release_test:
|
|
||||||
requires:
|
|
||||||
- release_build
|
|
||||||
cache_test: true
|
|
||||||
nightly:
|
|
||||||
jobs:
|
|
||||||
- release_build
|
|
||||||
- release_test:
|
|
||||||
requires:
|
|
||||||
- release_build
|
|
||||||
matrix:
|
|
||||||
parameters:
|
|
||||||
rmw:
|
|
||||||
- rmw_connextdds
|
|
||||||
- rmw_cyclonedds_cpp
|
|
||||||
- rmw_fastrtps_cpp
|
|
||||||
triggers:
|
|
||||||
- schedule:
|
|
||||||
cron: "0 13 * * *"
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- main
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
_common: &common
|
|
||||||
"test-result-base": "test_results"
|
|
||||||
|
|
||||||
"clean.packages":
|
|
||||||
<<: *common
|
|
||||||
"build":
|
|
||||||
<<: *common
|
|
||||||
"executor": "parallel"
|
|
||||||
"parallel-workers": 4
|
|
||||||
"symlink-install": true
|
|
||||||
"test":
|
|
||||||
<<: *common
|
|
||||||
"executor": "parallel"
|
|
||||||
"parallel-workers": 1
|
|
||||||
"test-result":
|
|
||||||
<<: *common
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
# Snippet for global matchers and variables
|
|
||||||
# to logically expression request conditions
|
|
||||||
# E.g. for conditionally changing redirects
|
|
||||||
(globals) {
|
|
||||||
# Use gzip compression for all responses
|
|
||||||
encode gzip
|
|
||||||
|
|
||||||
# Matcher for http request scheme. E.g. "http" or "https"
|
|
||||||
@http_scheme {
|
|
||||||
expression {http.request.scheme}=="https" || {header.X-Forwarded-Scheme}=="https" || {header.X-Forwarded-Proto}=="https"
|
|
||||||
}
|
|
||||||
# If any http scheme is "https", then use "wss"
|
|
||||||
vars @http_scheme WsScheme "wss"
|
|
||||||
# Else default to "ws"
|
|
||||||
vars WsScheme "ws"
|
|
||||||
|
|
||||||
# Matcher for forwarded request headers
|
|
||||||
@host_forwarded {
|
|
||||||
header X-Forwarded-Host *
|
|
||||||
}
|
|
||||||
# If http headers exists, then use them
|
|
||||||
vars @host_forwarded ReqHost {header.X-Forwarded-Host}
|
|
||||||
# Else default to host in request
|
|
||||||
vars ReqHost {http.request.hostport}
|
|
||||||
|
|
||||||
# Matcher for websocket connection upgrade requests
|
|
||||||
@websockets {
|
|
||||||
# Avoid case sensitivity issues when matching field values
|
|
||||||
# E.g. when values are rewritten by Codespace port forwarding
|
|
||||||
header_regexp Connection (?i)(Upgrade)
|
|
||||||
header Upgrade websocket
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Snippet for redirect with given URL queries values
|
|
||||||
# to simplify remote development with web apps
|
|
||||||
# E.g auto redirect websocket URL to match request scheme
|
|
||||||
(redirect) {
|
|
||||||
# Configure redirect to match request scheme
|
|
||||||
vars LayoutUrl "/assets/foxglove/nav2_layout.json"
|
|
||||||
vars DataSourceUrl "{vars.WsScheme}://{vars.ReqHost}{args.0}/"
|
|
||||||
redir /autoconnect "{args.0}/?ds=foxglove-websocket&ds.url={vars.DataSourceUrl}"
|
|
||||||
redir /autolayout "{args.0}/?ds=foxglove-websocket&ds.url={vars.DataSourceUrl}&layoutUrl={vars.LayoutUrl}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Snippet for dummy imports
|
|
||||||
(dummy) {
|
|
||||||
}
|
|
||||||
|
|
||||||
# Snippet for enabling mobile web app features
|
|
||||||
# to improve user experience on small screen devices
|
|
||||||
# E.g. for enabling fullscreen mode on iOS and Android
|
|
||||||
(mobile) {
|
|
||||||
# Match for directory redirects to index.html
|
|
||||||
route / {
|
|
||||||
# Inject link to manifest just after <head> tag
|
|
||||||
# https://developer.mozilla.org/docs/Web/Manifest
|
|
||||||
replace `<head>` `<head><link rel="manifest" href="manifest.json" crossorigin="use-credentials"/>`
|
|
||||||
}
|
|
||||||
# Redirect relative handle_path'ed manifest.json to /manifests directory
|
|
||||||
redir /manifest.json /assets{http.request.orig_uri.path.dir}manifest.json
|
|
||||||
}
|
|
||||||
|
|
||||||
# Snippet for hosted web app using websockets
|
|
||||||
# to serve static files and reverse proxying connections
|
|
||||||
# E.g. for serving GzWeb and Foxglove web apps
|
|
||||||
(app) {
|
|
||||||
# handle and strip path prefix from redirect
|
|
||||||
handle_path {args.0}/* {
|
|
||||||
# Set root directory for static files
|
|
||||||
root * {http.vars.root}{args.0}
|
|
||||||
# Enable mobile web app features
|
|
||||||
import mobile
|
|
||||||
# Reverse proxy websockets to backend address
|
|
||||||
reverse_proxy @websockets {args.1}
|
|
||||||
# Import custom snippets
|
|
||||||
import {args.2} {args.0}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Listen for http requests on port 8080
|
|
||||||
# regardless of hostname or domain address
|
|
||||||
# E.g. whatever Codespaces assigns to host
|
|
||||||
:8080 {
|
|
||||||
# Include global matchers and variables
|
|
||||||
import globals
|
|
||||||
root * {$ROOT_SRV:/srv}
|
|
||||||
file_server browse
|
|
||||||
|
|
||||||
# Handle root content
|
|
||||||
# I.e. assets internal to workspace
|
|
||||||
handle /* {
|
|
||||||
# Template manifest.json files
|
|
||||||
templates */manifest.json {
|
|
||||||
mime application/json
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Handle nav2 web app
|
|
||||||
# I.e. main landing page
|
|
||||||
handle_path /nav2/* {
|
|
||||||
root * {http.vars.root}/nav2
|
|
||||||
import mobile
|
|
||||||
# Render markdown files as html
|
|
||||||
templates
|
|
||||||
}
|
|
||||||
|
|
||||||
# Matcher for requests without browse query
|
|
||||||
@no_browse {
|
|
||||||
path /
|
|
||||||
not query browse=true
|
|
||||||
}
|
|
||||||
# Redirect to nav2 web app by default
|
|
||||||
redir @no_browse /nav2/
|
|
||||||
|
|
||||||
# Import app snippets for web apps
|
|
||||||
import app "/gzweb" "localhost:9090" "dummy"
|
|
||||||
import app "/foxglove" "localhost:8765" "redirect"
|
|
||||||
|
|
||||||
# Handle glances web app
|
|
||||||
redir /glances /glances/
|
|
||||||
handle_path /glances/* {
|
|
||||||
import mobile
|
|
||||||
# Reverse proxy to glances backend
|
|
||||||
reverse_proxy * "localhost:61208"
|
|
||||||
}
|
|
||||||
|
|
||||||
# For debugging
|
|
||||||
# log {
|
|
||||||
# output file /var/log/caddy/server.log
|
|
||||||
# }
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Foxglove: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"short_name": "Foxglove: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/media/icons/foxglove/any_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "any"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/media/icons/foxglove/maskable_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "maskable"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "/foxglove/",
|
|
||||||
"start_url": "/foxglove/autoconnect",
|
|
||||||
"theme_color": "#6F3BE8",
|
|
||||||
"background_color": "#6F3BE8",
|
|
||||||
"display": "fullscreen",
|
|
||||||
"shortcuts" : [
|
|
||||||
{
|
|
||||||
"name": "Auto Connect",
|
|
||||||
"url": "/foxglove/autoconnect",
|
|
||||||
"description": "Auto connect to default data source"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Auto Layout",
|
|
||||||
"url": "/foxglove/autolayout",
|
|
||||||
"description": "Auto connect using default layout"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Manual Connect",
|
|
||||||
"url": "/foxglove/",
|
|
||||||
"description": "Manually connect to data source"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,463 +0,0 @@
|
|||||||
{
|
|
||||||
"configById": {
|
|
||||||
"3D!18i6zy7": {
|
|
||||||
"layers": {
|
|
||||||
"845139cb-26bc-40b3-8161-8ab60af4baf5": {
|
|
||||||
"visible": true,
|
|
||||||
"frameLocked": true,
|
|
||||||
"label": "Grid",
|
|
||||||
"instanceId": "845139cb-26bc-40b3-8161-8ab60af4baf5",
|
|
||||||
"layerId": "foxglove.Grid",
|
|
||||||
"size": 10,
|
|
||||||
"divisions": 10,
|
|
||||||
"lineWidth": 1,
|
|
||||||
"color": "#A0A0A4ff",
|
|
||||||
"position": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"order": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cameraState": {
|
|
||||||
"perspective": true,
|
|
||||||
"distance": 21.05263157877764,
|
|
||||||
"phi": 38.925517117715195,
|
|
||||||
"thetaOffset": -138.92710744521386,
|
|
||||||
"targetOffset": [
|
|
||||||
-2.6847696124888896,
|
|
||||||
0.2191229688744439,
|
|
||||||
3.6086809432821955e-16
|
|
||||||
],
|
|
||||||
"target": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"targetOrientation": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"fovy": 45,
|
|
||||||
"near": 0.5,
|
|
||||||
"far": 5000
|
|
||||||
},
|
|
||||||
"followMode": "follow-pose",
|
|
||||||
"scene": {
|
|
||||||
"transforms": {
|
|
||||||
"showLabel": false,
|
|
||||||
"editable": false,
|
|
||||||
"labelSize": 0.049999999999999975,
|
|
||||||
"enablePreloading": false,
|
|
||||||
"lineWidth": 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transforms": {
|
|
||||||
"frame:camera_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_depth_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_depth_optical_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_rgb_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_rgb_optical_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:imu_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:caster_back_right_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:caster_back_left_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:odom": {
|
|
||||||
"visible": true
|
|
||||||
},
|
|
||||||
"frame:base_footprint": {
|
|
||||||
"visible": true
|
|
||||||
},
|
|
||||||
"frame:wheel_left_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:wheel_right_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:base_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:base_scan": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:map": {
|
|
||||||
"visible": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"topics": {
|
|
||||||
"/scan": {
|
|
||||||
"visible": true,
|
|
||||||
"colorField": "intensity",
|
|
||||||
"colorMode": "flat",
|
|
||||||
"colorMap": "turbo",
|
|
||||||
"pointSize": 5,
|
|
||||||
"flatColor": "#ff0000"
|
|
||||||
},
|
|
||||||
"/global_costmap/costmap": {
|
|
||||||
"visible": true,
|
|
||||||
"maxColor": "#E800174d",
|
|
||||||
"unknownColor": "#5700ff4d",
|
|
||||||
"minColor": "#ffffff4d",
|
|
||||||
"invalidColor": "#ff00ff4d",
|
|
||||||
"colorMode": "costmap",
|
|
||||||
"alpha": 0.3
|
|
||||||
},
|
|
||||||
"/global_costmap/obstacle_layer": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/global_costmap/voxel_marked_cloud": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/goal_pose": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_costmap/costmap": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_costmap/voxel_layer": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_costmap/clearing_endpoints": {
|
|
||||||
"visible": false,
|
|
||||||
"colorField": "x",
|
|
||||||
"colorMode": "colormap",
|
|
||||||
"colorMap": "turbo"
|
|
||||||
},
|
|
||||||
"/map": {
|
|
||||||
"visible": true,
|
|
||||||
"minColor": "#ffffff",
|
|
||||||
"maxColor": "#000000",
|
|
||||||
"unknownColor": "#708986ff",
|
|
||||||
"frameLocked": false,
|
|
||||||
"colorMode": "map"
|
|
||||||
},
|
|
||||||
"/amcl_pose": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_plan": {
|
|
||||||
"visible": true,
|
|
||||||
"lineWidth": 0.01,
|
|
||||||
"gradient": [
|
|
||||||
"#c8ff00c7",
|
|
||||||
"#00c8ffba"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"/plan": {
|
|
||||||
"visible": false,
|
|
||||||
"gradient": [
|
|
||||||
"rgba(124, 107, 255, 1)",
|
|
||||||
"#ff6b6b"
|
|
||||||
],
|
|
||||||
"lineWidth": 1
|
|
||||||
},
|
|
||||||
"/plan_smoothed": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/received_global_plan": {
|
|
||||||
"visible": true,
|
|
||||||
"gradient": [
|
|
||||||
"#ff0000c7",
|
|
||||||
"#6b70ffc2"
|
|
||||||
],
|
|
||||||
"lineWidth": 0.02,
|
|
||||||
"type": "line",
|
|
||||||
"arrowScale": [
|
|
||||||
0.02,
|
|
||||||
0.0015,
|
|
||||||
0.0015
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"/transformed_global_plan": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/robot_description": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/cost_cloud": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/initialpose": {
|
|
||||||
"visible": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publish": {
|
|
||||||
"type": "pose_estimate",
|
|
||||||
"poseTopic": "/move_base_simple/goal",
|
|
||||||
"pointTopic": "",
|
|
||||||
"poseEstimateTopic": "/initialpose",
|
|
||||||
"poseEstimateXDeviation": 0.5,
|
|
||||||
"poseEstimateYDeviation": 0.5,
|
|
||||||
"poseEstimateThetaDeviation": 0.26179939
|
|
||||||
},
|
|
||||||
"followTf": "map"
|
|
||||||
},
|
|
||||||
"DiagnosticSummary!3bo4e39": {
|
|
||||||
"minLevel": 0,
|
|
||||||
"pinnedIds": [],
|
|
||||||
"hardwareIdFilter": "",
|
|
||||||
"topicToRender": "/diagnostics",
|
|
||||||
"sortByLevel": true
|
|
||||||
},
|
|
||||||
"RosOut!1iib9dq": {
|
|
||||||
"searchTerms": [],
|
|
||||||
"minLogLevel": 1
|
|
||||||
},
|
|
||||||
"3D!2agiaqk": {
|
|
||||||
"layers": {
|
|
||||||
"845139cb-26bc-40b3-8161-8ab60af4baf5": {
|
|
||||||
"visible": false,
|
|
||||||
"frameLocked": true,
|
|
||||||
"label": "Grid",
|
|
||||||
"instanceId": "845139cb-26bc-40b3-8161-8ab60af4baf5",
|
|
||||||
"layerId": "foxglove.Grid",
|
|
||||||
"size": 10,
|
|
||||||
"divisions": 10,
|
|
||||||
"lineWidth": 1,
|
|
||||||
"color": "#A0A0A4ff",
|
|
||||||
"position": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"order": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cameraState": {
|
|
||||||
"perspective": true,
|
|
||||||
"distance": 4.078136514883917,
|
|
||||||
"phi": 56.068374260572,
|
|
||||||
"thetaOffset": 92.50000000000723,
|
|
||||||
"targetOffset": [
|
|
||||||
0.03816360663426963,
|
|
||||||
0.15755079607173259,
|
|
||||||
7.341598429161142e-18
|
|
||||||
],
|
|
||||||
"target": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"targetOrientation": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"fovy": 45,
|
|
||||||
"near": 0.5,
|
|
||||||
"far": 5000
|
|
||||||
},
|
|
||||||
"followMode": "follow-pose",
|
|
||||||
"scene": {
|
|
||||||
"transforms": {
|
|
||||||
"showLabel": true,
|
|
||||||
"editable": false,
|
|
||||||
"labelSize": 0.049999999999999975,
|
|
||||||
"enablePreloading": false,
|
|
||||||
"lineWidth": 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transforms": {
|
|
||||||
"frame:camera_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_depth_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_depth_optical_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_rgb_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:camera_rgb_optical_frame": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:imu_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:caster_back_right_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:caster_back_left_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:odom": {
|
|
||||||
"visible": true
|
|
||||||
},
|
|
||||||
"frame:base_footprint": {
|
|
||||||
"visible": true
|
|
||||||
},
|
|
||||||
"frame:wheel_left_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:wheel_right_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:base_link": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:base_scan": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"frame:map": {
|
|
||||||
"visible": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"topics": {
|
|
||||||
"/scan": {
|
|
||||||
"visible": true,
|
|
||||||
"colorField": "intensity",
|
|
||||||
"colorMode": "flat",
|
|
||||||
"colorMap": "turbo",
|
|
||||||
"pointSize": 5,
|
|
||||||
"flatColor": "#ff0000"
|
|
||||||
},
|
|
||||||
"/global_costmap/costmap": {
|
|
||||||
"visible": true,
|
|
||||||
"maxColor": "#E800174d",
|
|
||||||
"unknownColor": "#5700ff4d",
|
|
||||||
"minColor": "#ffffff4d",
|
|
||||||
"invalidColor": "#ff00ff4d",
|
|
||||||
"colorMode": "costmap",
|
|
||||||
"alpha": 0.3
|
|
||||||
},
|
|
||||||
"/global_costmap/obstacle_layer": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/global_costmap/voxel_marked_cloud": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/goal_pose": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_costmap/costmap": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_costmap/voxel_layer": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_costmap/clearing_endpoints": {
|
|
||||||
"visible": false,
|
|
||||||
"colorField": "x",
|
|
||||||
"colorMode": "colormap",
|
|
||||||
"colorMap": "turbo"
|
|
||||||
},
|
|
||||||
"/map": {
|
|
||||||
"visible": true,
|
|
||||||
"minColor": "#ffffff",
|
|
||||||
"maxColor": "#000000",
|
|
||||||
"unknownColor": "#708986ff",
|
|
||||||
"frameLocked": false,
|
|
||||||
"colorMode": "map"
|
|
||||||
},
|
|
||||||
"/amcl_pose": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/local_plan": {
|
|
||||||
"visible": true,
|
|
||||||
"lineWidth": 0.01,
|
|
||||||
"gradient": [
|
|
||||||
"#c8ff00c7",
|
|
||||||
"#00c8ffba"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"/plan": {
|
|
||||||
"visible": false,
|
|
||||||
"gradient": [
|
|
||||||
"rgba(124, 107, 255, 1)",
|
|
||||||
"#ff6b6b"
|
|
||||||
],
|
|
||||||
"lineWidth": 1
|
|
||||||
},
|
|
||||||
"/plan_smoothed": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/received_global_plan": {
|
|
||||||
"visible": true,
|
|
||||||
"gradient": [
|
|
||||||
"#ff0000c7",
|
|
||||||
"#6b70ffc2"
|
|
||||||
],
|
|
||||||
"lineWidth": 0.02,
|
|
||||||
"type": "line",
|
|
||||||
"arrowScale": [
|
|
||||||
0.02,
|
|
||||||
0.0015,
|
|
||||||
0.0015
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"/transformed_global_plan": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/robot_description": {
|
|
||||||
"visible": true
|
|
||||||
},
|
|
||||||
"/cost_cloud": {
|
|
||||||
"visible": false
|
|
||||||
},
|
|
||||||
"/initialpose": {
|
|
||||||
"visible": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publish": {
|
|
||||||
"type": "pose_estimate",
|
|
||||||
"poseTopic": "/move_base_simple/goal",
|
|
||||||
"pointTopic": "",
|
|
||||||
"poseEstimateTopic": "/initialpose",
|
|
||||||
"poseEstimateXDeviation": 0.5,
|
|
||||||
"poseEstimateYDeviation": 0.5,
|
|
||||||
"poseEstimateThetaDeviation": 0.26179939
|
|
||||||
},
|
|
||||||
"followTf": "base_link"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"globalVariables": {},
|
|
||||||
"userNodes": {},
|
|
||||||
"playbackConfig": {
|
|
||||||
"speed": 1
|
|
||||||
},
|
|
||||||
"layout": {
|
|
||||||
"first": "3D!18i6zy7",
|
|
||||||
"second": {
|
|
||||||
"first": "DiagnosticSummary!3bo4e39",
|
|
||||||
"second": {
|
|
||||||
"first": "RosOut!1iib9dq",
|
|
||||||
"second": "3D!2agiaqk",
|
|
||||||
"direction": "column"
|
|
||||||
},
|
|
||||||
"direction": "column",
|
|
||||||
"splitPercentage": 28.227360308285164
|
|
||||||
},
|
|
||||||
"direction": "row",
|
|
||||||
"splitPercentage": 74.87855655794587
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Glances: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"short_name": "Glances: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/media/icons/glances/any_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "any"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/media/icons/glances/maskable_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "maskable"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "/glances/",
|
|
||||||
"start_url": "/glances/",
|
|
||||||
"theme_color": "#2C363F",
|
|
||||||
"background_color": "#2C363F",
|
|
||||||
"display": "fullscreen",
|
|
||||||
"shortcuts" : [
|
|
||||||
{
|
|
||||||
"name": "Refresh 1sec",
|
|
||||||
"url": "/glances/1",
|
|
||||||
"description": "Refresh page every 1 second"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Refresh 5sec",
|
|
||||||
"url": "/glances/5",
|
|
||||||
"description": "Refresh page every 5 seconds"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Refresh 10sec",
|
|
||||||
"url": "/glances/10",
|
|
||||||
"description": "Refresh page every 10 seconds"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Gzweb: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"short_name": "Gzweb: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/media/icons/gzweb/any_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "any"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/media/icons/gzweb/maskable_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "maskable"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "/gzweb/",
|
|
||||||
"start_url": "/gzweb/",
|
|
||||||
"theme_color": "#ffffff",
|
|
||||||
"background_color": "#ffffff",
|
|
||||||
"display": "fullscreen"
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Nav2: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"short_name": "Nav2: {{placeholder "http.vars.ReqHost"}}",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "/media/icons/nav2/any_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "any"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "/media/icons/nav2/maskable_icon_x512.webp",
|
|
||||||
"sizes": "512x512",
|
|
||||||
"type": "image/webp",
|
|
||||||
"purpose": "maskable"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id": "/nav2/",
|
|
||||||
"start_url": "/nav2/",
|
|
||||||
"theme_color": "#ffffff",
|
|
||||||
"background_color": "#ffffff",
|
|
||||||
"display": "standalone"
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
{{$pathParts := splitList "/" .OriginalReq.URL.Path}}
|
|
||||||
{{$markdownFilename := default "index" (slice $pathParts 2 | join "/")}}
|
|
||||||
{{$markdownFilePath := printf "/%s.md" $markdownFilename}}
|
|
||||||
{{if not (fileExists $markdownFilePath)}}{{httpError 404}}{{end}}
|
|
||||||
{{$markdownFile := (include $markdownFilePath | splitFrontMatter)}}
|
|
||||||
{{$title := default $markdownFilename $markdownFile.Meta.title}}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui">
|
|
||||||
<title>{{$title}}</title>
|
|
||||||
<meta name="color-scheme" content="light dark">
|
|
||||||
<link rel="stylesheet" href="github-markdown.css">
|
|
||||||
<link rel="icon" type="image/webp" href="/media/icons/nav2/any_icon_x512.webp">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
box-sizing: border-box;
|
|
||||||
min-width: 200px;
|
|
||||||
max-width: 980px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 45px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
body {
|
|
||||||
background-color: #0d1117;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<article class="markdown-body">{{markdown $markdownFile.Body}}</article>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
{
|
|
||||||
"title": "Nav2 App"
|
|
||||||
}
|
|
||||||
## Progressive Web Apps
|
|
||||||
|
|
||||||
| PWAs | Shortcuts |
|
|
||||||
|-|-|
|
|
||||||
| [<img src="/media/icons/foxglove/any_icon_x512.webp" height="64">](/foxglove/autoconnect)<br>**Foxglove** | [**Auto Connect**](/foxglove/autoconnect)<br>[Auto Layout](/foxglove/autolayout)<br>[Manual](/foxglove/) |
|
|
||||||
| [<img src="/media/icons/gzweb/any_icon_x512.webp" height="64">](/gzweb/)<br>**Gzweb** | [**Auto Connect**](/gzweb/) |
|
|
||||||
| [<img src="/media/icons/glances/any_icon_x512.webp" height="64">](/glances/)<br>**Glances** | [**System Monitor**](/glances/)<br>[Refresh 1sec](/glances/1)<br>[Refresh 10sec](/glances/10) |
|
|
||||||
| [<img src="/media/icons/nav2/any_icon_x512.webp" height="64">](/nav2/)<br>**Nav2** | [**App Launcher**](/nav2/)<br>[File Browser](/?browse=true) |
|
|
||||||
|
|
||||||
## External Resources
|
|
||||||
|
|
||||||
For more related documentation:
|
|
||||||
|
|
||||||
- [Nav2 Documentation](https://navigation.ros.org)
|
|
||||||
- [Development Guides](https://navigation.ros.org/development_guides)
|
|
||||||
- [Dev Containers](https://navigation.ros.org/development_guides/devcontainer_docs)
|
|
||||||
|
|
||||||
## Session Info
|
|
||||||
|
|
||||||
Useful information about host server and remote client:
|
|
||||||
|
|
||||||
|Key | Value |
|
|
||||||
|-|-|
|
|
||||||
| Host | `{{.Host}}` |
|
|
||||||
| Remote IP | `{{placeholder "http.request.remote.host"}}` |
|
|
||||||
| Date | `{{now}}` |
|
|
||||||
|
|
||||||
### Server Diagnostics
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Websocket Debug</summary>
|
|
||||||
|
|
||||||
For troubleshooting websocket connections:
|
|
||||||
|
|
||||||
|Key | Value |
|
|
||||||
|-|-|
|
|
||||||
| `header.X-Forwarded-Host` | `{{placeholder "http.request.header.X-Forwarded-Host"}}` |
|
|
||||||
| `http.request.hostport` | `{{placeholder "http.request.hostport"}}` |
|
|
||||||
| `http.vars.ReqHost` | `{{placeholder "http.vars.ReqHost"}}` |
|
|
||||||
|
|
||||||
|Key | Value |
|
|
||||||
|-|-|
|
|
||||||
| `http.request.scheme` | `{{placeholder "http.request.scheme"}}` |
|
|
||||||
| `header.X-Forwarded-Scheme` | `{{placeholder "http.request.header.X-Forwarded-Scheme"}}` |
|
|
||||||
| `header.X-Forwarded-Proto` | `{{placeholder "http.request.header.X-Forwarded-Proto"}}` |
|
|
||||||
| `http.vars.WsScheme` | `{{placeholder "http.vars.WsScheme"}}` |
|
|
||||||
|
|
||||||
</details>
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Nav2",
|
|
||||||
"build": {
|
|
||||||
"dockerfile": "../Dockerfile",
|
|
||||||
"context": "..",
|
|
||||||
"target": "visualizer",
|
|
||||||
"cacheFrom": "ghcr.io/ros-planning/navigation2:humble"
|
|
||||||
},
|
|
||||||
"runArgs": [
|
|
||||||
// "--cap-add=SYS_PTRACE", // enable debugging, e.g. gdb
|
|
||||||
// "--ipc=host", // shared memory transport with host, e.g. rviz GUIs
|
|
||||||
// "--network=host", // network access to host interfaces, e.g. eth0
|
|
||||||
// "--pid=host", // DDS discovery with host, without --network=host
|
|
||||||
// "--privileged", // device access to host peripherals, e.g. USB
|
|
||||||
// "--security-opt=seccomp=unconfined", // enable debugging, e.g. gdb
|
|
||||||
],
|
|
||||||
"workspaceFolder": "/opt/overlay_ws/src/navigation2",
|
|
||||||
"workspaceMount": "source=${localWorkspaceFolder},target=${containerWorkspaceFolder},type=bind",
|
|
||||||
"onCreateCommand": ".devcontainer/on-create-command.sh",
|
|
||||||
"updateContentCommand": ".devcontainer/update-content-command.sh",
|
|
||||||
"postCreateCommand": ".devcontainer/post-create-command.sh",
|
|
||||||
"remoteEnv": {
|
|
||||||
"OVERLAY_MIXINS": "release ccache lld",
|
|
||||||
"CCACHE_DIR": "/tmp/.ccache"
|
|
||||||
},
|
|
||||||
"mounts": [
|
|
||||||
{
|
|
||||||
"source": "ccache-${devcontainerId}",
|
|
||||||
"target": "/tmp/.ccache",
|
|
||||||
"type": "volume"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "overlay-${devcontainerId}",
|
|
||||||
"target": "/opt/overlay_ws",
|
|
||||||
"type": "volume"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"features": {
|
|
||||||
// "ghcr.io/devcontainers/features/desktop-lite:1": {},
|
|
||||||
"ghcr.io/devcontainers/features/github-cli:1": {}
|
|
||||||
},
|
|
||||||
"customizations": {
|
|
||||||
"codespaces": {
|
|
||||||
"openFiles": [
|
|
||||||
"doc/development/codespaces.md"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"vscode": {
|
|
||||||
"settings": {},
|
|
||||||
"extensions": [
|
|
||||||
"althack.ament-task-provider",
|
|
||||||
"eamodio.gitlens",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"GitHub.copilot",
|
|
||||||
"ms-iot.vscode-ros",
|
|
||||||
"streetsidesoftware.code-spell-checker",
|
|
||||||
"twxs.cmake"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Immediately catch all errors
|
|
||||||
set -eo pipefail
|
|
||||||
|
|
||||||
# Uncomment for debugging
|
|
||||||
# set -x
|
|
||||||
# env
|
|
||||||
|
|
||||||
git config --global --add safe.directory "*"
|
|
||||||
|
|
||||||
.devcontainer/update-content-command.sh
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Immediately catch all errors
|
|
||||||
set -eo pipefail
|
|
||||||
|
|
||||||
# Uncomment for debugging
|
|
||||||
# set -x
|
|
||||||
# env
|
|
||||||
|
|
||||||
# Enable autocomplete for user
|
|
||||||
cp /etc/skel/.bashrc ~/
|
|
||||||
|
|
||||||
# Check if srv folder exists
|
|
||||||
if [ -d "$ROOT_SRV" ]; then
|
|
||||||
# Setup Nav2 web app
|
|
||||||
for dir in $OVERLAY_WS/src/navigation2/.devcontainer/caddy/srv/*; \
|
|
||||||
do if [ -d "$dir" ]; then ln -s "$dir" $ROOT_SRV; fi done
|
|
||||||
fi
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Immediately catch all errors
|
|
||||||
set -eo pipefail
|
|
||||||
|
|
||||||
# Uncomment for debugging
|
|
||||||
# set -x
|
|
||||||
# env
|
|
||||||
|
|
||||||
cd $OVERLAY_WS
|
|
||||||
|
|
||||||
colcon cache lock
|
|
||||||
|
|
||||||
BUILD_UNFINISHED=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-skip-build-finished \
|
|
||||||
| xargs)
|
|
||||||
echo BUILD_UNFINISHED: $BUILD_UNFINISHED
|
|
||||||
|
|
||||||
BUILD_FAILED=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-select-build-failed \
|
|
||||||
| xargs)
|
|
||||||
echo BUILD_FAILED: $BUILD_FAILED
|
|
||||||
|
|
||||||
BUILD_INVALID=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-select-cache-invalid \
|
|
||||||
--packages-select-cache-key build \
|
|
||||||
| xargs)
|
|
||||||
echo BUILD_INVALID: $BUILD_INVALID
|
|
||||||
|
|
||||||
BUILD_PACKAGES=""
|
|
||||||
if [ -n "$BUILD_UNFINISHED" ] || \
|
|
||||||
[ -n "$BUILD_FAILED" ] || \
|
|
||||||
[ -n "$BUILD_INVALID" ]
|
|
||||||
then
|
|
||||||
BUILD_PACKAGES=$(
|
|
||||||
colcon list \
|
|
||||||
--names-only \
|
|
||||||
--packages-above \
|
|
||||||
$BUILD_UNFINISHED \
|
|
||||||
$BUILD_FAILED \
|
|
||||||
$BUILD_INVALID \
|
|
||||||
| xargs)
|
|
||||||
fi
|
|
||||||
echo BUILD_PACKAGES: $BUILD_PACKAGES
|
|
||||||
|
|
||||||
# colcon clean packages --yes \
|
|
||||||
# --packages-select ${BUILD_PACKAGES} \
|
|
||||||
# --base-select install
|
|
||||||
|
|
||||||
. $UNDERLAY_WS/install/setup.sh
|
|
||||||
colcon build \
|
|
||||||
--symlink-install \
|
|
||||||
--mixin $OVERLAY_MIXINS \
|
|
||||||
--packages-select ${BUILD_PACKAGES}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
################################################################################
|
|
||||||
# Repo
|
|
||||||
|
|
||||||
.circleci/
|
|
||||||
.devcontainer/
|
|
||||||
.dockerignore
|
|
||||||
.git/
|
|
||||||
.github/
|
|
||||||
.gitignore
|
|
||||||
**.Dockerfile
|
|
||||||
**Dockerfile
|
|
||||||
doc/
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<!--
|
|
||||||
For general questions, please ask on ROS answers: https://answers.ros.org, make sure to include at least the `ros2` tag and the rosdistro version you are running, e.g. `ardent`.
|
|
||||||
For general design discussions, please post on discourse: https://discourse.ros.org/c/ng-ros
|
|
||||||
Not sure if this is the right repository? Open an issue on https://github.com/ros-planning/navigation2
|
|
||||||
For Bug report or feature requests, please fill out the relevant category below
|
|
||||||
-->
|
|
||||||
|
|
||||||
## Bug report
|
|
||||||
|
|
||||||
**Required Info:**
|
|
||||||
|
|
||||||
- Operating System:
|
|
||||||
- <!-- OS and version (e.g. Windows 10, Ubuntu 16.04...) -->
|
|
||||||
- ROS2 Version:
|
|
||||||
- <!-- ROS2 distribution and install method (e.g. Foxy binaries, Dashing source...) -->
|
|
||||||
- Version or commit hash:
|
|
||||||
- <!-- from source: output of `git -C navigation2 rev-parse HEAD
|
|
||||||
apt binaries: output of: dpkg-query --show "ros-$ROS_DISTRO-navigation2"
|
|
||||||
or: dpkg-query --show "ros-$ROS_DISTRO-nav2-*" -->
|
|
||||||
- DDS implementation:
|
|
||||||
- <!-- rmw_implementation used (e.g. Fast-RTPS, RTI Connext, etc.) -->
|
|
||||||
|
|
||||||
#### Steps to reproduce issue
|
|
||||||
<!-- Detailed instructions on how to reliably reproduce this issue http://sscce.org/
|
|
||||||
``` code that can be copy-pasted is preferred ``` -->
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Expected behavior
|
|
||||||
|
|
||||||
#### Actual behavior
|
|
||||||
|
|
||||||
#### Additional information
|
|
||||||
|
|
||||||
<!-- If you are reporting a bug delete everything below
|
|
||||||
If you are requesting a feature deleted everything above this line -->
|
|
||||||
----
|
|
||||||
## Feature request
|
|
||||||
|
|
||||||
#### Feature description
|
|
||||||
<!-- Description in a few sentences what the feature consists of and what problem it will solve -->
|
|
||||||
|
|
||||||
#### Implementation considerations
|
|
||||||
<!-- Relevant information on how the feature could be implemented and pros and cons of the different solutions -->
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<!-- Please fill out the following pull request template for non-trivial changes to help us process your PR faster and more efficiently.-->
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Basic Info
|
|
||||||
|
|
||||||
| Info | Please fill out this column |
|
|
||||||
| ------ | ----------- |
|
|
||||||
| Ticket(s) this addresses | (add tickets here #1) |
|
|
||||||
| Primary OS tested on | (Ubuntu, MacOS, Windows) |
|
|
||||||
| Robotic platform tested on | (Steve's Robot, gazebo simulation of Tally, hardware turtlebot) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Description of contribution in a few bullet points
|
|
||||||
|
|
||||||
<!--
|
|
||||||
* I added this neat new feature
|
|
||||||
* Also fixed a typo in a parameter name in nav2_costmap_2d
|
|
||||||
-->
|
|
||||||
|
|
||||||
## Description of documentation updates required from your changes
|
|
||||||
|
|
||||||
<!--
|
|
||||||
* Added new parameter, so need to add that to default configs and documentation page
|
|
||||||
* I added some capabilities, need to document them
|
|
||||||
-->
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Future work that may be required in bullet points
|
|
||||||
|
|
||||||
<!--
|
|
||||||
* I think there might be some optimizations to be made from STL vector
|
|
||||||
* I see alot of redundancy in this package, we might want to add a function `bool XYZ()` to reduce clutter
|
|
||||||
* I tested on a differential drive robot, but there might be issues turning near corners on an omnidirectional platform
|
|
||||||
-->
|
|
||||||
|
|
||||||
#### For Maintainers: <!-- DO NOT EDIT OR REMOVE -->
|
|
||||||
- [ ] Check that any new parameters added are updated in navigation.ros.org
|
|
||||||
- [ ] Check that any significant change is added to the migration guide
|
|
||||||
- [ ] Check that any new features **OR** changes to existing behaviors are reflected in the tuning guide
|
|
||||||
- [ ] Check that any new functions have Doxygen added
|
|
||||||
- [ ] Check that any new features have test coverage
|
|
||||||
- [ ] Check that any new plugins is added to the plugins page
|
|
||||||
- [ ] If BT Node, Additionally: add to BT's XML index of nodes for groot, BT package's readme table, and BT library lists
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "docker"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
commit-message:
|
|
||||||
prefix: "🐳"
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
commit-message:
|
|
||||||
prefix: "🛠️"
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
pull_request_rules:
|
|
||||||
- name: backport to galactic at reviewers discretion
|
|
||||||
conditions:
|
|
||||||
- base=main
|
|
||||||
- "label=backport-galactic"
|
|
||||||
actions:
|
|
||||||
backport:
|
|
||||||
branches:
|
|
||||||
- galactic
|
|
||||||
|
|
||||||
- name: backport to foxy at reviewers discretion
|
|
||||||
conditions:
|
|
||||||
- base=main
|
|
||||||
- "label=backport-foxy"
|
|
||||||
actions:
|
|
||||||
backport:
|
|
||||||
branches:
|
|
||||||
- foxy-devel
|
|
||||||
|
|
||||||
- name: delete head branch after merge
|
|
||||||
conditions:
|
|
||||||
- merged
|
|
||||||
actions:
|
|
||||||
delete_head_branch:
|
|
||||||
|
|
||||||
- name: ask to resolve conflict
|
|
||||||
conditions:
|
|
||||||
- conflict
|
|
||||||
- author!=mergify
|
|
||||||
actions:
|
|
||||||
comment:
|
|
||||||
message: This pull request is in conflict. Could you fix it @{{author}}?
|
|
||||||
|
|
||||||
- name: development targets main branch
|
|
||||||
conditions:
|
|
||||||
- base!=main
|
|
||||||
- author!=SteveMacenski
|
|
||||||
- author!=mergify
|
|
||||||
actions:
|
|
||||||
comment:
|
|
||||||
message: |
|
|
||||||
@{{author}}, all pull requests must be targeted towards the `main` development branch.
|
|
||||||
Once merged into `main`, it is possible to backport to @{{base}}, but it must be in `main`
|
|
||||||
to have these changes reflected into new distributions.
|
|
||||||
|
|
||||||
- name: Main build failures
|
|
||||||
conditions:
|
|
||||||
- base=main
|
|
||||||
- or:
|
|
||||||
- "check-failure=ci/circleci: debug_build"
|
|
||||||
- "check-failure=ci/circleci: release_build"
|
|
||||||
actions:
|
|
||||||
comment:
|
|
||||||
message: |
|
|
||||||
@{{author}}, your PR has failed to build. Please check CI outputs and resolve issues.
|
|
||||||
You may need to rebase or pull in `main` due to API changes (or your contribution genuinely fails).
|
|
||||||
|
|
||||||
- name: Removed maintainer checklist
|
|
||||||
conditions:
|
|
||||||
- "-body~=^.*#### For Maintainers: <!-- DO NOT EDIT OR REMOVE -->.*$"
|
|
||||||
- author!=SteveMacenski
|
|
||||||
- author!=mergify
|
|
||||||
actions:
|
|
||||||
comment:
|
|
||||||
message: |
|
|
||||||
@{{author}}, please properly fill in PR template in the future. @stevemacenski, use this instead.
|
|
||||||
- [ ] Check that any new parameters added are updated in navigation.ros.org
|
|
||||||
- [ ] Check that any significant change is added to the migration guide
|
|
||||||
- [ ] Check that any new features **OR** changes to existing behaviors are reflected in the tuning guide
|
|
||||||
- [ ] Check that any new functions have Doxygen added
|
|
||||||
- [ ] Check that any new features have test coverage
|
|
||||||
- [ ] Check that any new plugins is added to the plugins page
|
|
||||||
- [ ] If BT Node, Additionally: add to BT's XML index of nodes for groot, BT package's readme table, and BT library lists
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
---
|
|
||||||
name: Update CI Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
# 7am UTC, 12am PDT
|
|
||||||
- cron: '0 7 * * *'
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- jazzy
|
|
||||||
- humble
|
|
||||||
paths:
|
|
||||||
- '**/package.xml'
|
|
||||||
- '**/*.repos'
|
|
||||||
- 'Dockerfile'
|
|
||||||
- '.github/workflows/update_ci_image.yaml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_ci_files:
|
|
||||||
name: Check CI Files
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
trigger: ${{ steps.check.outputs.trigger }}
|
|
||||||
no_cache: ${{ steps.check.outputs.no_cache }}
|
|
||||||
steps:
|
|
||||||
- name: "Check package updates"
|
|
||||||
id: check
|
|
||||||
if: github.event_name == 'push'
|
|
||||||
run: |
|
|
||||||
echo "trigger=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "no_cache=false" >> $GITHUB_OUTPUT
|
|
||||||
check_ci_image:
|
|
||||||
name: Check CI Image
|
|
||||||
if: github.event_name == 'schedule'
|
|
||||||
needs: check_ci_files
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
trigger: ${{ steps.check.outputs.trigger }}
|
|
||||||
no_cache: ${{ steps.check.outputs.no_cache }}
|
|
||||||
container:
|
|
||||||
image: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
|
||||||
steps:
|
|
||||||
- name: "Check apt updates"
|
|
||||||
id: check
|
|
||||||
env:
|
|
||||||
SOURCELIST: sources.list.d/ros2.list
|
|
||||||
run: |
|
|
||||||
apt-get update \
|
|
||||||
-o Dir::Etc::sourcelist="${SOURCELIST}"
|
|
||||||
apt-get --simulate upgrade \
|
|
||||||
-o Dir::Etc::sourcelist="${SOURCELIST}" \
|
|
||||||
> upgrade.log
|
|
||||||
cat upgrade.log
|
|
||||||
cat upgrade.log \
|
|
||||||
| grep "^0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.$" \
|
|
||||||
&& echo "trigger=false" >> $GITHUB_OUTPUT \
|
|
||||||
|| echo "trigger=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "no_cache=true" >> $GITHUB_OUTPUT
|
|
||||||
rebuild_ci_image:
|
|
||||||
name: Rebuild CI Image
|
|
||||||
if: always()
|
|
||||||
needs:
|
|
||||||
- check_ci_files
|
|
||||||
- check_ci_image
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Set build config
|
|
||||||
id: config
|
|
||||||
run: |
|
|
||||||
created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
echo "created=${created}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
version=$(grep -oP '(?<=<version>).*?(?=</version>)' navigation2/package.xml)
|
|
||||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
no_cache=false
|
|
||||||
if [ "${{needs.check_ci_files.outputs.no_cache}}" == 'true' ] || \
|
|
||||||
[ "${{needs.check_ci_image.outputs.no_cache}}" == 'true' ]
|
|
||||||
then
|
|
||||||
no_cache=true
|
|
||||||
fi
|
|
||||||
echo "no_cache=${no_cache}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
trigger=false
|
|
||||||
if [ "${{needs.check_ci_files.outputs.trigger}}" == 'true' ] || \
|
|
||||||
[ "${{needs.check_ci_image.outputs.trigger}}" == 'true' ]
|
|
||||||
then
|
|
||||||
trigger=true
|
|
||||||
fi
|
|
||||||
echo "trigger=${trigger}" >> $GITHUB_OUTPUT
|
|
||||||
- name: Build and push ${{ github.ref_name }}
|
|
||||||
if: steps.config.outputs.trigger == 'true'
|
|
||||||
id: docker_build
|
|
||||||
uses: docker/build-push-action@v3
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
pull: true
|
|
||||||
push: true
|
|
||||||
provenance: false
|
|
||||||
no-cache: ${{ steps.config.outputs.no_cache }}
|
|
||||||
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
|
||||||
cache-to: type=inline
|
|
||||||
target: builder
|
|
||||||
tags: |
|
|
||||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
|
||||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }}-${{ steps.config.outputs.version }}
|
|
||||||
labels: |
|
|
||||||
org.opencontainers.image.authors=${{ github.event.repository.owner.html_url }}
|
|
||||||
org.opencontainers.image.created=${{ steps.config.outputs.created }}
|
|
||||||
org.opencontainers.image.description=${{ github.event.repository.description }}
|
|
||||||
org.opencontainers.image.documentation=${{ github.event.repository.homepage }}
|
|
||||||
org.opencontainers.image.licenses=${{ github.event.repository.license.spdx_id }}
|
|
||||||
org.opencontainers.image.ref.name=${{ github.ref }}
|
|
||||||
org.opencontainers.image.revision=${{ github.sha }}
|
|
||||||
org.opencontainers.image.source=${{ github.event.repository.clone_url }}
|
|
||||||
org.opencontainers.image.title=${{ github.event.repository.name }}
|
|
||||||
org.opencontainers.image.url=${{ github.event.repository.html_url }}
|
|
||||||
org.opencontainers.image.vendor=${{ github.event.repository.owner.login }}
|
|
||||||
org.opencontainers.image.version=${{ steps.config.outputs.version }}
|
|
||||||
- name: Image digest
|
|
||||||
if: steps.config.outputs.trigger == 'true'
|
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# Compiled Object files
|
|
||||||
*.slo
|
|
||||||
*.lo
|
|
||||||
*.o
|
|
||||||
*.obj
|
|
||||||
|
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
|
||||||
|
|
||||||
# Compiled Dynamic libraries
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
*.dll
|
|
||||||
|
|
||||||
# Fortran module files
|
|
||||||
*.mod
|
|
||||||
*.smod
|
|
||||||
|
|
||||||
# Compiled Static libraries
|
|
||||||
*.lai
|
|
||||||
*.la
|
|
||||||
*.a
|
|
||||||
*.lib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
|
|
||||||
# Colcon output
|
|
||||||
build
|
|
||||||
log
|
|
||||||
install
|
|
||||||
|
|
||||||
# Visual Studio Code files
|
|
||||||
.vscode
|
|
||||||
|
|
||||||
# Eclipse project files
|
|
||||||
.cproject
|
|
||||||
.project
|
|
||||||
.pydevproject
|
|
||||||
|
|
||||||
# Python artifacts
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
sphinx_doc/_build
|
|
||||||
|
|
||||||
# CLion artifacts
|
|
||||||
.idea
|
|
||||||
cmake-build-debug/
|
|
||||||
|
|
||||||
# doxygen docs
|
|
||||||
doc/html/
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
# This dockerfile can be configured via --build-arg
|
|
||||||
# Build context must be the /navigation2 root folder for COPY.
|
|
||||||
# Example build command:
|
|
||||||
# export UNDERLAY_MIXINS="debug ccache lld"
|
|
||||||
# export OVERLAY_MIXINS="debug ccache coverage-gcc lld"
|
|
||||||
# docker build -t nav2:latest \
|
|
||||||
# --build-arg UNDERLAY_MIXINS \
|
|
||||||
# --build-arg OVERLAY_MIXINS ./
|
|
||||||
ARG FROM_IMAGE=ros:humble
|
|
||||||
ARG UNDERLAY_WS=/opt/underlay_ws
|
|
||||||
ARG OVERLAY_WS=/opt/overlay_ws
|
|
||||||
|
|
||||||
# multi-stage for caching
|
|
||||||
FROM $FROM_IMAGE AS cacher
|
|
||||||
|
|
||||||
# clone underlay source
|
|
||||||
ARG UNDERLAY_WS
|
|
||||||
WORKDIR $UNDERLAY_WS/src
|
|
||||||
COPY ./tools/underlay.repos ../
|
|
||||||
RUN vcs import ./ < ../underlay.repos
|
|
||||||
|
|
||||||
# copy overlay source
|
|
||||||
ARG OVERLAY_WS
|
|
||||||
WORKDIR $OVERLAY_WS/src
|
|
||||||
COPY ./ ./navigation2
|
|
||||||
|
|
||||||
# copy manifests for caching
|
|
||||||
WORKDIR /opt
|
|
||||||
RUN find . -name "src" -type d \
|
|
||||||
-mindepth 1 -maxdepth 2 -printf '%P\n' \
|
|
||||||
| xargs -I % mkdir -p /tmp/opt/% && \
|
|
||||||
find . -name "package.xml" \
|
|
||||||
| xargs cp --parents -t /tmp/opt && \
|
|
||||||
find . -name "COLCON_IGNORE" \
|
|
||||||
| xargs cp --parents -t /tmp/opt || true
|
|
||||||
|
|
||||||
# multi-stage for building
|
|
||||||
FROM $FROM_IMAGE AS builder
|
|
||||||
|
|
||||||
# config dependencies install
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
|
||||||
RUN echo '\
|
|
||||||
APT::Install-Recommends "0";\n\
|
|
||||||
APT::Install-Suggests "0";\n\
|
|
||||||
' > /etc/apt/apt.conf.d/01norecommend
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
|
||||||
|
|
||||||
# install CI dependencies
|
|
||||||
ARG RTI_NC_LICENSE_ACCEPTED=yes
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get upgrade -y --with-new-pkgs && \
|
|
||||||
apt-get install -y \
|
|
||||||
ccache \
|
|
||||||
lcov \
|
|
||||||
lld \
|
|
||||||
python3-pip \
|
|
||||||
ros-$ROS_DISTRO-rmw-fastrtps-cpp \
|
|
||||||
ros-$ROS_DISTRO-rmw-connextdds \
|
|
||||||
ros-$ROS_DISTRO-rmw-cyclonedds-cpp \
|
|
||||||
&& pip3 install \
|
|
||||||
fastcov \
|
|
||||||
git+https://github.com/ruffsl/colcon-cache.git@a937541bfc496c7a267db7ee9d6cceca61e470ca \
|
|
||||||
git+https://github.com/ruffsl/colcon-clean.git@a7f1074d1ebc1a54a6508625b117974f2672f2a9 \
|
|
||||||
&& rosdep update \
|
|
||||||
&& colcon mixin update \
|
|
||||||
&& colcon metadata update \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# install underlay dependencies
|
|
||||||
ARG UNDERLAY_WS
|
|
||||||
ENV UNDERLAY_WS $UNDERLAY_WS
|
|
||||||
WORKDIR $UNDERLAY_WS
|
|
||||||
COPY --from=cacher /tmp/$UNDERLAY_WS ./
|
|
||||||
RUN . /opt/ros/$ROS_DISTRO/setup.sh && \
|
|
||||||
apt-get update && rosdep install -q -y \
|
|
||||||
--from-paths src \
|
|
||||||
--skip-keys " \
|
|
||||||
slam_toolbox \
|
|
||||||
" \
|
|
||||||
--ignore-src \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# build underlay source
|
|
||||||
COPY --from=cacher $UNDERLAY_WS ./
|
|
||||||
ARG UNDERLAY_MIXINS="release ccache lld"
|
|
||||||
ARG CCACHE_DIR="$UNDERLAY_WS/.ccache"
|
|
||||||
RUN . /opt/ros/$ROS_DISTRO/setup.sh && \
|
|
||||||
colcon cache lock && \
|
|
||||||
colcon build \
|
|
||||||
--symlink-install \
|
|
||||||
--mixin $UNDERLAY_MIXINS \
|
|
||||||
--event-handlers console_direct+
|
|
||||||
|
|
||||||
# install overlay dependencies
|
|
||||||
ARG OVERLAY_WS
|
|
||||||
ENV OVERLAY_WS $OVERLAY_WS
|
|
||||||
WORKDIR $OVERLAY_WS
|
|
||||||
COPY --from=cacher /tmp/$OVERLAY_WS ./
|
|
||||||
RUN . $UNDERLAY_WS/install/setup.sh && \
|
|
||||||
apt-get update && rosdep install -q -y \
|
|
||||||
--from-paths src \
|
|
||||||
--skip-keys " \
|
|
||||||
slam_toolbox \
|
|
||||||
"\
|
|
||||||
--ignore-src \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# multi-stage for testing
|
|
||||||
FROM builder AS tester
|
|
||||||
|
|
||||||
# build overlay source
|
|
||||||
COPY --from=cacher $OVERLAY_WS ./
|
|
||||||
ARG OVERLAY_MIXINS="release ccache lld"
|
|
||||||
ARG CCACHE_DIR="$OVERLAY_WS/.ccache"
|
|
||||||
RUN . $UNDERLAY_WS/install/setup.sh && \
|
|
||||||
colcon cache lock && \
|
|
||||||
colcon build \
|
|
||||||
--symlink-install \
|
|
||||||
--mixin $OVERLAY_MIXINS
|
|
||||||
|
|
||||||
# source overlay from entrypoint
|
|
||||||
RUN sed --in-place \
|
|
||||||
's|^source .*|source "$OVERLAY_WS/install/setup.bash"|' \
|
|
||||||
/ros_entrypoint.sh
|
|
||||||
|
|
||||||
# test overlay build
|
|
||||||
ARG RUN_TESTS
|
|
||||||
ARG FAIL_ON_TEST_FAILURE
|
|
||||||
RUN if [ -n "$RUN_TESTS" ]; then \
|
|
||||||
. install/setup.sh && \
|
|
||||||
colcon test && \
|
|
||||||
colcon test-result \
|
|
||||||
|| ([ -z "$FAIL_ON_TEST_FAILURE" ] || exit 1) \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# multi-stage for developing
|
|
||||||
FROM builder AS dever
|
|
||||||
|
|
||||||
# edit apt for caching
|
|
||||||
RUN mv /etc/apt/apt.conf.d/docker-clean /etc/apt/
|
|
||||||
|
|
||||||
# install developer dependencies
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y \
|
|
||||||
bash-completion \
|
|
||||||
gdb \
|
|
||||||
wget && \
|
|
||||||
pip3 install \
|
|
||||||
bottle \
|
|
||||||
glances
|
|
||||||
|
|
||||||
# source underlay for shell
|
|
||||||
RUN echo 'source "$UNDERLAY_WS/install/setup.bash"' >> /etc/bash.bashrc
|
|
||||||
|
|
||||||
# multi-stage for caddy
|
|
||||||
FROM caddy:builder AS caddyer
|
|
||||||
|
|
||||||
# build custom modules
|
|
||||||
RUN xcaddy build \
|
|
||||||
--with github.com/caddyserver/replace-response
|
|
||||||
|
|
||||||
# multi-stage for visualizing
|
|
||||||
FROM dever AS visualizer
|
|
||||||
|
|
||||||
ENV ROOT_SRV /srv
|
|
||||||
RUN mkdir -p $ROOT_SRV
|
|
||||||
|
|
||||||
# install demo dependencies
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
ros-$ROS_DISTRO-aws-robomaker-small-warehouse-world \
|
|
||||||
ros-$ROS_DISTRO-rviz2 \
|
|
||||||
ros-$ROS_DISTRO-turtlebot3-simulations
|
|
||||||
|
|
||||||
# install gzweb dependacies
|
|
||||||
RUN apt-get install -y --no-install-recommends \
|
|
||||||
imagemagick \
|
|
||||||
libboost-all-dev \
|
|
||||||
libgazebo-dev \
|
|
||||||
libgts-dev \
|
|
||||||
libjansson-dev \
|
|
||||||
libtinyxml-dev \
|
|
||||||
nodejs \
|
|
||||||
npm \
|
|
||||||
psmisc \
|
|
||||||
xvfb
|
|
||||||
|
|
||||||
# clone gzweb
|
|
||||||
ENV GZWEB_WS /opt/gzweb
|
|
||||||
RUN git clone https://github.com/osrf/gzweb.git $GZWEB_WS
|
|
||||||
|
|
||||||
# setup gzweb
|
|
||||||
RUN cd $GZWEB_WS && . /usr/share/gazebo/setup.sh && \
|
|
||||||
GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:$(find /opt/ros/$ROS_DISTRO/share \
|
|
||||||
-mindepth 1 -maxdepth 2 -type d -name "models" | paste -s -d: -) && \
|
|
||||||
sed -i "s|var modelList =|var modelList = []; var oldModelList =|g" gz3d/src/gzgui.js && \
|
|
||||||
xvfb-run -s "-screen 0 1280x1024x24" ./deploy.sh -m local && \
|
|
||||||
ln -s $GZWEB_WS/http/client/assets http/client/assets/models && \
|
|
||||||
ln -s $GZWEB_WS/http/client $ROOT_SRV/gzweb
|
|
||||||
|
|
||||||
# patch gzsever
|
|
||||||
RUN GZSERVER=$(which gzserver) && \
|
|
||||||
mv $GZSERVER $GZSERVER.orig && \
|
|
||||||
echo '#!/bin/bash' > $GZSERVER && \
|
|
||||||
echo 'exec xvfb-run -s "-screen 0 1280x1024x24" gzserver.orig "$@"' >> $GZSERVER && \
|
|
||||||
chmod +x $GZSERVER
|
|
||||||
|
|
||||||
# install foxglove dependacies
|
|
||||||
RUN apt-get install -y --no-install-recommends \
|
|
||||||
ros-$ROS_DISTRO-foxglove-bridge
|
|
||||||
|
|
||||||
# setup foxglove
|
|
||||||
# Use custom fork until PR is merged:
|
|
||||||
# https://github.com/foxglove/studio/pull/5987
|
|
||||||
# COPY --from=ghcr.io/foxglove/studio /src $ROOT_SRV/foxglove
|
|
||||||
COPY --from=ghcr.io/ruffsl/foxglove_studio@sha256:8a2f2be0a95f24b76b0d7aa536f1c34f3e224022eed607cbf7a164928488332e /src $ROOT_SRV/foxglove
|
|
||||||
|
|
||||||
# install web server
|
|
||||||
COPY --from=caddyer /usr/bin/caddy /usr/bin/caddy
|
|
||||||
|
|
||||||
# download media files
|
|
||||||
RUN mkdir -p $ROOT_SRV/media && cd /tmp && \
|
|
||||||
export ICONS="icons.tar.gz" && wget https://github.com/ros-planning/navigation2/files/11506823/$ICONS && \
|
|
||||||
echo "cae5e2a5230f87b004c8232b579781edb4a72a7431405381403c6f9e9f5f7d41 $ICONS" | sha256sum -c && \
|
|
||||||
tar xvz -C $ROOT_SRV/media -f $ICONS && rm $ICONS
|
|
||||||
|
|
||||||
# multi-stage for exporting
|
|
||||||
FROM tester AS exporter
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
Portions of this repository are available under one of the following licenses
|
|
||||||
|
|
||||||
SPDX-ID:
|
|
||||||
* LGPL-2.1-or-later
|
|
||||||
* Apache-2.0
|
|
||||||
* BSD-3-Clause
|
|
||||||
* Apache-2.0 AND BSD-3-Clause
|
|
||||||
|
|
||||||
Please see the package.xml file for each package to see the specific license for
|
|
||||||
that package.
|
|
||||||
|
|
||||||
Contributions to existing files should be made under the license of that file.
|
|
||||||
New files should be made under the first license listed in the appropriate
|
|
||||||
package.xml file
|
|
||||||
|
|
||||||
For files that are not otherwise marked, they are provided under the Apache-2.0
|
|
||||||
license.
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
# Nav2
|
|
||||||
[](https://github.com/ros-planning/navigation2/actions/workflows/update_ci_image.yaml)
|
|
||||||
[](https://codecov.io/gh/ros-planning/navigation2)
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img height="300" src="doc/nav2_logo.png" />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
For detailed instructions on how to:
|
|
||||||
- [Getting Started](https://navigation.ros.org/getting_started/index.html)
|
|
||||||
- [Concepts](https://navigation.ros.org/concepts/index.html)
|
|
||||||
- [Build](https://navigation.ros.org/development_guides/build_docs/index.html#build)
|
|
||||||
- [Install](https://navigation.ros.org/development_guides/build_docs/index.html#install)
|
|
||||||
- [General Tutorials](https://navigation.ros.org/tutorials/index.html) and [Algorithm Developer Tutorials](https://navigation.ros.org/plugin_tutorials/index.html)
|
|
||||||
- [Configure](https://navigation.ros.org/configuration/index.html)
|
|
||||||
- [Navigation Plugins](https://navigation.ros.org/plugins/index.html)
|
|
||||||
- [Migration Guides](https://navigation.ros.org/migration/index.html)
|
|
||||||
- [Container Images for Building Nav2](https://github.com/orgs/ros-planning/packages/container/package/navigation2)
|
|
||||||
- [Contribute](https://navigation.ros.org/development_guides/involvement_docs/index.html)
|
|
||||||
|
|
||||||
Please visit our [documentation site](https://navigation.ros.org/). [Please visit our community Slack here](https://join.slack.com/t/navigation2/shared_invite/zt-hu52lnnq-cKYjuhTY~sEMbZXL8p9tOw) (if this link does not work, please contact maintainers to reactivate).
|
|
||||||
|
|
||||||
If you need professional services related to Nav2, please contact Open Navigation at info@opennav.org.
|
|
||||||
|
|
||||||
## Our Sponsors
|
|
||||||
|
|
||||||
Please thank our amazing sponsors for their generous support of Nav2 on behalf of the community to allow the project to continue to be professionally maintained, developed, and supported for the long-haul! [Open Navigation LLC](https://www.opennav.org/) provides project leadership, maintenance, development, and support services to the Nav2 & ROS community.
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img src="doc/sponsors_may_2023.png" />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
### [Dexory](https://www.dexory.com/) develops robotics and AI logistics solutions to drive better business decisions using a digital twin of warehouses to provide inventory insights.
|
|
||||||
|
|
||||||
### [Polymath Robotics](https://www.polymathrobotics.com/) creates safety-critical navigation systems for industrial vehicles that are radically simple to enable and deploy.
|
|
||||||
|
|
||||||
### [Stereolabs](https://www.stereolabs.com/) produces the high-quality ZED stereo cameras with a complete vision pipeline from neural depth to SLAM, 3D object tracking, AI and more.
|
|
||||||
|
|
||||||
### Confidential is just happy to support Nav2's mission!
|
|
||||||
|
|
||||||
|
|
||||||
## Citation
|
|
||||||
|
|
||||||
If you use the navigation framework, an algorithm from this repository, or ideas from it
|
|
||||||
please cite this work in your papers!
|
|
||||||
|
|
||||||
- S. Macenski, F. Martín, R. White, J. Clavero. [**The Marathon 2: A Navigation System**](https://arxiv.org/abs/2003.00368). IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS), 2020.
|
|
||||||
|
|
||||||
```bibtex
|
|
||||||
@InProceedings{macenski2020marathon2,
|
|
||||||
title = {The Marathon 2: A Navigation System},
|
|
||||||
author = {Macenski, Steve and Martín, Francisco and White, Ruffin and Ginés Clavero, Jonatan},
|
|
||||||
year = {2020},
|
|
||||||
booktitle = {2020 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
|
|
||||||
url = {https://github.com/ros-planning/navigation2},
|
|
||||||
pdf = {https://arxiv.org/abs/2003.00368}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you use our work on VSLAM and formal comparisons for service robot needs, please cite the paper:
|
|
||||||
|
|
||||||
- A. Merzlyakov, S. Macenski. [**A Comparison of Modern General-Purpose Visual SLAM Approaches**](https://arxiv.org/abs/2107.07589). IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS), 2021.
|
|
||||||
|
|
||||||
```bibtex
|
|
||||||
@InProceedings{vslamComparison2021,
|
|
||||||
title = {A Comparison of Modern General-Purpose Visual SLAM Approaches},
|
|
||||||
author = {Merzlyakov, Alexey and Macenski, Steven},
|
|
||||||
year = {2021},
|
|
||||||
booktitle = {2021 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)},
|
|
||||||
pdf = {https://arxiv.org/abs/2107.07589}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build Status
|
|
||||||
|
|
||||||
| Service | Foxy | Humble | Main |
|
|
||||||
| :---: | :---: | :---: | :---: |
|
|
||||||
| ROS Build Farm | [](http://build.ros2.org/job/Fdev__navigation2__ubuntu_focal_amd64/) | [](https://build.ros2.org/job/Hdev__navigation2__ubuntu_jammy_amd64/) | N/A |
|
|
||||||
| Circle CI | N/A | N/A | [](https://circleci.com/gh/ros-planning/navigation2/tree/main) |
|
|
||||||
|
|
||||||
|
|
||||||
| Package | Foxy Source | Foxy Debian | Humble Source | Humble Debian |
|
|
||||||
| :---: | :---: | :---: | :---: | :---: |
|
|
||||||
| Navigation2 | [](http://build.ros2.org/job/Fsrc_uF__navigation2__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__navigation2__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__navigation2__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__navigation2__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_amcl | [](http://build.ros2.org/job/Fsrc_uF__nav2_amcl__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_amcl__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_amcl__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_amcl__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_behavior_tree | [](http://build.ros2.org/job/Fsrc_uF__nav2_behavior_tree__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_behavior_tree__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_behavior_tree__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_behavior_tree__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_{recoveries, behaviors} | [](http://build.ros2.org/job/Fsrc_uF__nav2_recoveries__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_recoveries__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_behaviors__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_behaviors__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_bringup | [](http://build.ros2.org/job/Fsrc_uF__nav2_bringup__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_bringup__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_bringup__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_bringup__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_bt_navigator | [](http://build.ros2.org/job/Fsrc_uF__nav2_bt_navigator__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_bt_navigator__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_bt_navigator__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_bt_navigator__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_common | [](http://build.ros2.org/job/Fsrc_uF__nav2_common__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_common__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_common__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_common__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_constrained_smoother | N/A | N/A | N/A | N/A | [](https://build.ros2.org/job/Hsrc_uJ__nav2_constrained_smoother__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_constrained_smoother__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_controller | [](http://build.ros2.org/job/Fsrc_uF__nav2_controller__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_controller__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_controller__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_controller__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_core | [](http://build.ros2.org/job/Fsrc_uF__nav2_core__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_core__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_core__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_core__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_costmap_2d | [](http://build.ros2.org/job/Fsrc_uF__nav2_costmap_2d__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_costmap_2d__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_costmap_2d__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_costmap_2d__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_dwb_controller | [](http://build.ros2.org/job/Fsrc_uF__nav2_dwb_controller__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_dwb_controller__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_dwb_controller__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_dwb_controller__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_lifecycle_manager | [](http://build.ros2.org/job/Fsrc_uF__nav2_lifecycle_manager__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_lifecycle_manager__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_lifecycle_manager__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_lifecycle_manager__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_map_server | [](http://build.ros2.org/job/Fsrc_uF__nav2_map_server__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_map_server__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_map_server__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_map_server__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_msgs | [](http://build.ros2.org/job/Fsrc_uF__nav2_msgs__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_msgs__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_msgs__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_msgs__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_navfn_planner | [](http://build.ros2.org/job/Fsrc_uF__nav2_navfn_planner__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_navfn_planner__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_navfn_planner__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_navfn_planner__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_planner | [](http://build.ros2.org/job/Fsrc_uF__nav2_planner__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_planner__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_planner__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_planner__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_regulated_pure_pursuit | [](http://build.ros2.org/job/Fsrc_uF__nav2_regulated_pure_pursuit_controller__ubuntu_focal__source/) | [](https://build.ros2.org/job/Fbin_uF64__nav2_regulated_pure_pursuit_controller__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_regulated_pure_pursuit_controller__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_regulated_pure_pursuit_controller__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_rotation_shim_controller | N/A | N/A | N/A | N/A | [](https://build.ros2.org/job/Hsrc_uJ__nav2_rotation_shim_controller__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_rotation_shim_controller__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_rviz_plugins | [](http://build.ros2.org/job/Fsrc_uF__nav2_rviz_plugins__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_rviz_plugins__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_rviz_plugins__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_rviz_plugins__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_simple_commander | N/A | N/A | [](https://build.ros2.org/job/Hsrc_uJ__nav2_simple_commander__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_simple_commander__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_smac_planner | [](http://build.ros2.org/job/Fsrc_uF__smac_planner__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__smac_planner__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_smac_planner__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_smac_planner__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_smoother | N/A | N/A | N/A | N/A | [](https://build.ros2.org/job/Hsrc_uJ__nav2_smoother__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_smoother__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_system_tests | [](http://build.ros2.org/job/Fsrc_uF__nav2_system_tests__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_system_tests__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_system_tests__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_system_tests__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_theta_star_planner | N/A | N/A | [](https://build.ros2.org/job/Hsrc_uJ__nav2_theta_star_planner__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_theta_star_planner__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_util | [](http://build.ros2.org/job/Fsrc_uF__nav2_util__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_util__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_util__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_util__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_voxel_grid | [](https://build.ros2.org/job/Fsrc_uF__nav2_voxel_grid__ubuntu_focal__source/) | [](https://build.ros2.org/job/Fbin_uF64__nav2_voxel_grid__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_voxel_grid__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_voxel_grid__ubuntu_jammy_amd64__binary/) |
|
|
||||||
| nav2_waypoint_follower | [](http://build.ros2.org/job/Fsrc_uF__nav2_waypoint_follower__ubuntu_focal__source/) | [](http://build.ros2.org/job/Fbin_uF64__nav2_waypoint_follower__ubuntu_focal_amd64__binary/) | [](https://build.ros2.org/job/Hsrc_uJ__nav2_waypoint_follower__ubuntu_jammy__source/) | [](https://build.ros2.org/job/Hbin_uJ64__nav2_waypoint_follower__ubuntu_jammy_amd64__binary/) |
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
fixes:
|
|
||||||
- "src/navigation2/::"
|
|
||||||
- "install/::"
|
|
||||||
|
|
||||||
ignore:
|
|
||||||
- "*/**/test/*" # ignore package test directories, e.g. nav2_dwb_controller/costmap_queue/tests
|
|
||||||
- "*/test/**/*" # ignore package test directories, e.g. nav2_costmap_2d/tests
|
|
||||||
- "**/test_*.*" # ignore files starting with test_ e.g. nav2_map_server/test/test_constants.cpp
|
|
||||||
- "**/*_tests.*" # ignore files ending with _tests e.g. nav2_voxel_grid/test/voxel_grid_tests.cpp
|
|
||||||
- "*/**/benchmark/*" # ignore package test directories, e.g. nav2_dwb_controller/costmap_queue/tests
|
|
||||||
- "*/benchmark/**/*" # ignore package test directories, e.g. nav2_costmap_2d/tests
|
|
||||||
- "**/benchmark_*.*" # ignore files starting with test_ e.g. nav2_map_server/test/test_constants.cpp
|
|
||||||
- "**/*_benchmark.*" # ignore files ending with _tests e.g. nav2_voxel_grid/test/voxel_grid_tests.cpp
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# ROS2 Navigation System Documentation
|
|
||||||
This is where the ROS2 Navigation System documentation is being collected and vetted.
|
|
||||||
|
|
||||||
# Use Cases
|
|
||||||
See the [Use Cases README](use_cases/README.md) for info on our target use cases.
|
|
||||||
|
|
||||||
# Requirements
|
|
||||||
See the [Requirements document](requirements/requirements.md) for the current list of requirements.
|
|
||||||
|
|
||||||
# Design Overview
|
|
||||||
See the [Navigation 2 Overview](design/Navigation_2_Overview.pdf) file for the current design / architecture
|
|
||||||
|
|
||||||
# Differences from ROS Navigation
|
|
||||||
See the [ROS_COMPARISON](design/ROS_COMPARISON.md) file for an overview of the differences between this design and ROS1 Navigation (move_base)
|
|
||||||
|
|
||||||
# Contributing
|
|
||||||
To propose additions or changes to the design or requirements, please file an issue to initiate a discussion of the topic. Then, once the discussion has completed and the group has agreed to move forward on the item, you can submit a pull request and link to the issue.
|
|
||||||
|
Before Width: | Height: | Size: 376 KiB |
@@ -1,23 +0,0 @@
|
|||||||
# Codespaces
|
|
||||||
|
|
||||||
TODO: welcome and introduction
|
|
||||||
|
|
||||||
# Overview
|
|
||||||
|
|
||||||
TODO: document devcontainer
|
|
||||||
TODO: reference extensions
|
|
||||||
TODO: use of dockercompose and services
|
|
||||||
|
|
||||||
# Terminal
|
|
||||||
|
|
||||||
TODO: link to vscode terminal
|
|
||||||
|
|
||||||
# Graphics and Simulations
|
|
||||||
|
|
||||||
TODO: vnc options
|
|
||||||
TODO: foxglove example
|
|
||||||
TODO: gazebo example with gzweb
|
|
||||||
|
|
||||||
# References
|
|
||||||
|
|
||||||
TODO: links to more info
|
|
||||||
|
Before Width: | Height: | Size: 36 KiB |
@@ -1,65 +0,0 @@
|
|||||||
# Pre Release Checklist
|
|
||||||
|
|
||||||
This documents the steps to be taken prior to making a new release of the
|
|
||||||
nav2 stack.
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
1. `Ensure all dependencies are listed in the package.xml files` by doing a
|
|
||||||
build of all of ROS2, dependencies, and navigation 2 in one workspace.
|
|
||||||
|
|
||||||
2. `Ensure all dependencies are released.` by using rosdep to pull in dependencies instead of building them ourselves.
|
|
||||||
|
|
||||||
3. `Ensure the test suite passes`
|
|
||||||
|
|
||||||
## Detailed Steps
|
|
||||||
|
|
||||||
### Ensure all dependencies are listed in the package.xml files
|
|
||||||
|
|
||||||
We want to ensure that every package has a complete list of its dependencies
|
|
||||||
in the `package.xml` file. This can be done by not sourcing any ros `setup.bash` files. Instead we need to build everything as one big repo.
|
|
||||||
|
|
||||||
There is a docker file to do that, so run
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo docker build -t nav2:full_ros_build --build-arg ROS2_BRANCH=dashing --build-arg http_proxy=http://myproxy.example.com:80 --build-arg https_proxy=http://myproxy.example.com:80 -f Dockerfile.full_ros_build ./
|
|
||||||
```
|
|
||||||
|
|
||||||
ROS2_BRANCH should be the release you are targeting or just `main` if you want
|
|
||||||
to compare against ROS2 main.
|
|
||||||
|
|
||||||
### Ensure all dependencies are released.
|
|
||||||
|
|
||||||
We want to ensure the correct version of all our dependencies have been released
|
|
||||||
to the branch we are targeting. To do that, we skip the
|
|
||||||
`underlay.repos` install step and rely solely on rosdep to install
|
|
||||||
everything.
|
|
||||||
|
|
||||||
There is a dockerfile to do that as well, so run
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo docker build -t nav2:rosdep_only_build --build-arg ROS2_BRANCH=dashing --build-arg http_proxy=http://myproxy.example.com:80 --build-arg https_proxy=http://myproxy.example.com:80 -f Dockerfile.release_branch ./
|
|
||||||
```
|
|
||||||
|
|
||||||
As before, ROS2_BRANCH is the branch you are targeting. In this case, there is
|
|
||||||
no main option. We can only run this dockerfile against a set of released
|
|
||||||
packages.
|
|
||||||
|
|
||||||
### Ensure the test suite passes
|
|
||||||
|
|
||||||
Ensure the test suite passes in one of the docker images you just built.
|
|
||||||
|
|
||||||
#### Crystal
|
|
||||||
|
|
||||||
For the `crystal` release, run
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo docker run nav2:crystal colcon test
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Dashing and newer
|
|
||||||
|
|
||||||
For newer releases, run
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo docker run nav2:crystal src/navigation2/tools/run_test_suite.bash
|
|
||||||
```
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Requirement Title
|
|
||||||
The \<navigation system> should be able to \<shall> \<do something>
|
|
||||||
|
|
||||||
## More details
|
|
||||||
- Why is this needed?
|
|
||||||
- What is the expected user interaction?
|
|
||||||
- What use case does this map to?
|
|
||||||
- Are there any non-functional requirements (build system, tools, performance, etc)
|
|
||||||
|
|
||||||
|
|
||||||
# Example:
|
|
||||||
|
|
||||||
# Warehouse Navigation
|
|
||||||
The navigation system should include a modular collision avoidance algorithm that can be replaced with a new algorithm at run time
|
|
||||||
|
|
||||||
## More details
|
|
||||||
- I want to be able to write or use my own collision avoidance algorithm without having to re-compile the entire stack from source
|
|
||||||
- Ideally I can just change out a node using a custom launch file
|
|
||||||
- This maps to the "Collision Avoidance" use case
|
|
||||||
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 45 KiB |
@@ -1,332 +0,0 @@
|
|||||||
# ROS 2 Navigation System Requirements
|
|
||||||
|
|
||||||
The ROS 2 Navigation System ("Navigation System") is the control system that enables a robot to autonomously reach a goal state, such as a specific position and orientation relative to a given map. Provided with a navigation command to execute, the Navigation System generates a plan to achieve the desired result and outputs control commands to autonomously direct the robot, respecting any safety constraints and avoiding obstacles encountered along the way.
|
|
||||||
|
|
||||||
This document lists the requirements for the ROS 2 Navigation System. The ROS 2 Navigation System is intended to be a generalization of the ROS 1 navigation stack and will address some of its known limitations.
|
|
||||||
|
|
||||||
# 1. Introduction
|
|
||||||
|
|
||||||
This section describes the format of each requirement, the keywords available for use in the definition of each requirement, and the basic concepts needed to define and understand the requirements.
|
|
||||||
|
|
||||||
## 1.1 Requirement Fields
|
|
||||||
|
|
||||||
Each requirement is presented in tabular form with the following fields:
|
|
||||||
|
|
||||||
* **Id** - A unique identifier for the requirement
|
|
||||||
* **Handle** - A short, scoped, description summarizing the essence of the requirement
|
|
||||||
* **Priority** - An associated priority level: **1** (high), **2** (medium), and **3** (low)
|
|
||||||
* **Requirement** - The requirement itself, stated in clear, concise requirements language
|
|
||||||
* **Notes** - Elaboration and related information for the requirement
|
|
||||||
|
|
||||||
## 1.2 Requirement Language Keywords
|
|
||||||
|
|
||||||
In the requirements specified below, certain keywords have a specific meaning as they appear in the text. These keywords are defined as follows and must be capitalized whenever used in a manner intended to specify a behavior or requirement.
|
|
||||||
|
|
||||||
1. **MUST**: This word, or the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification.
|
|
||||||
|
|
||||||
2. **MUST NOT**: This phrase, or the phrase "SHALL NOT", mean that the definition is an absolute prohibition of the specification.
|
|
||||||
|
|
||||||
3. **SHOULD**: This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
|
|
||||||
|
|
||||||
4. **SHOULD NOT**: This phrase, or the phrase "NOT RECOMMENDED" mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label.
|
|
||||||
|
|
||||||
5. **MAY**: This word, or the adjective "OPTIONAL", mean that an item is truly optional. An implementation which does not include a particular option MUST be prepared to interoperate with another implementation which does include the option, though perhaps with reduced functionality. In the same vein an implementation which does include a particular option MUST be prepared to interoperate with another implementation which does not include the option (except, of course, for the feature the option provides).
|
|
||||||
|
|
||||||
These definitions are derived from the [IETF Best Current Practices Document 14](https://tools.ietf.org/html/bcp14).
|
|
||||||
|
|
||||||
## 1.3 Terminology
|
|
||||||
|
|
||||||
This section defines some common terminology as used in this document.
|
|
||||||
|
|
||||||
Term | Definition
|
|
||||||
---- | ----------
|
|
||||||
Path | A *Path* is an ordered sequence of points in space.
|
|
||||||
Route | A *Route* is a synonym for Path.
|
|
||||||
Trajectory | A *Trajectory* is a path parameterized by time.
|
|
||||||
Path Planning | *Path Planning* refers to the process of finding an optimal path between multiple locations. Path planning is typically characterized as a graph traversal problem and algorithms such as A*, D*, and RRT are common choices for implementation.
|
|
||||||
Motion Planning | *Motion Planning* refers to the process of specifying the motion of the robot over time to follow a specific path.
|
|
||||||
|
|
||||||
## 1.4 Use Cases
|
|
||||||
|
|
||||||
The Navigation System is part of a larger system that includes a person or automated system ("the user") directing the operation of one or more robots. To provide context for the Navigation System, this section lists the expected interactions between the user and the robot system.
|
|
||||||
|
|
||||||
## 1.4.1 Mapping Use Cases
|
|
||||||
|
|
||||||
The user will typically create a map of the area in which the robot is to navigate, either manually or using the SLAM algorithm. This map identifies significant features of the environment, including fixed features, such as walls and fixed obstacles, and virtual features, such as navigation lanes and safety zones. While the creation of the map itself is outside the scope of the Navigation System, the system is dependent on the map format(s). The map will need to be rich enough to support the Navigation System requirements listed in this document.
|
|
||||||
|
|
||||||
The following use case diagram shows an example of the kinds of operations provided by a mapping interface.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 1.4.2 Mission Planning Use Cases
|
|
||||||
|
|
||||||
Another area in which the user interacts with the system is in the creation of a mission plan for the robot. The user composes a sequence of primitive navigation commands, such as **Navigate to Pose**, **Navigate to Area**, **Maintain Pose**, etc., into an overall plan. While mission planning is also outside the scope of the Navigation System, the mission plan format should be sufficient to meet the Navigation System requirements listed in this document.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 1.4.3 Mission Execution Use Cases
|
|
||||||
|
|
||||||
The user will be able to initiate the execution of specific mission plans ("missions") and should also be able to view the status of the mission in progress, as well as cancel the mission that is currently in progress. In addition, the user may be required to provide the robot with its initial pose if the robot is not able to determine it automatically.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 1.5 Architectural Components
|
|
||||||
|
|
||||||
The Navigation System is part of a larger software system. This document does not specify the architecture for the complete system, but simply gives a conceptual overview for the purpose of requirements definition.
|
|
||||||
|
|
||||||
The Navigation System has a *command chain*, where each level refines its command input into successively more specific operations for the lext level down, and *support modules* which are used by modules in the command chain.
|
|
||||||
|
|
||||||
## 1.5.1 Command Chain
|
|
||||||
|
|
||||||
The command chain is the sequence of modules that comprise the chain of command from the user, at the top, to the robot, at the bottom.
|
|
||||||
|
|
||||||
* **Mission Planning** - Mission Planning provides an interface to the user to allow the user to create mission plans and assign them to robots for execution. A *Mission Plan* is a sequence of *Navigation Commands* along with associated information about how the commands should be carried out.
|
|
||||||
* **Mission Execution** - Mission Execution receives the Mission Plan and is responsible to execute the plan and report progress on its execution.
|
|
||||||
* **Navigation System** - The Navigation System receives a segment of an overall plan to execute (a *Navigation Command*) and generates the control commands to the robot to carry it out.
|
|
||||||
* **Robot Interface** - The Robot Interface is an abstraction of the robot platform, providing the means for the Navigation System to control the robot, learn about its capabilities, and receive feedback from the robot.
|
|
||||||
|
|
||||||
The following diagram shows the modules in the command chain and the successive refinement of the control commands:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The Navigation System itself can be decomposed into two general responsibilities, *Planning*, and *Execution*.
|
|
||||||
|
|
||||||
* **Planning** - The Planning Module is responsible to execute Navigation Commands. To do so, this module can evaluate input maps and continually assess the robot's environment to plan motion and provide the path for the robot to follow to achieve completion of the Navigation Command.
|
|
||||||
* **Execution** - The Execution Module is responsible to execute the path provided by Planning, generating the control commands required to follow the path.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Decomposing the Navigation System, the overall command chain is as follows:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 1.5.2 Support Modules
|
|
||||||
|
|
||||||
In addition to the command chain, there are several supporting modules and subsystems required for a complete system. The implementation of these modules is outside the scope of the Navigation System. However, the interface to these components is in scope and the associated requirements should be defined. Together, the support modules provide the robot with a full picture of the robot's environment.
|
|
||||||
|
|
||||||
* **Mapping** - The Mapping Subsystem generates maps that can be used by the Navigation System to plan the robot's motion. Maps are typically created in advance and are available to the Navigation System. A map can be updated to reflect changes in the environment. The frequency of these updates will vary among implementations.
|
|
||||||
* **Perception** - The Perception Subsystem utilizes sensors to develop an understanding of the dynamic environment around the robot. This information is available to the Navigation System, such as when avoiding obstacles in the robot's path.
|
|
||||||
* **Prediction** - The Prediction Subsystem anticipates future motion trajectories of any perceived objects.
|
|
||||||
* **Localization** - The Localization Subsystem provides the current location of the robot.
|
|
||||||
|
|
||||||
In a complete robot system these modules are available to the core navigation modules (the command chain), as shown in the following diagram:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
To facilitate error recovery, each module in the command chain, if it is unable to carry out its task, should be able to propagate error information to its predecessor in the chain.
|
|
||||||
|
|
||||||
## 1.6 Design Goals
|
|
||||||
|
|
||||||
The Navigation System should meet the following high-level design goals:
|
|
||||||
|
|
||||||
* **Extensibility** - The Navigation System should be a *pluggable framework* to allow for other developers to easily extend the capabilities of the Navigation System, such as adding the ability to handle new navigation commands.
|
|
||||||
* **Modularity** - The Navigation System should allow developers to *easily replace components* with alternative implementations.
|
|
||||||
* **Generality** - The Navigation System should not introduce inherent limitations in the architectural blocks. For example, it should support multiple kinds of robots, not making assumptions about robot capabilities and limitations and should support various map types and orientations.
|
|
||||||
* **Performance** - *TODO: What are the performance goals?*
|
|
||||||
* **Scalability** - *TODO: What are the scalability goals?*
|
|
||||||
* *TODO: Other important design goals to call out?*
|
|
||||||
|
|
||||||
# 2.0 Requirements
|
|
||||||
|
|
||||||
This section lists the requirements for the Navigation System.
|
|
||||||
|
|
||||||
## 2.1 Implementation Constraints
|
|
||||||
|
|
||||||
There are various constraints on the development of the ROS 2 Navigation stack.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
IC001 | Developer's Guide | 1 | The Navigation System SHOULD be developed in accordance with the ROS 2 Developer's Guide | [ROS 2 Developer's Guide](https://github.com/ros2/ros2/wiki/Developer-Guide)
|
|
||||||
IC002 | Implementation Language.C++.Version | 1 | Developers SHALL assume the availability of C++14 language features | Per the ROS 2 Developer's Guide
|
|
||||||
IC003 | Implementation Language.C++.API Preference | 1 | Developers SHOULD prefer standard C++, then Boost, then custom code, in that order. | Boost may be used if equivalent functionality is not already available in the C++ standard library
|
|
||||||
IC004 | Implementation Language.C++.Supported Compilers.g++ | 1 | The Navigation System code SHALL compile with gcc 5.4 or newer
|
|
||||||
IC005 | Implementation Language.C++.Supported Compilers.Clang | 1 | The Navigation System code SHALL compile with Clang, version *x*
|
|
||||||
IC006 | Implementation Language.C++.Supported Compilers.Intel C++ Compiler | 1 | The Navigation System code SHOULD compile with the Intel C++ Compiler, version *x* | Could be useful for optimization purposes
|
|
||||||
IC007 | Implementation Language.Python.Version | 1 | Any Python code developed for the Navigation System MUST use Python 3
|
|
||||||
IC008 | Implementation Language.GUI | 1 | Any GUIs developed as part of the Navigation System SHOULD use the Qt library, via C++ or Python (PyQt) | *Which version?*
|
|
||||||
IC009 | Implementation Language.GUI.QML | 1 | Any GUIs developed as part of the Navigation System MAY use QML
|
|
||||||
IC010 | ROS2.Version | 1 | The first revision of the Navigation System WILL target the Crystal Clemmys release of ROS2. | We should develop against the latest ROS2 code whenever possible.
|
|
||||||
|
|
||||||
## 2.2 Target Platforms
|
|
||||||
|
|
||||||
Navigation System will run on the latest versions of the operating systems supported by the core ROS 2 code.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
TP001 | Target Platforms.Operating Systems.Ubuntu | 1 | The Navigation System MUST support Ubuntu Desktop 16.04 and Ubuntu Desktop 18.04
|
|
||||||
TP002 | Target Platforms.Operating Systems.MacOS | 1 | The Navigation System MUST support MacOS 10.13 (High Sierra) and MacOS 10.14 (Mohave)
|
|
||||||
TP003 | Target Platforms.Operating Systems.Windows | 1 | The Navigation System MUST support Windows 10 Professional
|
|
||||||
TP004 | Target Platforms.Operating Systems.Clear Linux | 1 | The Navigation System SHOULD support the Intel's Clear Linux distribution | Clear Linux uses a continuous deployment model.
|
|
||||||
TP005 | Target Platforms.CPU.Word Size | 1 | The Navigation System SHALL support 64-bit processors | Don't assume a specific pointer size
|
|
||||||
TP006 | Target Platforms.Minimum Platform | 1 | *TODO: Should we specify a minimum target platform? Or, should this be expressed as minimum platform requirements?*
|
|
||||||
|
|
||||||
## 2.3 Command Chain Modules
|
|
||||||
|
|
||||||
This section lists the requirements for the core command chain modules in the Navigation System.
|
|
||||||
|
|
||||||
### 2.3.1 Mission Planning
|
|
||||||
|
|
||||||
A complete system should have some kind of Mission Planning subsystem to convey the user's intentions to the robot. The User interacts with this Mission Planning subsystem to generate a Mission Plan for the robot. The Mission Plan is defined as a sequence of Navigation Commands, along with any associated information about how and when the plan should be carried out. The design and implementation of a Mission Planning subsystem is outside the scope of the Navigation System. However, in order to understand the larger system context and how Mission Planning interacts with the Navigation System, this section will consider the nature of a mission plan and the kinds of operations it may contain.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
MP001 | Mission Planning.Navigation Commands | 1 | The Mission Plan MUST be able to express the plan as a coordinated sequence of Navigation Commands. | Could include time and policy aspects (*when* and *how*, not just *what*)
|
|
||||||
MP002 | Mission Planning.Navigation Commands.Composition | 1 | The Mission Plan SHOULD allow for the composition and naming of new Navigation Commands from a sequence of previously-defined Navigation Commands. | Build up levels of abstraction. For example, Enter-Elevator could be expressed as Navigate-to-Pose (right outside of elevator), Wait (for door to open), Navigate-to-Pose (inside the elevator).
|
|
||||||
MP003 | Mission Planning.Navigation Commands.Navigate to Pose | 1 | The Mission Plan MUST be able to convey the information required for a robot to navigate from its current location to a specific destination pose.
|
|
||||||
MP004 | Mission Planning.Navigation Commands.Navigate to Area | 2 | The Mission Plan SHOULD be able to convey the information required for a robot to navigate from its current location to a specific area. | An "area" could be a rectangular region or a more complex shape. It may be defined as tolerance to a goal (ie. within +/- 1 meter distance).
|
|
||||||
MP005 | Mission Planning.Navigation Commands.Enqueue | 2 | The Mission Plan SHOULD be able to convey the information required for a robot to navigate from its current location to a position behind another specified robot.
|
|
||||||
MP006 | Mission Planning.Navigation Commands.Follow | 2 | The Mission Plan SHOULD be able to convey the information required for a robot to be able to follow another specified robot. | This one doesn't have a completion state (reaching the goal), unless it specifies additional information such as "follow until destination reached."
|
|
||||||
MP007 | Mission Planning.Navigation Commands.Maintain Pose | 1 | The Mission Plan SHOULD be able to convey the information required for a robot to maintain its current pose. | Could be indefinite or time-based.
|
|
||||||
MP008 | Mission Planning.Navigation Commands.Park | 2 | The Mission Plan SHOULD be able to convey the information required for a robot to park itself. | The implementation of the parking command could interact with the robot to cause it, for example, to shut down or enter a low-power state.
|
|
||||||
MP009 | Mission Planning.Navigation Commands.Dock to Charger | 2 | The Mission Plan SHOULD be able to convey the information required for a robot to dock to a specific charging station.
|
|
||||||
MP010 | Mission Planning.Policy | 1 | The Mission Plan SHOULD be able to express information about how and when the navigation commands are to be carried out. | Time and safety constraints.
|
|
||||||
MP011 | Mission Planning.Policy.Time.Initiation | 1 | The Mission Plan SHOULD be able to convey when a mission should begin.
|
|
||||||
MP012 | Mission Planning.Policy.Time.Completion | 1 | The Mission Plan SHOULD be able to convey by when a mission should end.
|
|
||||||
MP013 | Mission Planning.Policy.Safety.Maximum Speed | 1 | The Mission Plan SHOULD be able to convey a maximum speed for the robot. | The robot would respect this value in carrying out the plan. This could be site-specific policy.
|
|
||||||
MP014 | Mission Planning.Policy.Safety.Minimum Safety Buffer | 1 | The Mission Plan SHOULD be able to convey a minimum safety buffer distance. | The robot would respect this value and maintain the distance from other objects at all times. Should vary with relative velocities.
|
|
||||||
|
|
||||||
### 2.3.2 Mission Execution
|
|
||||||
|
|
||||||
The Mission Execution module has the responsibility to execute a provided mission. It provides each successive Navigation Command to the Navigation Subsystem, monitoring and reporting progress towards completion of the plan.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
ME001 | Mission Execution.Inputs.Mission Plan | 1 | The Mission Execution module MUST accept the Mission Plan to execute.
|
|
||||||
ME002 | Mission Execution.Inputs.Commands.Execute Mission | 1 | When commanded to do so, the Mission Execution module MUST execute the provided Mission Plan, respecting any specified constraints.
|
|
||||||
ME003 | Mission Execution.Inputs.Commands.Cancel Mission | 1 | When commanded to do so, the Mission Execution module MUST interrupt the Robot's navigation and cancel the current mission.
|
|
||||||
ME004 | Mission Execution.Outputs.Navigation Command | 1 | Upon completion of each Navigation Command, the Mission Execution module SHALL output the next Navigation Command to execute.
|
|
||||||
ME005 | Mission Execution.Command Sequencing | 1 | The Mission Execution module MUST monitor for completion of each Navigation Command before sending the next command.
|
|
||||||
ME006 | Mission Execution.Logging | 1 | The Mission Execution module SHOULD log its activity. | In case of forensic analysis of a safety event, for example.
|
|
||||||
ME007 | Mission Execution.Feedback.Inputs.Error Recovery | 1 | Upon receipt of a downstream failure (unable to execute the Navigation Command), the Mission Execution module SHOULD attempt to recover and continue execution of the mission.
|
|
||||||
ME008 | Mission Execution.Feedback.Outputs.Progress Notification | 1 | The Mission Execution module SHALL provide progress notifications on the execution of the mission. | Intermediate steps of interest.
|
|
||||||
ME009 | Mission Execution.Feedback.Outputs.Mission Completed | 1 | Upon successfull completion of the mission, the Mission Execution module SHALL output a corresponding notification.
|
|
||||||
ME010 | Mission Execution.Feedback.Outputs.Mission Canceled | 1 | Upon receiving a cancellation command and cancelling the mission, the Mission Execution module SHALL output a corresponding notification.
|
|
||||||
ME011 | Mission Execution.Feedback.Outputs.Mission Failure | 1 | If the Mission Execution module is unable to execute the mission, it MUST output a failure notification. | This would be received by the user-level interface and could necessitate user intervention, such as having a remote operating center where the remote operator "rescues" the robot.
|
|
||||||
ME012 | Mission Execution.Safe State Upon Failure | 1 | If the Mission Execution module is unable to execute the mission, it MUST direct the robot to a safe state. | The failure could be for a variety of reasons - sensor failures, algorithmic failure, a collision, etc.
|
|
||||||
ME013 | Mission Execution.Selection of Planners | 1 | The Navigation System SHOULD allow the association and use of specific Planning and Execution Modules for a given Navigation Command. | For example, a user may want to have components for classic point-A-to-point-B travel, but upon reaching point B, have specialized components that control a series of maneuvers such as docking to a charging station or a conveyor belt.
|
|
||||||
|
|
||||||
### 2.3.3 Navigation System.Planning
|
|
||||||
|
|
||||||
The Navigation System's Planning Module receives the Navigation Command from the Mission Execution module and is responsible to implement that command. To do so, the Planning Module can use information from the Mapping Subsystem to plan a route and use input from the Perception Subsystem to evaluate the dynamic environment and avoid collisions with objects crossing its path.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
PLN001 | Planning | 1 | The Navigation System SHOULD have a Planning Module that generates the Path for the robot to follow to implement a specified Navigation Command.
|
|
||||||
PLN002 | Planning.Inputs.Navigation Command | 1 | The Planning Module SHALL receive the Navigation Command to execute.
|
|
||||||
PLN003 | Planning.Inputs.Policy | 1 | The Planning Module SHALL receive policy information associated with the Navigation Command to execute. | This could be global policy and/or per-command policy. Policy could contain, for example, a list of conventions for the robot to follow (navigate on the right side of a path, for example).
|
|
||||||
PLN004 | Planning.Inputs.Mapping.Maps | 1 | The Planning Module MUST have access to one or more maps available that describe the robot's environment.
|
|
||||||
PLN005 | Planning.Inputs.Perception.Sensory Input | 1 | The Planning Module MUST have access to data from the Perception Subsystem.
|
|
||||||
PLN006 | Planning.Inputs.Prediction.Predicted Trajectories | 1 | The Planning Module MAY have access to predicted trajectories of objects detected by the Perception Subsystem. | In simple planners, there is no prediction of moving objects, but in more complex planners, this may be considered.
|
|
||||||
PLN007 | Planning.Inputs.Localization.Current Pose | 1 | The Planning Module MUST have access to the robot's current pose. | The pose could be be provided manually or automatically determined (outside of this module).
|
|
||||||
PLN008 | Planning.Outputs.Path | 1 | The Planning Module SHOULD output the Path for the robot to follow to execute the input Navigation Command and MUST respect any associated policy.
|
|
||||||
PLN009 | Planning.Feedback.Inputs | 1 | The Planning Module MAY receive error input from the downstream Execution Module. | So that it can attempt to recover from execution failures.
|
|
||||||
PLN010 | Planning.Feedback.Inputs.Error Recovery | 1 | Upon receipt of a downstream failure, the Planning Module SHOULD attempt to automatically recover from the error. | Handling a robot that gets stuck or handling a collision, for example.
|
|
||||||
PLN011 | Planning.Feedback.Outputs.Command Completed | 1 | Upon completing the provided Navigation Command, the Planning Module MUST report this event on its feedback output.
|
|
||||||
PLN012 | Planning.Feedback.Outputs.Unable to Execute Command | 1 | If the Planning Module is unable to execute the Navigation Command, it SHALL report the error on its feedback output. | It should handle errors if possible, but report back if it can't.
|
|
||||||
PLN013 | Planning.Feedback.Outputs.Error Propagation | 1 | The Planning Module SHOULD propagate errors that it can't handle.
|
|
||||||
PLN014 | Planning.Logging | 1 | The Planning Module SHOULD log significant events. | Commands completed, failures, recoveries, etc.
|
|
||||||
PLN015 | Planning.Documentation | 1 | The Navigation System SHOULD provided detailed documentation on how to develop a Planning Module.
|
|
||||||
PLN016 | Planning.Simple Example | 1 | The Navigation System SHOULD provided a simple example of a Planning Module. | An easily understood module that developers and students could use as a starting point.
|
|
||||||
|
|
||||||
### 2.3.4 Navigation System.Execution
|
|
||||||
|
|
||||||
The Navigation System's Execution Module is responsible to execute the Path specified by the Planning Module. It has available to it all of the information from the support modules and must respect any policy guidance.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
EXE001 | Execution | 1 | The Navigation System SHOULD have an Execution Module that generates commands to the robot to achieve a specific Path.
|
|
||||||
EXE002 | Execution.Inputs.Path | 1 | The Execution Module SHALL receive a Path that the robot is to follow.
|
|
||||||
EXE003 | Execution.Inputs.Policy | 1 | The Execution Module SHALL receive policy information associated with the Path to follow. | Could filter down from higher-level policy specification.
|
|
||||||
EXE004 | Execution.Collision Avoidance.Avoid Stationary Objects | 1 | The Execution Module MUST direct the robot such that it avoids colliding into stationary objects in its environment.
|
|
||||||
EXE005 | Execution.Collision Avoidance.Avoid Moving Objects | 1 | The Execution Module MUST direct the robot such that it avoids colliding into moving objects that intercept its path.
|
|
||||||
EXE006 | Execution.Collision Detection | 1 | The Execution Module SHOULD detect if a collision has occurred.
|
|
||||||
EXE007 | Execution.Collision Detection.Latency | 1 | The Execution Module SHOULD detect collisions within 50ms. | *TODO: What is the right value?*
|
|
||||||
EXE008 | Execution.Feedback.Inputs.Robot Malfunction | 1 | The Execution Module SHOULD receive notifications of any robot malfunctions from the downstream robot interface. | A sensor failure, for example.
|
|
||||||
EXE009 | Execution.Feedback.Outputs.Collision Detected | 1 | The Execution Module SHOULD report the detection of a collision. | So that the Planning Module can attempt recovery or otherwise respond.
|
|
||||||
EXE010 | Execution.Feedback.Outputs.Error Propagation | 1 | The Execution Module SHOULD propagate errors that it can't handle.
|
|
||||||
EXE011 | Execution.Documentation | 1 | The Navigation System SHOULD provided detailed documentation on how to develop an Execution Module.
|
|
||||||
EXE012 | Execution.Simple Example | 1 | The Navigation System SHOULD provided a simple example of an Execution Module| An easily understood module that developers and students could use as a starting point.
|
|
||||||
|
|
||||||
### 2.3.5 Robot Interface
|
|
||||||
|
|
||||||
There should be a uniform interface to the various supported robots. The abstraction of different robots may be handled by current mechanisms, such as UDRF, Twist commands, etc. We should consider if anything else is needed here. The user should be able to specify different types of robot drive types, such as Ackerman (automobile) steering, and robot shapes.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
RI001 | Robot Interface.Attributes | 1 | Holonomicity, max/min speeds and accelerations, etc.
|
|
||||||
RI002 | Robot Interface.Dynamic Switching | 1 | Can the robot dynamically change attributes?
|
|
||||||
RI003 | Robot Interface.Safety.Limited Parameters | 1 | A list of parameters used to limit certain circumstances and provide the hooks for users to set those values if they want
|
|
||||||
RI004 | Robot Interface.Safety.Speed Limiting | 1 | *TODO*
|
|
||||||
RI005 | Robot Interface.Safety.Force Limiting | 1 | *TODO*
|
|
||||||
RI006 | Robot Interface.EMO Button | 1 | *TODO*
|
|
||||||
RI007 | Robot Interface.Feedback.Outputs | 1 | *TODO*
|
|
||||||
|
|
||||||
## 2.4 Support Modules
|
|
||||||
|
|
||||||
There are a few support modules and subsystems that are not part of the Navigation System proper, but are necessary components in a complete system. The Navigation System depends on the data interfaces to these components. This section describes the requirements and assumptions of these interface.
|
|
||||||
|
|
||||||
### 2.4.1 Mapping
|
|
||||||
|
|
||||||
The map data format should be capable of describing typical indoor and outdoor environments encoutered by the robots.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
MAP001 | Mapping | 1 | The Mapping System SHALL provide map information to the Navigation System.
|
|
||||||
MAP002 | Mapping.Data Model.Obstacles | 1 | Maps provided by Mapping Subsystem MUST indicate the location of known obstacles.
|
|
||||||
MAP003 | Mapping.Data Model.Confidence Metric | 1 | Each known obstacle in a map SHALL have a confidence metric associated with it.
|
|
||||||
MAP004 | Mapping.Data Model.Unknown Space | 1 | Maps provided by the Mapping Subsystem MUST indicate unmapped/unknown space. | Such as areas beyond the edge of the map, or areas within the map for which we didn't have any observations during map building.
|
|
||||||
MAP005 | Mapping.Data Model.Surface Planarity | 1 | The map data format SHALL be capable of describing the planarity of traversable surfaces. | Can describe uneven ground.
|
|
||||||
MAP006 | Mapping.Data Model.Safety Zone | 1 | The map data format SHALL be capable of defining regions where the robot may have to adjust its operations according to specified constraints.
|
|
||||||
MAP007 | Mapping.Data Model.Safety Zone.Name | 1 | The map data format SHOULD allow for naming each safety zone. | *TODO: Does it need to be a unique name?*
|
|
||||||
MAP008 | Mapping.Data Model.Safety Zone.Type | 1 | The map data format SHOULD allow for defining types of safety zones. | To allow for re-use of a safety zone type without redefining policy. Could be an "intersection" type, for example. May want to slot down at all intersections, for example.
|
|
||||||
MAP009 | Mapping.Data Model.Safety Zone.Policy | 1 | The map data format SHALL be capable of expressing policy associated with each safety zone and safety zone type. | Maximum speed, (increased) distance to people, etc.
|
|
||||||
MAP010 | Mapping.Data Model.Safety Zone.Policy.Keep Out Zone | 1 | The map data format SHALL be capable of expressing that a robot must not navigate through this zone.
|
|
||||||
MAP011 | Mapping.Data Model.Lanes | 1 | The map data format SHALL be able to specify virtual lanes. | May prefer specified lanes in a warehouse, for example.
|
|
||||||
MAP012 | Mapping.Data Model.Building Levels | 1 | The map data format SHALL be able to specify single and multi-level buildings.
|
|
||||||
MAP013 | Mapping.Data Model.Building Levels.Level Connecting Features | 1 | The map data format SHALL be able to specify level-connecting features, such as elevators, stairways, and ramps.
|
|
||||||
MAP014 | Mapping.Multiple Maps Per Environment | 1 | The Mapping System MAY provide multiple maps of the same environment. | Such as for different scales and elevations.
|
|
||||||
MAP015 | Mapping.Data Model.Extensibility | 1 | The Mapping System SHOULD be extensible, to allow for the description of additional entities in the environment.
|
|
||||||
MAP016 | Mapping.Dimensionality.2D | 1 | The Mapping System MUST provide 2D map information.
|
|
||||||
MAP017 | Mapping.Dimensionality.2D+ | 1 | The Mapping System MAY provide 2D+ map information.
|
|
||||||
MAP018 | Mapping.Dimensionality.3D | 1 | The Mapping System MAY provide 3D map information.
|
|
||||||
MAP019 | Mapping.Dynamic Updates | 1 | The Mapping System SHOULD provide real-time updates of map information. | Allow for updates to the map to be pushed to clients.
|
|
||||||
MAP020 | Mapping.Memory Optimization.Tiling | 1 | The Mapping System MAY provide the Navigation System with local map regions, sufficient for navigation. | Could provide relevant map tiles, for example, saving memory in the planners.
|
|
||||||
|
|
||||||
### 2.4.2 Perception
|
|
||||||
|
|
||||||
The Perception Subsystem provides information about objects detected in the robot's environment. This information would typically be generated from a fusion of sensor input.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
PER001 | Perception | 1 | The Perception Subsystem SHALL provide information about the dynamic environment of the robot. | Info sufficient to carry out the Navigation System requirements.
|
|
||||||
PER002 | Perception.Latency | 1 | *TODO*
|
|
||||||
|
|
||||||
### 2.4.3 Prediction
|
|
||||||
|
|
||||||
The Prediction Subsystem uses input from the Perception Subsystem and predicts the trajectories of the detected objects over time.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
PRE001 | Prediction.Object Prediction | 1 | The Prediction Subsystem SHOULD predict the trajectories of detected objects. | One of the biggest shortcomings of the current system is the inability to model/predict where obstacles will be in the future. This leads to collisions with other moving objects
|
|
||||||
PRE002 | Prediction.Object Prediction.Time Horizon | 1 | *TODO: How far into the future should the object prediction work?*
|
|
||||||
|
|
||||||
### 2.4.4 Localization
|
|
||||||
|
|
||||||
The Navigation System requires the Robot's current pose, provided by an external Localization module. This section lists the requirements for the information provided by the the Localization Module.
|
|
||||||
|
|
||||||
Id | Handle | Priority | Description | Notes
|
|
||||||
-- | ------ | -------- | ----------- | -----
|
|
||||||
LOC001 | Localization.Robot Pose | 1 | The Localization module MUST provide the robot's current pose to the Navigation System. | This could be manual or as a result of automatic localization; the Navigation System wouldn't know either way.
|
|
||||||
LOC002 | Localization.Robot Pose.Accuracy | 1 | The Localization Module MUST provide the estimated accuracy of the pose. | So that Planning modules can determine if a particular Localization module has sufficient accuracy. Could use PoseWithCovariance message.
|
|
||||||
|
|
||||||
## 2.5 Open Issues
|
|
||||||
|
|
||||||
* What are the performance goals for the ROS2 Navigation System?
|
|
||||||
* What are the scalability for the ROS2 Navigaton System?
|
|
||||||
* Any other important design goals to call out?
|
|
||||||
* Should we specify a minimum target platform? Or, should this be expressed as minimum platform requirements?
|
|
||||||
* What is the right latency value for detecting a collision?
|
|
||||||
* Should we add any safety-related functionality at the robot interface level?
|
|
||||||
* Do safety zones need unique names?
|
|
||||||
* What is the target latency for the perception subsystem?
|
|
||||||
* How far into the future should the object prediction work?
|
|
||||||
|
Before Width: | Height: | Size: 157 KiB |