update
|
|
@ -1,19 +1,7 @@
|
|||
# Python
|
||||
build/
|
||||
log/
|
||||
autorun_logs/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# ROS
|
||||
build/
|
||||
devel/
|
||||
logs/
|
||||
install/
|
||||
build_isolated/
|
||||
devel_isolated/
|
||||
*.bag
|
||||
CATKIN_IGNORE
|
||||
|
||||
# Misc
|
||||
.vscode/
|
||||
*.swp
|
||||
log/
|
||||
test/
|
||||
*.log
|
||||
node_modules/
|
||||
|
|
|
|||
312
README.md
|
|
@ -1,318 +1,34 @@
|
|||
# BCR Bot
|
||||
# 仓库 3D 场景
|
||||
|
||||
https://github.com/blackcoffeerobotics/bcr_bot/assets/13151010/0fc570a3-c70c-415b-8222-b9573d5911c8
|
||||
|
||||
## About
|
||||
|
||||
This repository contains a Gazebo and Isaac Sim simulation for a differential drive robot, equipped with an IMU, a depth camera, stereo camera and a 2D LiDAR. The primary contriution of this project is to support multiple ROS and Gazebo distros. Currently, the project supports the following versions -
|
||||
## 场景预览
|
||||
|
||||
1. [ROS Noetic + Gazebo Classic 11 (branch ros1)](#noetic--classic-ubuntu-2004)
|
||||
2. [ROS2 Humble + Gazebo Classic 11 (branch ros2)](#humble--classic-ubuntu-2204)
|
||||
3. [ROS2 Humble + Gazebo Fortress (branch ros2)](#humble--fortress-ubuntu-2204)
|
||||
4. [ROS2 Humble + Gazebo Harmonic (branch ros2)](#humble--harmonic-ubuntu-2204)
|
||||
5. [ROS2 Humble + Isaac Sim (branch ros2)](#humble--isaac-sim-ubuntu-2204)
|
||||

|
||||
|
||||
Each of the following sections describes depedencies, build and run instructions for each of the above combinations
|
||||
|
||||
## Noetic + Classic (Ubuntu 20.04)
|
||||
---
|
||||
|
||||
### Dependencies
|
||||
## 启动(唯一命令,无需编译)
|
||||
|
||||
In addition to ROS1 Noetic and Gazebo Classic installations, the dependencies can be installed with [rosdep](http://wiki.ros.org/rosdep)
|
||||
卡片内已包含预编译 `install/`,**直接运行即可**,不要 `colcon build`。
|
||||
|
||||
```bash
|
||||
# From the root directory of the workspace. This will install everything mentioned in package.xml
|
||||
rosdep install --from-paths src --ignore-src -r -y
|
||||
./gzsim_run.sh
|
||||
|
||||
|
||||
| `./gzsim_stop.sh` | 停止仿真 |
|
||||
```
|
||||
|
||||
### Source Build
|
||||
**必须等到**终端出现:
|
||||
|
||||
```bash
|
||||
catkin build --packages-select bcr_bot
|
||||
```text
|
||||
[autorun] GzWeb scene OK (... bytes), 9002 stable
|
||||
[autorun] ✓ 全部就绪 — 现在刷新「仿真器」面板
|
||||
```
|
||||
|
||||
### Binary Install
|
||||
To install BCR bot in the binaries:
|
||||
|
||||
```bash
|
||||
sudo apt-get install ros-noetic-bcr-bot
|
||||
```
|
||||
### Run
|
||||
|
||||
To launch the robot in Gazebo,
|
||||
```bash
|
||||
roslaunch bcr_bot gazebo.launch
|
||||
```
|
||||
To view in rviz,
|
||||
```bash
|
||||
roslaunch bcr_bot rviz.launch
|
||||
```
|
||||
### Configuration
|
||||
|
||||
The launch file accepts multiple launch arguments,
|
||||
```bash
|
||||
roslaunch bcr_bot gazebo.launch
|
||||
camera_enabled:=True \
|
||||
two_d_lidar_enabled:=True \
|
||||
position_x:=0.0 \
|
||||
position_y:=0.0 \
|
||||
orientation_yaw:=0.0 \
|
||||
odometry_source:=world \
|
||||
world_file:=small_warehouse.world \
|
||||
robot_namespace:="bcr_bot"
|
||||
```
|
||||
**Note:** To use stereo_image_proc with the stereo images excute following command:
|
||||
```bash
|
||||
ROS_NAMESPACE=bcr_bot/stereo_camera rosrun stereo_image_proc stereo_image_proc
|
||||
```
|
||||
|
||||
## Humble + Classic (Ubuntu 22.04)
|
||||
|
||||
### Dependencies
|
||||
|
||||
In addition to ROS2 Humble and Gazebo Classic installations, we need to manually install [gazebo_ros_pkgs](https://github.com/ros-simulation/gazebo_ros_pkgs/tree/ros2) (since the same branch supports Classic and Fortress)
|
||||
|
||||
```bash
|
||||
sudo apt-get install ros-humble-gazebo-ros-pkgs
|
||||
```
|
||||
Remainder of the dependencies can be installed with [rosdep](http://wiki.ros.org/rosdep)
|
||||
|
||||
```bash
|
||||
# From the root directory of the workspace. This will install everything mentioned in package.xml
|
||||
rosdep install --from-paths src --ignore-src -r -y
|
||||
```
|
||||
|
||||
### Source Build
|
||||
|
||||
```bash
|
||||
colcon build --packages-select bcr_bot
|
||||
```
|
||||
|
||||
### Binary Install
|
||||
To install BCR bot in the binaries:
|
||||
|
||||
```bash
|
||||
sudo apt-get install ros-humble-bcr-bot
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
To launch the robot in Gazebo,
|
||||
```bash
|
||||
ros2 launch bcr_bot gazebo.launch.py
|
||||
```
|
||||
To view in rviz,
|
||||
```bash
|
||||
ros2 launch bcr_bot rviz.launch.py
|
||||
```
|
||||
### Configuration
|
||||
|
||||
The launch file accepts multiple launch arguments,
|
||||
```bash
|
||||
ros2 launch bcr_bot gazebo.launch.py \
|
||||
camera_enabled:=True \
|
||||
two_d_lidar_enabled:=True \
|
||||
stereo_camera_enabled:=False \
|
||||
position_x:=0.0 \
|
||||
position_y:=0.0 \
|
||||
orientation_yaw:=0.0 \
|
||||
odometry_source:=world \
|
||||
world_file:=small_warehouse.sdf \
|
||||
robot_namespace:="bcr_bot"
|
||||
```
|
||||
**Note:** To use stereo_image_proc with the stereo images excute following command:
|
||||
```bash
|
||||
ros2 launch stereo_image_proc stereo_image_proc.launch.py left_namespace:=bcr_bot/stereo_camera/left right_namespace:=bcr_bot/stereo_camera/right
|
||||
```
|
||||
## Humble + Fortress (Ubuntu 22.04)
|
||||
|
||||
### Dependencies
|
||||
|
||||
In addition to ROS2 Humble and [Gazebo Fortress installations](https://gazebosim.org/docs/fortress/install_ubuntu), we need to manually install interfaces between ROS2 and Gazebo sim as follows,
|
||||
|
||||
```bash
|
||||
sudo apt-get install ros-humble-ros-gz-sim ros-humble-ros-gz-bridge ros-humble-ros-gz-interfaces
|
||||
```
|
||||
Remainder of the dependencies can be installed with [rosdep](http://wiki.ros.org/rosdep)
|
||||
|
||||
```bash
|
||||
# From the root directory of the workspace. This will install everything mentioned in package.xml
|
||||
rosdep install --from-paths src --ignore-src -r -y
|
||||
```
|
||||
|
||||
### Source Build
|
||||
|
||||
```bash
|
||||
colcon build --packages-select bcr_bot
|
||||
```
|
||||
|
||||
### Binary Install
|
||||
To install BCR bot in the binaries:
|
||||
|
||||
```bash
|
||||
sudo apt-get install ros-humble-bcr-bot
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
To launch the robot in Gazebo,
|
||||
```bash
|
||||
ros2 launch bcr_bot ign.launch.py
|
||||
```
|
||||
To view in rviz,
|
||||
```bash
|
||||
ros2 launch bcr_bot rviz.launch.py
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
The launch file accepts multiple launch arguments,
|
||||
```bash
|
||||
ros2 launch bcr_bot ign.launch.py \
|
||||
camera_enabled:=True \
|
||||
stereo_camera_enabled:=False \
|
||||
two_d_lidar_enabled:=True \
|
||||
position_x:=0.0 \
|
||||
position_y:=0.0 \
|
||||
orientation_yaw:=0.0 \
|
||||
odometry_source:=world \
|
||||
world_file:=small_warehouse.sdf
|
||||
```
|
||||
**Note:** To use stereo_image_proc with the stereo images excute following command:
|
||||
```bash
|
||||
ros2 launch stereo_image_proc stereo_image_proc.launch.py left_namespace:=bcr_bot/stereo_camera/left right_namespace:=bcr_bot/stereo_camera/right
|
||||
```
|
||||
|
||||
## Humble + Harmonic (Ubuntu 22.04)
|
||||
|
||||
### Dependencies
|
||||
|
||||
In addition to ROS2 Humble and [Gazebo Harmonic installations](https://gazebosim.org/docs/harmonic/install_ubuntu), we need to manually install interfaces between ROS2 and Gazebo sim as follows,
|
||||
|
||||
```bash
|
||||
sudo apt-get install ros-humble-ros-gzharmonic
|
||||
```
|
||||
Remainder of the dependencies can be installed with [rosdep](http://wiki.ros.org/rosdep)
|
||||
|
||||
```bash
|
||||
# From the root directory of the workspace. This will install everything mentioned in package.xml
|
||||
rosdep install --from-paths src --ignore-src -r -y
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
colcon build --packages-select bcr_bot
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
To launch the robot in Gazebo,
|
||||
```bash
|
||||
ros2 launch bcr_bot gz.launch.py
|
||||
```
|
||||
To view in rviz,
|
||||
```bash
|
||||
ros2 launch bcr_bot rviz.launch.py
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
The launch file accepts multiple launch arguments,
|
||||
```bash
|
||||
ros2 launch bcr_bot gz.launch.py \
|
||||
camera_enabled:=True \
|
||||
stereo_camera_enabled:=False \
|
||||
two_d_lidar_enabled:=True \
|
||||
position_x:=0.0 \
|
||||
position_y:=0.0 \
|
||||
orientation_yaw:=0.0 \
|
||||
odometry_source:=world \
|
||||
world_file:=small_warehouse.sdf
|
||||
```
|
||||
**Note:**
|
||||
1. To use stereo_image_proc with the stereo images excute following command:
|
||||
```bash
|
||||
ros2 launch stereo_image_proc stereo_image_proc.launch.py left_namespace:=bcr_bot/stereo_camera/left right_namespace:=bcr_bot/stereo_camera/right
|
||||
```
|
||||
2. Harmonic support is not available in the bcr_bot binaries yet.
|
||||
|
||||
**Warning:** `gz-harmonic` cannot be installed alongside gazebo-classic (eg. gazebo11) since both use the `gz` command line tool.
|
||||
|
||||
### Humble + Isaac Sim (Ubuntu 22.04)
|
||||
|
||||
### Dependencies
|
||||
|
||||
In addition to ROS2 Humble [Isaac Sim installation](https://docs.omniverse.nvidia.com/isaacsim/latest/installation/index.html) with ROS2 extension is required. Remainder of bcr_bot specific dependencies can be installed with [rosdep](http://wiki.ros.org/rosdep)
|
||||
|
||||
```bash
|
||||
# From the root directory of the workspace. This will install everything mentioned in package.xml
|
||||
rosdep install --from-paths src --ignore-src -r -y
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
colcon build --packages-select bcr_bot
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
To launch the robot in Isaac Sim:
|
||||
- Open Isaac Sim and load the `warehouse_scene.usd` or `scene.usd` from [here](usd).
|
||||
- Add in extra viewports for different camera views.
|
||||
- Start the Simulation: Run the simulation directly within Isaac Sim.
|
||||
- The following USDs are included in the package:
|
||||
- `warehouse_scene.usd` - Warehouse scene with a robot.
|
||||
- `scene.usd` - Scene with a robot in a empty world.
|
||||
- `bcr_bot.usd` - Robot model that can be imported into any scene.
|
||||
- `ActionGraphFull.usd` - Action graph for the robot to publish all the required topics.
|
||||
|
||||
To view in rviz:
|
||||
```bash
|
||||
ros2 launch bcr_bot rviz.launch.py
|
||||
```
|
||||
NOTE: The command to run mapping and navigation is common between all versions of gazebo and Isaac sim see [here](#mapping-with-slam-toolbox).
|
||||
|
||||
### Mapping with SLAM Toolbox
|
||||
|
||||
SLAM Toolbox is an open-source package designed to map the environment using laser scans and odometry, generating a map for autonomous navigation.
|
||||
|
||||
NOTE: The command to run mapping is common between all versions of gazebo.
|
||||
|
||||
To start mapping:
|
||||
```bash
|
||||
ros2 launch bcr_bot mapping.launch.py
|
||||
```
|
||||
|
||||
Use the teleop twist keyboard to control the robot and map the area:
|
||||
```bash
|
||||
ros2 run teleop_twist_keyboard teleop_twist_keyboard cmd_vel:=/bcr_bot/cmd_vel
|
||||
```
|
||||
|
||||
To save the map:
|
||||
```bash
|
||||
cd src/bcr_bot/config
|
||||
ros2 run nav2_map_server map_saver_cli -f bcr_map
|
||||
```
|
||||
|
||||
### Using Nav2 with bcr_bot
|
||||
|
||||
Nav2 is an open-source navigation package that enables a robot to navigate through an environment easily. It takes laser scan and odometry data, along with the map of the environment, as inputs.
|
||||
|
||||
NOTE: The command to run navigation is common between all versions of gazebo and Isaac sim.
|
||||
|
||||
To run Nav2 on bcr_bot:
|
||||
```bash
|
||||
ros2 launch bcr_bot nav2.launch.py
|
||||
```
|
||||
|
||||
### Simulation and Visualization
|
||||
1. Gz Sim (Ignition Gazebo) (small_warehouse World):
|
||||

|
||||
|
||||
2. Isaac Sim:
|
||||

|
||||
|
||||
3. Rviz (Depth camera) (small_warehouse World):
|
||||

|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
# 容器 INIT_SCRIPT 入口 — 仅调用唯一启动脚本
|
||||
exec /workspace/gzsim_run.sh
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# 仓库 3D 场景
|
||||
|
||||
|
||||
|
||||
## 场景预览
|
||||
|
||||

|
||||
|
||||
|
||||
---
|
||||
|
||||
## 启动(唯一命令,无需编译)
|
||||
|
||||
卡片内已包含预编译 `install/`,**直接运行即可**,不要 `colcon build`。
|
||||
|
||||
```bash
|
||||
./gzsim_run.sh
|
||||
|
||||
|
||||
| `./gzsim_stop.sh` | 停止仿真 |
|
||||
```
|
||||
|
||||
**必须等到**终端出现:
|
||||
|
||||
```text
|
||||
[autorun] GzWeb scene OK (... bytes), 9002 stable
|
||||
[autorun] ✓ 全部就绪 — 现在刷新「仿真器」面板
|
||||
```
|
||||
|
||||
打开rviz,显示实时点云数据
|
||||
|
||||
```bash
|
||||
source install/setup.bash
|
||||
ros2 launch bcr_bot rviz.launch.py
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 173 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
# 简要诊断 :9002 / gz-launch(GzWeb 使用 wss://同域/gzbridge/)
|
||||
set -euo pipefail
|
||||
|
||||
echo "========== GzWeb / gzbridge (:9002) =========="
|
||||
echo "[1] port 9002"
|
||||
ss -ltnp 2>/dev/null | grep ':9002 ' || echo " (not listening)"
|
||||
|
||||
echo
|
||||
echo "[2] processes"
|
||||
ps aux | grep -E 'gz sim|gz-launch|gz launch.*websocket|warehouse_gzweb' | grep -v grep || echo " (none)"
|
||||
|
||||
echo
|
||||
echo "GzWeb panel: wss://{your-space}.spaces.databall.tech/gzbridge/"
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
# GzWeb 仓库场景 — Gazebo Sim + gz-launch :9002(GzWeb 连 wss://同域/gzbridge/)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
sleep 3
|
||||
export PATH="/usr/bin:/bin:/opt/ros/humble/bin:${PATH}"
|
||||
export LIBGL_ALWAYS_SOFTWARE=1
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
set +u
|
||||
source /opt/ros/humble/setup.bash
|
||||
[[ -f "${ROOT}/install/setup.bash" ]] && source "${ROOT}/install/setup.bash"
|
||||
set -u
|
||||
|
||||
LOG_DIR="${ROOT}/autorun_logs/autorun_$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
pkill -f 'gz launch.*websocket' 2>/dev/null || true
|
||||
pkill -f 'gz-launch.*websocket' 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
echo "[autorun] launching warehouse Gazebo Sim ..."
|
||||
ros2 launch bcr_bot gz.launch.py > "${LOG_DIR}/warehouse_gzsim.log" 2>&1 &
|
||||
GZSIM_PID=$!
|
||||
|
||||
sleep 15
|
||||
if ! ps -p "$GZSIM_PID" > /dev/null; then
|
||||
echo "[autorun] Gazebo exited early:"
|
||||
tail -40 "${LOG_DIR}/warehouse_gzsim.log" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WS_CONFIG="${ROOT}/src/websocket.gzlaunch"
|
||||
[[ -f "$WS_CONFIG" ]] || WS_CONFIG="/usr/share/gz/gz-launch7/configs/websocket.gzlaunch"
|
||||
|
||||
# WebsocketServer is a separate process from ros2 launch — it does NOT inherit
|
||||
# AppendEnvironmentVariable from warehouse_gzweb.launch.py. Without install/src
|
||||
# on GZ_SIM_RESOURCE_PATH, mesh requests get "Access denied" and GzWeb stays empty.
|
||||
export GZ_SIM_RESOURCE_PATH="${ROOT}/install:${ROOT}/src${GZ_SIM_RESOURCE_PATH:+:$GZ_SIM_RESOURCE_PATH}"
|
||||
export IGN_GAZEBO_RESOURCE_PATH="${GZ_SIM_RESOURCE_PATH}"
|
||||
|
||||
echo "[autorun] starting gz-launch websocket on :9002 ..."
|
||||
echo "[autorun] GZ_SIM_RESOURCE_PATH=${GZ_SIM_RESOURCE_PATH}"
|
||||
gz launch "$WS_CONFIG" > "${LOG_DIR}/websocket.log" 2>&1 &
|
||||
WEBSOCKET_PID=$!
|
||||
|
||||
sleep 10
|
||||
if ! ps -p "$WEBSOCKET_PID" > /dev/null; then
|
||||
echo "[autorun] websocket exited:"
|
||||
cat "${LOG_DIR}/websocket.log" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[autorun] ready. Refresh GzWeb (wss://{host}/gzbridge/). logs: ${LOG_DIR}"
|
||||
wait
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env bash
|
||||
# GzWeb 仓库场景 — Gazebo Sim + gz-launch :9002(GzWeb 连 wss://同域/gzbridge/)
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
sleep 3
|
||||
export PATH="/usr/bin:/bin:/opt/ros/humble/bin:${PATH}"
|
||||
export LIBGL_ALWAYS_SOFTWARE=1
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
set +u
|
||||
source /opt/ros/humble/setup.bash
|
||||
[[ -f "${ROOT}/install/setup.bash" ]] && source "${ROOT}/install/setup.bash"
|
||||
set -u
|
||||
|
||||
# WebsocketServer asset whitelist (mesh under install/ share).
|
||||
export GZ_SIM_RESOURCE_PATH="/workspace/install/bcr_bot/share/bcr_bot:/workspace/install:${GZ_SIM_RESOURCE_PATH:-}"
|
||||
|
||||
LOG_DIR="${ROOT}/autorun_logs/autorun_$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
pkill -f 'gz launch.*websocket' 2>/dev/null || true
|
||||
pkill -f 'gz-launch.*websocket' 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
echo "[autorun] launching warehouse Gazebo Sim ..."
|
||||
ros2 launch bcr_bot warehouse_gzweb.launch.py > "${LOG_DIR}/warehouse_gzsim.log" 2>&1 &
|
||||
GZSIM_PID=$!
|
||||
|
||||
sleep 15
|
||||
if ! ps -p "$GZSIM_PID" > /dev/null; then
|
||||
echo "[autorun] Gazebo exited early:"
|
||||
tail -40 "${LOG_DIR}/warehouse_gzsim.log" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WS_CONFIG="${ROOT}/src/websocket.gzlaunch"
|
||||
[[ -f "$WS_CONFIG" ]] || WS_CONFIG="/usr/share/gz/gz-launch7/configs/websocket.gzlaunch"
|
||||
|
||||
echo "[autorun] starting gz-launch websocket on :9002 ..."
|
||||
gz launch "$WS_CONFIG" > "${LOG_DIR}/websocket.log" 2>&1 &
|
||||
WEBSOCKET_PID=$!
|
||||
|
||||
sleep 10
|
||||
if ! ps -p "$WEBSOCKET_PID" > /dev/null; then
|
||||
echo "[autorun] websocket exited:"
|
||||
cat "${LOG_DIR}/websocket.log" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[autorun] ready. Refresh GzWeb (wss://{host}/gzbridge/). logs: ${LOG_DIR}"
|
||||
wait
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env bash
|
||||
# 停止仓库 GzWeb 仿真(释放 9002 与单实例锁)
|
||||
set -euo pipefail
|
||||
|
||||
echo "[stop] stopping warehouse GzWeb services ..."
|
||||
|
||||
pkill -9 -f 'warehouse_foxglove_guard.sh' 2>/dev/null || true
|
||||
pkill -9 -f 'warehouse_gzsim_keepalive.sh' 2>/dev/null || true
|
||||
pkill -9 -f 'warehouse_gzweb.launch.py' 2>/dev/null || true
|
||||
pkill -9 -f 'gz-launch.*websocket' 2>/dev/null || true
|
||||
pkill -9 -f 'gz launch.*websocket' 2>/dev/null || true
|
||||
pkill -9 -f 'foxglove_bridge' 2>/dev/null || true
|
||||
pkill -9 -f 'gz sim' 2>/dev/null || true
|
||||
pkill -9 -f 'robot_state_publisher' 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
pids="$(ss -ltnp 2>/dev/null | grep ':9002 ' | sed -E 's/.*pid=([0-9]+).*/\1/' | sort -u || true)"
|
||||
if [[ -n "${pids}" ]]; then
|
||||
kill -9 ${pids} 2>/dev/null || true
|
||||
fi
|
||||
|
||||
rm -f /tmp/warehouse_gzsim.lock
|
||||
sleep 1
|
||||
|
||||
if ps aux | grep -E 'warehouse_gzweb|warehouse_foxglove|warehouse_gzsim_keepalive|gz-launch|gz sim' | grep -v grep >/dev/null; then
|
||||
echo "[stop] WARN: some processes may remain:"
|
||||
ps aux | grep -E 'warehouse_gzweb|warehouse_foxglove|warehouse_gzsim_keepalive|gz-launch|gz sim' | grep -v grep || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[stop] done. 9002 free, lock removed. Now run: ./gzsim_run.sh"
|
||||
|
|
@ -0,0 +1 @@
|
|||
isolated
|
||||
|
|
@ -0,0 +1,406 @@
|
|||
# Copyright 2016-2019 Dirk Thomas
|
||||
# Licensed under the Apache License, Version 2.0
|
||||
|
||||
import argparse
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
|
||||
FORMAT_STR_COMMENT_LINE = '# {comment}'
|
||||
FORMAT_STR_SET_ENV_VAR = 'Set-Item -Path "Env:{name}" -Value "{value}"'
|
||||
FORMAT_STR_USE_ENV_VAR = '$env:{name}'
|
||||
FORMAT_STR_INVOKE_SCRIPT = '_colcon_prefix_powershell_source_script "{script_path}"' # noqa: E501
|
||||
FORMAT_STR_REMOVE_LEADING_SEPARATOR = '' # noqa: E501
|
||||
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = '' # noqa: E501
|
||||
|
||||
DSV_TYPE_APPEND_NON_DUPLICATE = 'append-non-duplicate'
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE = 'prepend-non-duplicate'
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS = 'prepend-non-duplicate-if-exists'
|
||||
DSV_TYPE_SET = 'set'
|
||||
DSV_TYPE_SET_IF_UNSET = 'set-if-unset'
|
||||
DSV_TYPE_SOURCE = 'source'
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]): # noqa: D103
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Output shell commands for the packages in topological '
|
||||
'order')
|
||||
parser.add_argument(
|
||||
'primary_extension',
|
||||
help='The file extension of the primary shell')
|
||||
parser.add_argument(
|
||||
'additional_extension', nargs='?',
|
||||
help='The additional file extension to be considered')
|
||||
parser.add_argument(
|
||||
'--merged-install', action='store_true',
|
||||
help='All install prefixes are merged into a single location')
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
packages = get_packages(Path(__file__).parent, args.merged_install)
|
||||
|
||||
ordered_packages = order_packages(packages)
|
||||
for pkg_name in ordered_packages:
|
||||
if _include_comments():
|
||||
print(
|
||||
FORMAT_STR_COMMENT_LINE.format_map(
|
||||
{'comment': 'Package: ' + pkg_name}))
|
||||
prefix = os.path.abspath(os.path.dirname(__file__))
|
||||
if not args.merged_install:
|
||||
prefix = os.path.join(prefix, pkg_name)
|
||||
for line in get_commands(
|
||||
pkg_name, prefix, args.primary_extension,
|
||||
args.additional_extension
|
||||
):
|
||||
print(line)
|
||||
|
||||
for line in _remove_ending_separators():
|
||||
print(line)
|
||||
|
||||
|
||||
def get_packages(prefix_path, merged_install):
|
||||
"""
|
||||
Find packages based on colcon-specific files created during installation.
|
||||
|
||||
:param Path prefix_path: The install prefix path of all packages
|
||||
:param bool merged_install: The flag if the packages are all installed
|
||||
directly in the prefix or if each package is installed in a subdirectory
|
||||
named after the package
|
||||
:returns: A mapping from the package name to the set of runtime
|
||||
dependencies
|
||||
:rtype: dict
|
||||
"""
|
||||
packages = {}
|
||||
# since importing colcon_core isn't feasible here the following constant
|
||||
# must match colcon_core.location.get_relative_package_index_path()
|
||||
subdirectory = 'share/colcon-core/packages'
|
||||
if merged_install:
|
||||
# return if workspace is empty
|
||||
if not (prefix_path / subdirectory).is_dir():
|
||||
return packages
|
||||
# find all files in the subdirectory
|
||||
for p in (prefix_path / subdirectory).iterdir():
|
||||
if not p.is_file():
|
||||
continue
|
||||
if p.name.startswith('.'):
|
||||
continue
|
||||
add_package_runtime_dependencies(p, packages)
|
||||
else:
|
||||
# for each subdirectory look for the package specific file
|
||||
for p in prefix_path.iterdir():
|
||||
if not p.is_dir():
|
||||
continue
|
||||
if p.name.startswith('.'):
|
||||
continue
|
||||
p = p / subdirectory / p.name
|
||||
if p.is_file():
|
||||
add_package_runtime_dependencies(p, packages)
|
||||
|
||||
# remove unknown dependencies
|
||||
pkg_names = set(packages.keys())
|
||||
for k in packages.keys():
|
||||
packages[k] = {d for d in packages[k] if d in pkg_names}
|
||||
|
||||
return packages
|
||||
|
||||
|
||||
def add_package_runtime_dependencies(path, packages):
|
||||
"""
|
||||
Check the path and if it exists extract the packages runtime dependencies.
|
||||
|
||||
:param Path path: The resource file containing the runtime dependencies
|
||||
:param dict packages: A mapping from package names to the sets of runtime
|
||||
dependencies to add to
|
||||
"""
|
||||
content = path.read_text()
|
||||
dependencies = set(content.split(os.pathsep) if content else [])
|
||||
packages[path.name] = dependencies
|
||||
|
||||
|
||||
def order_packages(packages):
|
||||
"""
|
||||
Order packages topologically.
|
||||
|
||||
:param dict packages: A mapping from package name to the set of runtime
|
||||
dependencies
|
||||
:returns: The package names
|
||||
:rtype: list
|
||||
"""
|
||||
# select packages with no dependencies in alphabetical order
|
||||
to_be_ordered = list(packages.keys())
|
||||
ordered = []
|
||||
while to_be_ordered:
|
||||
pkg_names_without_deps = [
|
||||
name for name in to_be_ordered if not packages[name]]
|
||||
if not pkg_names_without_deps:
|
||||
reduce_cycle_set(packages)
|
||||
raise RuntimeError(
|
||||
'Circular dependency between: ' + ', '.join(sorted(packages)))
|
||||
pkg_names_without_deps.sort()
|
||||
pkg_name = pkg_names_without_deps[0]
|
||||
to_be_ordered.remove(pkg_name)
|
||||
ordered.append(pkg_name)
|
||||
# remove item from dependency lists
|
||||
for k in list(packages.keys()):
|
||||
if pkg_name in packages[k]:
|
||||
packages[k].remove(pkg_name)
|
||||
return ordered
|
||||
|
||||
|
||||
def reduce_cycle_set(packages):
|
||||
"""
|
||||
Reduce the set of packages to the ones part of the circular dependency.
|
||||
|
||||
:param dict packages: A mapping from package name to the set of runtime
|
||||
dependencies which is modified in place
|
||||
"""
|
||||
last_depended = None
|
||||
while len(packages) > 0:
|
||||
# get all remaining dependencies
|
||||
depended = set()
|
||||
for pkg_name, dependencies in packages.items():
|
||||
depended = depended.union(dependencies)
|
||||
# remove all packages which are not dependent on
|
||||
for name in list(packages.keys()):
|
||||
if name not in depended:
|
||||
del packages[name]
|
||||
if last_depended:
|
||||
# if remaining packages haven't changed return them
|
||||
if last_depended == depended:
|
||||
return packages.keys()
|
||||
# otherwise reduce again
|
||||
last_depended = depended
|
||||
|
||||
|
||||
def _include_comments():
|
||||
# skipping comment lines when COLCON_TRACE is not set speeds up the
|
||||
# processing especially on Windows
|
||||
return bool(os.environ.get('COLCON_TRACE'))
|
||||
|
||||
|
||||
def get_commands(pkg_name, prefix, primary_extension, additional_extension):
|
||||
commands = []
|
||||
package_dsv_path = os.path.join(prefix, 'share', pkg_name, 'package.dsv')
|
||||
if os.path.exists(package_dsv_path):
|
||||
commands += process_dsv_file(
|
||||
package_dsv_path, prefix, primary_extension, additional_extension)
|
||||
return commands
|
||||
|
||||
|
||||
def process_dsv_file(
|
||||
dsv_path, prefix, primary_extension=None, additional_extension=None
|
||||
):
|
||||
commands = []
|
||||
if _include_comments():
|
||||
commands.append(FORMAT_STR_COMMENT_LINE.format_map({
|
||||
'comment': dsv_path}))
|
||||
with open(dsv_path, 'r') as h:
|
||||
content = h.read()
|
||||
lines = content.splitlines()
|
||||
|
||||
basename_map = OrderedDict()
|
||||
for i, line in enumerate(lines):
|
||||
# skip over empty or whitespace-only lines
|
||||
if not line.strip():
|
||||
continue
|
||||
# skip over comments
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
try:
|
||||
type_, remainder = line.split(';', 1)
|
||||
except ValueError:
|
||||
raise RuntimeError(
|
||||
"Line %d in '%s' doesn't contain a semicolon separating the "
|
||||
'type from the arguments' % (i + 1, dsv_path))
|
||||
if type_ != DSV_TYPE_SOURCE:
|
||||
# handle non-source lines
|
||||
try:
|
||||
commands += handle_dsv_types_except_source(
|
||||
type_, remainder, prefix)
|
||||
except RuntimeError as e:
|
||||
raise RuntimeError(
|
||||
"Line %d in '%s' %s" % (i + 1, dsv_path, e)) from e
|
||||
else:
|
||||
# group remaining source lines by basename
|
||||
path_without_ext, ext = os.path.splitext(remainder)
|
||||
if path_without_ext not in basename_map:
|
||||
basename_map[path_without_ext] = set()
|
||||
assert ext.startswith('.')
|
||||
ext = ext[1:]
|
||||
if ext in (primary_extension, additional_extension):
|
||||
basename_map[path_without_ext].add(ext)
|
||||
|
||||
# add the dsv extension to each basename if the file exists
|
||||
for basename, extensions in basename_map.items():
|
||||
if not os.path.isabs(basename):
|
||||
basename = os.path.join(prefix, basename)
|
||||
if os.path.exists(basename + '.dsv'):
|
||||
extensions.add('dsv')
|
||||
|
||||
for basename, extensions in basename_map.items():
|
||||
if not os.path.isabs(basename):
|
||||
basename = os.path.join(prefix, basename)
|
||||
if 'dsv' in extensions:
|
||||
# process dsv files recursively
|
||||
commands += process_dsv_file(
|
||||
basename + '.dsv', prefix, primary_extension=primary_extension,
|
||||
additional_extension=additional_extension)
|
||||
elif primary_extension in extensions and len(extensions) == 1:
|
||||
# source primary-only files
|
||||
commands += [
|
||||
FORMAT_STR_INVOKE_SCRIPT.format_map({
|
||||
'prefix': prefix,
|
||||
'script_path': basename + '.' + primary_extension})]
|
||||
elif additional_extension in extensions:
|
||||
# source non-primary files
|
||||
commands += [
|
||||
FORMAT_STR_INVOKE_SCRIPT.format_map({
|
||||
'prefix': prefix,
|
||||
'script_path': basename + '.' + additional_extension})]
|
||||
|
||||
return commands
|
||||
|
||||
|
||||
def handle_dsv_types_except_source(type_, remainder, prefix):
|
||||
commands = []
|
||||
if type_ in (DSV_TYPE_SET, DSV_TYPE_SET_IF_UNSET):
|
||||
try:
|
||||
env_name, value = remainder.split(';', 1)
|
||||
except ValueError:
|
||||
raise RuntimeError(
|
||||
"doesn't contain a semicolon separating the environment name "
|
||||
'from the value')
|
||||
try_prefixed_value = os.path.join(prefix, value) if value else prefix
|
||||
if os.path.exists(try_prefixed_value):
|
||||
value = try_prefixed_value
|
||||
if type_ == DSV_TYPE_SET:
|
||||
commands += _set(env_name, value)
|
||||
elif type_ == DSV_TYPE_SET_IF_UNSET:
|
||||
commands += _set_if_unset(env_name, value)
|
||||
else:
|
||||
assert False
|
||||
elif type_ in (
|
||||
DSV_TYPE_APPEND_NON_DUPLICATE,
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE,
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS
|
||||
):
|
||||
try:
|
||||
env_name_and_values = remainder.split(';')
|
||||
except ValueError:
|
||||
raise RuntimeError(
|
||||
"doesn't contain a semicolon separating the environment name "
|
||||
'from the values')
|
||||
env_name = env_name_and_values[0]
|
||||
values = env_name_and_values[1:]
|
||||
for value in values:
|
||||
if not value:
|
||||
value = prefix
|
||||
elif not os.path.isabs(value):
|
||||
value = os.path.join(prefix, value)
|
||||
if (
|
||||
type_ == DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS and
|
||||
not os.path.exists(value)
|
||||
):
|
||||
comment = f'skip extending {env_name} with not existing ' \
|
||||
f'path: {value}'
|
||||
if _include_comments():
|
||||
commands.append(FORMAT_STR_COMMENT_LINE.format_map({
|
||||
'comment': comment}))
|
||||
elif type_ == DSV_TYPE_APPEND_NON_DUPLICATE:
|
||||
commands += _append_unique_value(env_name, value)
|
||||
else:
|
||||
commands += _prepend_unique_value(env_name, value)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'contains an unknown environment hook type: ' + type_)
|
||||
return commands
|
||||
|
||||
|
||||
env_state = {}
|
||||
|
||||
|
||||
def _append_unique_value(name, value):
|
||||
if name not in env_state:
|
||||
if os.environ.get(name):
|
||||
env_state[name] = set(os.environ[name].split(os.pathsep))
|
||||
else:
|
||||
env_state[name] = set()
|
||||
# Append even if the variable has not been set yet, in case a shell script
|
||||
# sets the same variable without the knowledge of this Python script.
|
||||
# Later, _remove_ending_separators() will cleanup any unintentional
|
||||
# leading separator.
|
||||
extend = FORMAT_STR_USE_ENV_VAR.format_map({'name': name}) + os.pathsep
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': extend + value})
|
||||
if value not in env_state[name]:
|
||||
env_state[name].add(value)
|
||||
else:
|
||||
if not _include_comments():
|
||||
return []
|
||||
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
|
||||
return [line]
|
||||
|
||||
|
||||
def _prepend_unique_value(name, value):
|
||||
if name not in env_state:
|
||||
if os.environ.get(name):
|
||||
env_state[name] = set(os.environ[name].split(os.pathsep))
|
||||
else:
|
||||
env_state[name] = set()
|
||||
# Prepend even if the variable has not been set yet, in case a shell script
|
||||
# sets the same variable without the knowledge of this Python script.
|
||||
# Later, _remove_ending_separators() will cleanup any unintentional
|
||||
# trailing separator.
|
||||
extend = os.pathsep + FORMAT_STR_USE_ENV_VAR.format_map({'name': name})
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': value + extend})
|
||||
if value not in env_state[name]:
|
||||
env_state[name].add(value)
|
||||
else:
|
||||
if not _include_comments():
|
||||
return []
|
||||
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
|
||||
return [line]
|
||||
|
||||
|
||||
# generate commands for removing prepended underscores
|
||||
def _remove_ending_separators():
|
||||
# do nothing if the shell extension does not implement the logic
|
||||
if FORMAT_STR_REMOVE_TRAILING_SEPARATOR is None:
|
||||
return []
|
||||
|
||||
commands = []
|
||||
for name in env_state:
|
||||
# skip variables that already had values before this script started
|
||||
# appending/prepending
|
||||
if name in os.environ:
|
||||
continue
|
||||
commands += [
|
||||
FORMAT_STR_REMOVE_LEADING_SEPARATOR.format_map({'name': name}),
|
||||
FORMAT_STR_REMOVE_TRAILING_SEPARATOR.format_map({'name': name})]
|
||||
return commands
|
||||
|
||||
|
||||
def _set(name, value):
|
||||
env_state[name] = value
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': value})
|
||||
return [line]
|
||||
|
||||
|
||||
def _set_if_unset(name, value):
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': value})
|
||||
if env_state.get(name, os.environ.get(name)):
|
||||
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
|
||||
return [line]
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
try:
|
||||
rc = main()
|
||||
except RuntimeError as e:
|
||||
print(str(e), file=sys.stderr)
|
||||
rc = 1
|
||||
sys.exit(rc)
|
||||
|
|
@ -0,0 +1,406 @@
|
|||
# Copyright 2016-2019 Dirk Thomas
|
||||
# Licensed under the Apache License, Version 2.0
|
||||
|
||||
import argparse
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
|
||||
FORMAT_STR_COMMENT_LINE = '# {comment}'
|
||||
FORMAT_STR_SET_ENV_VAR = 'export {name}="{value}"'
|
||||
FORMAT_STR_USE_ENV_VAR = '${name}'
|
||||
FORMAT_STR_INVOKE_SCRIPT = 'COLCON_CURRENT_PREFIX="{prefix}" _colcon_prefix_sh_source_script "{script_path}"' # noqa: E501
|
||||
FORMAT_STR_REMOVE_LEADING_SEPARATOR = 'export {name}=${{{name}#:}}' # noqa: E501
|
||||
FORMAT_STR_REMOVE_TRAILING_SEPARATOR = 'export {name}=${{{name}%:}}' # noqa: E501
|
||||
|
||||
DSV_TYPE_APPEND_NON_DUPLICATE = 'append-non-duplicate'
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE = 'prepend-non-duplicate'
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS = 'prepend-non-duplicate-if-exists'
|
||||
DSV_TYPE_SET = 'set'
|
||||
DSV_TYPE_SET_IF_UNSET = 'set-if-unset'
|
||||
DSV_TYPE_SOURCE = 'source'
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]): # noqa: D103
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Output shell commands for the packages in topological '
|
||||
'order')
|
||||
parser.add_argument(
|
||||
'primary_extension',
|
||||
help='The file extension of the primary shell')
|
||||
parser.add_argument(
|
||||
'additional_extension', nargs='?',
|
||||
help='The additional file extension to be considered')
|
||||
parser.add_argument(
|
||||
'--merged-install', action='store_true',
|
||||
help='All install prefixes are merged into a single location')
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
packages = get_packages(Path(__file__).parent, args.merged_install)
|
||||
|
||||
ordered_packages = order_packages(packages)
|
||||
for pkg_name in ordered_packages:
|
||||
if _include_comments():
|
||||
print(
|
||||
FORMAT_STR_COMMENT_LINE.format_map(
|
||||
{'comment': 'Package: ' + pkg_name}))
|
||||
prefix = os.path.abspath(os.path.dirname(__file__))
|
||||
if not args.merged_install:
|
||||
prefix = os.path.join(prefix, pkg_name)
|
||||
for line in get_commands(
|
||||
pkg_name, prefix, args.primary_extension,
|
||||
args.additional_extension
|
||||
):
|
||||
print(line)
|
||||
|
||||
for line in _remove_ending_separators():
|
||||
print(line)
|
||||
|
||||
|
||||
def get_packages(prefix_path, merged_install):
|
||||
"""
|
||||
Find packages based on colcon-specific files created during installation.
|
||||
|
||||
:param Path prefix_path: The install prefix path of all packages
|
||||
:param bool merged_install: The flag if the packages are all installed
|
||||
directly in the prefix or if each package is installed in a subdirectory
|
||||
named after the package
|
||||
:returns: A mapping from the package name to the set of runtime
|
||||
dependencies
|
||||
:rtype: dict
|
||||
"""
|
||||
packages = {}
|
||||
# since importing colcon_core isn't feasible here the following constant
|
||||
# must match colcon_core.location.get_relative_package_index_path()
|
||||
subdirectory = 'share/colcon-core/packages'
|
||||
if merged_install:
|
||||
# return if workspace is empty
|
||||
if not (prefix_path / subdirectory).is_dir():
|
||||
return packages
|
||||
# find all files in the subdirectory
|
||||
for p in (prefix_path / subdirectory).iterdir():
|
||||
if not p.is_file():
|
||||
continue
|
||||
if p.name.startswith('.'):
|
||||
continue
|
||||
add_package_runtime_dependencies(p, packages)
|
||||
else:
|
||||
# for each subdirectory look for the package specific file
|
||||
for p in prefix_path.iterdir():
|
||||
if not p.is_dir():
|
||||
continue
|
||||
if p.name.startswith('.'):
|
||||
continue
|
||||
p = p / subdirectory / p.name
|
||||
if p.is_file():
|
||||
add_package_runtime_dependencies(p, packages)
|
||||
|
||||
# remove unknown dependencies
|
||||
pkg_names = set(packages.keys())
|
||||
for k in packages.keys():
|
||||
packages[k] = {d for d in packages[k] if d in pkg_names}
|
||||
|
||||
return packages
|
||||
|
||||
|
||||
def add_package_runtime_dependencies(path, packages):
|
||||
"""
|
||||
Check the path and if it exists extract the packages runtime dependencies.
|
||||
|
||||
:param Path path: The resource file containing the runtime dependencies
|
||||
:param dict packages: A mapping from package names to the sets of runtime
|
||||
dependencies to add to
|
||||
"""
|
||||
content = path.read_text()
|
||||
dependencies = set(content.split(os.pathsep) if content else [])
|
||||
packages[path.name] = dependencies
|
||||
|
||||
|
||||
def order_packages(packages):
|
||||
"""
|
||||
Order packages topologically.
|
||||
|
||||
:param dict packages: A mapping from package name to the set of runtime
|
||||
dependencies
|
||||
:returns: The package names
|
||||
:rtype: list
|
||||
"""
|
||||
# select packages with no dependencies in alphabetical order
|
||||
to_be_ordered = list(packages.keys())
|
||||
ordered = []
|
||||
while to_be_ordered:
|
||||
pkg_names_without_deps = [
|
||||
name for name in to_be_ordered if not packages[name]]
|
||||
if not pkg_names_without_deps:
|
||||
reduce_cycle_set(packages)
|
||||
raise RuntimeError(
|
||||
'Circular dependency between: ' + ', '.join(sorted(packages)))
|
||||
pkg_names_without_deps.sort()
|
||||
pkg_name = pkg_names_without_deps[0]
|
||||
to_be_ordered.remove(pkg_name)
|
||||
ordered.append(pkg_name)
|
||||
# remove item from dependency lists
|
||||
for k in list(packages.keys()):
|
||||
if pkg_name in packages[k]:
|
||||
packages[k].remove(pkg_name)
|
||||
return ordered
|
||||
|
||||
|
||||
def reduce_cycle_set(packages):
|
||||
"""
|
||||
Reduce the set of packages to the ones part of the circular dependency.
|
||||
|
||||
:param dict packages: A mapping from package name to the set of runtime
|
||||
dependencies which is modified in place
|
||||
"""
|
||||
last_depended = None
|
||||
while len(packages) > 0:
|
||||
# get all remaining dependencies
|
||||
depended = set()
|
||||
for pkg_name, dependencies in packages.items():
|
||||
depended = depended.union(dependencies)
|
||||
# remove all packages which are not dependent on
|
||||
for name in list(packages.keys()):
|
||||
if name not in depended:
|
||||
del packages[name]
|
||||
if last_depended:
|
||||
# if remaining packages haven't changed return them
|
||||
if last_depended == depended:
|
||||
return packages.keys()
|
||||
# otherwise reduce again
|
||||
last_depended = depended
|
||||
|
||||
|
||||
def _include_comments():
|
||||
# skipping comment lines when COLCON_TRACE is not set speeds up the
|
||||
# processing especially on Windows
|
||||
return bool(os.environ.get('COLCON_TRACE'))
|
||||
|
||||
|
||||
def get_commands(pkg_name, prefix, primary_extension, additional_extension):
|
||||
commands = []
|
||||
package_dsv_path = os.path.join(prefix, 'share', pkg_name, 'package.dsv')
|
||||
if os.path.exists(package_dsv_path):
|
||||
commands += process_dsv_file(
|
||||
package_dsv_path, prefix, primary_extension, additional_extension)
|
||||
return commands
|
||||
|
||||
|
||||
def process_dsv_file(
|
||||
dsv_path, prefix, primary_extension=None, additional_extension=None
|
||||
):
|
||||
commands = []
|
||||
if _include_comments():
|
||||
commands.append(FORMAT_STR_COMMENT_LINE.format_map({
|
||||
'comment': dsv_path}))
|
||||
with open(dsv_path, 'r') as h:
|
||||
content = h.read()
|
||||
lines = content.splitlines()
|
||||
|
||||
basename_map = OrderedDict()
|
||||
for i, line in enumerate(lines):
|
||||
# skip over empty or whitespace-only lines
|
||||
if not line.strip():
|
||||
continue
|
||||
# skip over comments
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
try:
|
||||
type_, remainder = line.split(';', 1)
|
||||
except ValueError:
|
||||
raise RuntimeError(
|
||||
"Line %d in '%s' doesn't contain a semicolon separating the "
|
||||
'type from the arguments' % (i + 1, dsv_path))
|
||||
if type_ != DSV_TYPE_SOURCE:
|
||||
# handle non-source lines
|
||||
try:
|
||||
commands += handle_dsv_types_except_source(
|
||||
type_, remainder, prefix)
|
||||
except RuntimeError as e:
|
||||
raise RuntimeError(
|
||||
"Line %d in '%s' %s" % (i + 1, dsv_path, e)) from e
|
||||
else:
|
||||
# group remaining source lines by basename
|
||||
path_without_ext, ext = os.path.splitext(remainder)
|
||||
if path_without_ext not in basename_map:
|
||||
basename_map[path_without_ext] = set()
|
||||
assert ext.startswith('.')
|
||||
ext = ext[1:]
|
||||
if ext in (primary_extension, additional_extension):
|
||||
basename_map[path_without_ext].add(ext)
|
||||
|
||||
# add the dsv extension to each basename if the file exists
|
||||
for basename, extensions in basename_map.items():
|
||||
if not os.path.isabs(basename):
|
||||
basename = os.path.join(prefix, basename)
|
||||
if os.path.exists(basename + '.dsv'):
|
||||
extensions.add('dsv')
|
||||
|
||||
for basename, extensions in basename_map.items():
|
||||
if not os.path.isabs(basename):
|
||||
basename = os.path.join(prefix, basename)
|
||||
if 'dsv' in extensions:
|
||||
# process dsv files recursively
|
||||
commands += process_dsv_file(
|
||||
basename + '.dsv', prefix, primary_extension=primary_extension,
|
||||
additional_extension=additional_extension)
|
||||
elif primary_extension in extensions and len(extensions) == 1:
|
||||
# source primary-only files
|
||||
commands += [
|
||||
FORMAT_STR_INVOKE_SCRIPT.format_map({
|
||||
'prefix': prefix,
|
||||
'script_path': basename + '.' + primary_extension})]
|
||||
elif additional_extension in extensions:
|
||||
# source non-primary files
|
||||
commands += [
|
||||
FORMAT_STR_INVOKE_SCRIPT.format_map({
|
||||
'prefix': prefix,
|
||||
'script_path': basename + '.' + additional_extension})]
|
||||
|
||||
return commands
|
||||
|
||||
|
||||
def handle_dsv_types_except_source(type_, remainder, prefix):
|
||||
commands = []
|
||||
if type_ in (DSV_TYPE_SET, DSV_TYPE_SET_IF_UNSET):
|
||||
try:
|
||||
env_name, value = remainder.split(';', 1)
|
||||
except ValueError:
|
||||
raise RuntimeError(
|
||||
"doesn't contain a semicolon separating the environment name "
|
||||
'from the value')
|
||||
try_prefixed_value = os.path.join(prefix, value) if value else prefix
|
||||
if os.path.exists(try_prefixed_value):
|
||||
value = try_prefixed_value
|
||||
if type_ == DSV_TYPE_SET:
|
||||
commands += _set(env_name, value)
|
||||
elif type_ == DSV_TYPE_SET_IF_UNSET:
|
||||
commands += _set_if_unset(env_name, value)
|
||||
else:
|
||||
assert False
|
||||
elif type_ in (
|
||||
DSV_TYPE_APPEND_NON_DUPLICATE,
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE,
|
||||
DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS
|
||||
):
|
||||
try:
|
||||
env_name_and_values = remainder.split(';')
|
||||
except ValueError:
|
||||
raise RuntimeError(
|
||||
"doesn't contain a semicolon separating the environment name "
|
||||
'from the values')
|
||||
env_name = env_name_and_values[0]
|
||||
values = env_name_and_values[1:]
|
||||
for value in values:
|
||||
if not value:
|
||||
value = prefix
|
||||
elif not os.path.isabs(value):
|
||||
value = os.path.join(prefix, value)
|
||||
if (
|
||||
type_ == DSV_TYPE_PREPEND_NON_DUPLICATE_IF_EXISTS and
|
||||
not os.path.exists(value)
|
||||
):
|
||||
comment = f'skip extending {env_name} with not existing ' \
|
||||
f'path: {value}'
|
||||
if _include_comments():
|
||||
commands.append(FORMAT_STR_COMMENT_LINE.format_map({
|
||||
'comment': comment}))
|
||||
elif type_ == DSV_TYPE_APPEND_NON_DUPLICATE:
|
||||
commands += _append_unique_value(env_name, value)
|
||||
else:
|
||||
commands += _prepend_unique_value(env_name, value)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'contains an unknown environment hook type: ' + type_)
|
||||
return commands
|
||||
|
||||
|
||||
env_state = {}
|
||||
|
||||
|
||||
def _append_unique_value(name, value):
|
||||
if name not in env_state:
|
||||
if os.environ.get(name):
|
||||
env_state[name] = set(os.environ[name].split(os.pathsep))
|
||||
else:
|
||||
env_state[name] = set()
|
||||
# Append even if the variable has not been set yet, in case a shell script
|
||||
# sets the same variable without the knowledge of this Python script.
|
||||
# Later, _remove_ending_separators() will cleanup any unintentional
|
||||
# leading separator.
|
||||
extend = FORMAT_STR_USE_ENV_VAR.format_map({'name': name}) + os.pathsep
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': extend + value})
|
||||
if value not in env_state[name]:
|
||||
env_state[name].add(value)
|
||||
else:
|
||||
if not _include_comments():
|
||||
return []
|
||||
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
|
||||
return [line]
|
||||
|
||||
|
||||
def _prepend_unique_value(name, value):
|
||||
if name not in env_state:
|
||||
if os.environ.get(name):
|
||||
env_state[name] = set(os.environ[name].split(os.pathsep))
|
||||
else:
|
||||
env_state[name] = set()
|
||||
# Prepend even if the variable has not been set yet, in case a shell script
|
||||
# sets the same variable without the knowledge of this Python script.
|
||||
# Later, _remove_ending_separators() will cleanup any unintentional
|
||||
# trailing separator.
|
||||
extend = os.pathsep + FORMAT_STR_USE_ENV_VAR.format_map({'name': name})
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': value + extend})
|
||||
if value not in env_state[name]:
|
||||
env_state[name].add(value)
|
||||
else:
|
||||
if not _include_comments():
|
||||
return []
|
||||
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
|
||||
return [line]
|
||||
|
||||
|
||||
# generate commands for removing prepended underscores
|
||||
def _remove_ending_separators():
|
||||
# do nothing if the shell extension does not implement the logic
|
||||
if FORMAT_STR_REMOVE_TRAILING_SEPARATOR is None:
|
||||
return []
|
||||
|
||||
commands = []
|
||||
for name in env_state:
|
||||
# skip variables that already had values before this script started
|
||||
# appending/prepending
|
||||
if name in os.environ:
|
||||
continue
|
||||
commands += [
|
||||
FORMAT_STR_REMOVE_LEADING_SEPARATOR.format_map({'name': name}),
|
||||
FORMAT_STR_REMOVE_TRAILING_SEPARATOR.format_map({'name': name})]
|
||||
return commands
|
||||
|
||||
|
||||
def _set(name, value):
|
||||
env_state[name] = value
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': value})
|
||||
return [line]
|
||||
|
||||
|
||||
def _set_if_unset(name, value):
|
||||
line = FORMAT_STR_SET_ENV_VAR.format_map(
|
||||
{'name': name, 'value': value})
|
||||
if env_state.get(name, os.environ.get(name)):
|
||||
line = FORMAT_STR_COMMENT_LINE.format_map({'comment': line})
|
||||
return [line]
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
try:
|
||||
rc = main()
|
||||
except RuntimeError as e:
|
||||
print(str(e), file=sys.stderr)
|
||||
rc = 1
|
||||
sys.exit(rc)
|
||||
|
|
@ -0,0 +1 @@
|
|||
ament_index_python;launch;launch_ros;robot_state_publisher;xacro
|
||||
|
|
@ -0,0 +1 @@
|
|||
/workspace/install/bcr_bot:/opt/ros/humble
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# generated from ament/cmake/core/templates/nameConfig-version.cmake.in
|
||||
set(PACKAGE_VERSION "1.0.2")
|
||||
|
||||
set(PACKAGE_VERSION_EXACT False)
|
||||
set(PACKAGE_VERSION_COMPATIBLE False)
|
||||
|
||||
if("${PACKAGE_FIND_VERSION}" VERSION_EQUAL "${PACKAGE_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT True)
|
||||
set(PACKAGE_VERSION_COMPATIBLE True)
|
||||
endif()
|
||||
|
||||
if("${PACKAGE_FIND_VERSION}" VERSION_LESS "${PACKAGE_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE True)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
# generated from ament/cmake/core/templates/nameConfig.cmake.in
|
||||
|
||||
# prevent multiple inclusion
|
||||
if(_bcr_bot_CONFIG_INCLUDED)
|
||||
# ensure to keep the found flag the same
|
||||
if(NOT DEFINED bcr_bot_FOUND)
|
||||
# explicitly set it to FALSE, otherwise CMake will set it to TRUE
|
||||
set(bcr_bot_FOUND FALSE)
|
||||
elseif(NOT bcr_bot_FOUND)
|
||||
# use separate condition to avoid uninitialized variable warning
|
||||
set(bcr_bot_FOUND FALSE)
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
set(_bcr_bot_CONFIG_INCLUDED TRUE)
|
||||
|
||||
# output package information
|
||||
if(NOT bcr_bot_FIND_QUIETLY)
|
||||
message(STATUS "Found bcr_bot: 1.0.2 (${bcr_bot_DIR})")
|
||||
endif()
|
||||
|
||||
# warn when using a deprecated package
|
||||
if(NOT "" STREQUAL "")
|
||||
set(_msg "Package 'bcr_bot' is deprecated")
|
||||
# append custom deprecation text if available
|
||||
if(NOT "" STREQUAL "TRUE")
|
||||
set(_msg "${_msg} ()")
|
||||
endif()
|
||||
# optionally quiet the deprecation message
|
||||
if(NOT ${bcr_bot_DEPRECATED_QUIET})
|
||||
message(DEPRECATION "${_msg}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# flag package as ament-based to distinguish it after being find_package()-ed
|
||||
set(bcr_bot_FOUND_AMENT_PACKAGE TRUE)
|
||||
|
||||
# include all config extra files
|
||||
set(_extras "")
|
||||
foreach(_extra ${_extras})
|
||||
include("${bcr_bot_DIR}/${_extra}")
|
||||
endforeach()
|
||||
0
config/bcr_map.pgm → install/bcr_bot/share/bcr_bot/config/bcr_map.pgm
Executable file → Normal file
0
config/bcr_map.yaml → install/bcr_bot/share/bcr_bot/config/bcr_map.yaml
Executable file → Normal file
|
|
@ -0,0 +1 @@
|
|||
prepend-non-duplicate;AMENT_PREFIX_PATH;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# copied from
|
||||
# ament_cmake_core/cmake/environment_hooks/environment/ament_prefix_path.sh
|
||||
|
||||
ament_prepend_unique_value AMENT_PREFIX_PATH "$AMENT_CURRENT_PREFIX"
|
||||
|
|
@ -0,0 +1 @@
|
|||
prepend-non-duplicate-if-exists;PATH;bin
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# copied from ament_cmake_core/cmake/environment_hooks/environment/path.sh
|
||||
|
||||
if [ -d "$AMENT_CURRENT_PREFIX/bin" ]; then
|
||||
ament_prepend_unique_value PATH "$AMENT_CURRENT_PREFIX/bin"
|
||||
fi
|
||||
|
|
@ -0,0 +1 @@
|
|||
prepend-non-duplicate;CMAKE_PREFIX_PATH;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# generated from colcon_powershell/shell/template/hook_prepend_value.ps1.em
|
||||
|
||||
colcon_prepend_unique_value CMAKE_PREFIX_PATH "$env:COLCON_CURRENT_PREFIX"
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# generated from colcon_core/shell/template/hook_prepend_value.sh.em
|
||||
|
||||
_colcon_prepend_unique_value CMAKE_PREFIX_PATH "$COLCON_CURRENT_PREFIX"
|
||||
|
|
@ -19,7 +19,7 @@ def generate_launch_description():
|
|||
gz_sim = IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(join(gz_sim_share, "launch", "gz_sim.launch.py")),
|
||||
launch_arguments={
|
||||
"gz_args" : PythonExpression(["'", world_file, " -r'"])
|
||||
"gz_args" : PythonExpression(["'", world_file, " -r -s'"])
|
||||
|
||||
}.items()
|
||||
)
|
||||
0
launch/nav2.launch.py → install/bcr_bot/share/bcr_bot/launch/nav2.launch.py
Executable file → Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# generated from ament_package/template/package_level/local_setup.bash.in
|
||||
|
||||
# source local_setup.sh from same directory as this file
|
||||
_this_path=$(builtin cd "`dirname "${BASH_SOURCE[0]}"`" && pwd)
|
||||
# provide AMENT_CURRENT_PREFIX to shell script
|
||||
AMENT_CURRENT_PREFIX=$(builtin cd "`dirname "${BASH_SOURCE[0]}"`/../.." && pwd)
|
||||
# store AMENT_CURRENT_PREFIX to restore it before each environment hook
|
||||
_package_local_setup_AMENT_CURRENT_PREFIX=$AMENT_CURRENT_PREFIX
|
||||
|
||||
# trace output
|
||||
if [ -n "$AMENT_TRACE_SETUP_FILES" ]; then
|
||||
echo "# . \"$_this_path/local_setup.sh\""
|
||||
fi
|
||||
. "$_this_path/local_setup.sh"
|
||||
unset _this_path
|
||||
|
||||
# unset AMENT_ENVIRONMENT_HOOKS
|
||||
# if not appending to them for return
|
||||
if [ -z "$AMENT_RETURN_ENVIRONMENT_HOOKS" ]; then
|
||||
unset AMENT_ENVIRONMENT_HOOKS
|
||||
fi
|
||||
|
||||
# restore AMENT_CURRENT_PREFIX before evaluating the environment hooks
|
||||
AMENT_CURRENT_PREFIX=$_package_local_setup_AMENT_CURRENT_PREFIX
|
||||
# list all environment hooks of this package
|
||||
|
||||
# source all shell-specific environment hooks of this package
|
||||
# if not returning them
|
||||
if [ -z "$AMENT_RETURN_ENVIRONMENT_HOOKS" ]; then
|
||||
_package_local_setup_IFS=$IFS
|
||||
IFS=":"
|
||||
for _hook in $AMENT_ENVIRONMENT_HOOKS; do
|
||||
# restore AMENT_CURRENT_PREFIX for each environment hook
|
||||
AMENT_CURRENT_PREFIX=$_package_local_setup_AMENT_CURRENT_PREFIX
|
||||
# restore IFS before sourcing other files
|
||||
IFS=$_package_local_setup_IFS
|
||||
. "$_hook"
|
||||
done
|
||||
unset _hook
|
||||
IFS=$_package_local_setup_IFS
|
||||
unset _package_local_setup_IFS
|
||||
unset AMENT_ENVIRONMENT_HOOKS
|
||||
fi
|
||||
|
||||
unset _package_local_setup_AMENT_CURRENT_PREFIX
|
||||
unset AMENT_CURRENT_PREFIX
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
source;share/bcr_bot/environment/ament_prefix_path.sh
|
||||
source;share/bcr_bot/environment/path.sh
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
# generated from ament_package/template/package_level/local_setup.sh.in
|
||||
|
||||
# since this file is sourced use either the provided AMENT_CURRENT_PREFIX
|
||||
# or fall back to the destination set at configure time
|
||||
: ${AMENT_CURRENT_PREFIX:="/workspace/install/bcr_bot"}
|
||||
if [ ! -d "$AMENT_CURRENT_PREFIX" ]; then
|
||||
if [ -z "$COLCON_CURRENT_PREFIX" ]; then
|
||||
echo "The compile time prefix path '$AMENT_CURRENT_PREFIX' doesn't " \
|
||||
"exist. Consider sourcing a different extension than '.sh'." 1>&2
|
||||
else
|
||||
AMENT_CURRENT_PREFIX="$COLCON_CURRENT_PREFIX"
|
||||
fi
|
||||
fi
|
||||
|
||||
# function to append values to environment variables
|
||||
# using colons as separators and avoiding leading separators
|
||||
ament_append_value() {
|
||||
# arguments
|
||||
_listname="$1"
|
||||
_value="$2"
|
||||
#echo "listname $_listname"
|
||||
#eval echo "list value \$$_listname"
|
||||
#echo "value $_value"
|
||||
|
||||
# avoid leading separator
|
||||
eval _values=\"\$$_listname\"
|
||||
if [ -z "$_values" ]; then
|
||||
eval export $_listname=\"$_value\"
|
||||
#eval echo "set list \$$_listname"
|
||||
else
|
||||
# field separator must not be a colon
|
||||
_ament_append_value_IFS=$IFS
|
||||
unset IFS
|
||||
eval export $_listname=\"\$$_listname:$_value\"
|
||||
#eval echo "append list \$$_listname"
|
||||
IFS=$_ament_append_value_IFS
|
||||
unset _ament_append_value_IFS
|
||||
fi
|
||||
unset _values
|
||||
|
||||
unset _value
|
||||
unset _listname
|
||||
}
|
||||
|
||||
# function to append non-duplicate values to environment variables
|
||||
# using colons as separators and avoiding leading separators
|
||||
ament_append_unique_value() {
|
||||
# arguments
|
||||
_listname=$1
|
||||
_value=$2
|
||||
#echo "listname $_listname"
|
||||
#eval echo "list value \$$_listname"
|
||||
#echo "value $_value"
|
||||
|
||||
# check if the list contains the value
|
||||
eval _values=\$$_listname
|
||||
_duplicate=
|
||||
_ament_append_unique_value_IFS=$IFS
|
||||
IFS=":"
|
||||
if [ "$AMENT_SHELL" = "zsh" ]; then
|
||||
ament_zsh_to_array _values
|
||||
fi
|
||||
for _item in $_values; do
|
||||
# ignore empty strings
|
||||
if [ -z "$_item" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ $_item = $_value ]; then
|
||||
_duplicate=1
|
||||
fi
|
||||
done
|
||||
unset _item
|
||||
|
||||
# append only non-duplicates
|
||||
if [ -z "$_duplicate" ]; then
|
||||
# avoid leading separator
|
||||
if [ -z "$_values" ]; then
|
||||
eval $_listname=\"$_value\"
|
||||
#eval echo "set list \$$_listname"
|
||||
else
|
||||
# field separator must not be a colon
|
||||
unset IFS
|
||||
eval $_listname=\"\$$_listname:$_value\"
|
||||
#eval echo "append list \$$_listname"
|
||||
fi
|
||||
fi
|
||||
IFS=$_ament_append_unique_value_IFS
|
||||
unset _ament_append_unique_value_IFS
|
||||
unset _duplicate
|
||||
unset _values
|
||||
|
||||
unset _value
|
||||
unset _listname
|
||||
}
|
||||
|
||||
# function to prepend non-duplicate values to environment variables
|
||||
# using colons as separators and avoiding trailing separators
|
||||
ament_prepend_unique_value() {
|
||||
# arguments
|
||||
_listname="$1"
|
||||
_value="$2"
|
||||
#echo "listname $_listname"
|
||||
#eval echo "list value \$$_listname"
|
||||
#echo "value $_value"
|
||||
|
||||
# check if the list contains the value
|
||||
eval _values=\"\$$_listname\"
|
||||
_duplicate=
|
||||
_ament_prepend_unique_value_IFS=$IFS
|
||||
IFS=":"
|
||||
if [ "$AMENT_SHELL" = "zsh" ]; then
|
||||
ament_zsh_to_array _values
|
||||
fi
|
||||
for _item in $_values; do
|
||||
# ignore empty strings
|
||||
if [ -z "$_item" ]; then
|
||||
continue
|
||||
fi
|
||||
if [ "$_item" = "$_value" ]; then
|
||||
_duplicate=1
|
||||
fi
|
||||
done
|
||||
unset _item
|
||||
|
||||
# prepend only non-duplicates
|
||||
if [ -z "$_duplicate" ]; then
|
||||
# avoid trailing separator
|
||||
if [ -z "$_values" ]; then
|
||||
eval export $_listname=\"$_value\"
|
||||
#eval echo "set list \$$_listname"
|
||||
else
|
||||
# field separator must not be a colon
|
||||
unset IFS
|
||||
eval export $_listname=\"$_value:\$$_listname\"
|
||||
#eval echo "prepend list \$$_listname"
|
||||
fi
|
||||
fi
|
||||
IFS=$_ament_prepend_unique_value_IFS
|
||||
unset _ament_prepend_unique_value_IFS
|
||||
unset _duplicate
|
||||
unset _values
|
||||
|
||||
unset _value
|
||||
unset _listname
|
||||
}
|
||||
|
||||
# unset AMENT_ENVIRONMENT_HOOKS
|
||||
# if not appending to them for return
|
||||
if [ -z "$AMENT_RETURN_ENVIRONMENT_HOOKS" ]; then
|
||||
unset AMENT_ENVIRONMENT_HOOKS
|
||||
fi
|
||||
|
||||
# list all environment hooks of this package
|
||||
ament_append_value AMENT_ENVIRONMENT_HOOKS "$AMENT_CURRENT_PREFIX/share/bcr_bot/environment/ament_prefix_path.sh"
|
||||
ament_append_value AMENT_ENVIRONMENT_HOOKS "$AMENT_CURRENT_PREFIX/share/bcr_bot/environment/path.sh"
|
||||
|
||||
# source all shell-specific environment hooks of this package
|
||||
# if not returning them
|
||||
if [ -z "$AMENT_RETURN_ENVIRONMENT_HOOKS" ]; then
|
||||
_package_local_setup_IFS=$IFS
|
||||
IFS=":"
|
||||
if [ "$AMENT_SHELL" = "zsh" ]; then
|
||||
ament_zsh_to_array AMENT_ENVIRONMENT_HOOKS
|
||||
fi
|
||||
for _hook in $AMENT_ENVIRONMENT_HOOKS; do
|
||||
if [ -f "$_hook" ]; then
|
||||
# restore IFS before sourcing other files
|
||||
IFS=$_package_local_setup_IFS
|
||||
# trace output
|
||||
if [ -n "$AMENT_TRACE_SETUP_FILES" ]; then
|
||||
echo "# . \"$_hook\""
|
||||
fi
|
||||
. "$_hook"
|
||||
fi
|
||||
done
|
||||
unset _hook
|
||||
IFS=$_package_local_setup_IFS
|
||||
unset _package_local_setup_IFS
|
||||
unset AMENT_ENVIRONMENT_HOOKS
|
||||
fi
|
||||
|
||||
# reset AMENT_CURRENT_PREFIX after each package
|
||||
# allowing to source multiple package-level setup files
|
||||
unset AMENT_CURRENT_PREFIX
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
# generated from ament_package/template/package_level/local_setup.zsh.in
|
||||
|
||||
AMENT_SHELL=zsh
|
||||
|
||||
# source local_setup.sh from same directory as this file
|
||||
_this_path=$(builtin cd -q "`dirname "${(%):-%N}"`" > /dev/null && pwd)
|
||||
# provide AMENT_CURRENT_PREFIX to shell script
|
||||
AMENT_CURRENT_PREFIX=$(builtin cd -q "`dirname "${(%):-%N}"`/../.." > /dev/null && pwd)
|
||||
# store AMENT_CURRENT_PREFIX to restore it before each environment hook
|
||||
_package_local_setup_AMENT_CURRENT_PREFIX=$AMENT_CURRENT_PREFIX
|
||||
|
||||
# function to convert array-like strings into arrays
|
||||
# to wordaround SH_WORD_SPLIT not being set
|
||||
ament_zsh_to_array() {
|
||||
local _listname=$1
|
||||
local _dollar="$"
|
||||
local _split="{="
|
||||
local _to_array="(\"$_dollar$_split$_listname}\")"
|
||||
eval $_listname=$_to_array
|
||||
}
|
||||
|
||||
# trace output
|
||||
if [ -n "$AMENT_TRACE_SETUP_FILES" ]; then
|
||||
echo "# . \"$_this_path/local_setup.sh\""
|
||||
fi
|
||||
# the package-level local_setup file unsets AMENT_CURRENT_PREFIX
|
||||
. "$_this_path/local_setup.sh"
|
||||
unset _this_path
|
||||
|
||||
# unset AMENT_ENVIRONMENT_HOOKS
|
||||
# if not appending to them for return
|
||||
if [ -z "$AMENT_RETURN_ENVIRONMENT_HOOKS" ]; then
|
||||
unset AMENT_ENVIRONMENT_HOOKS
|
||||
fi
|
||||
|
||||
# restore AMENT_CURRENT_PREFIX before evaluating the environment hooks
|
||||
AMENT_CURRENT_PREFIX=$_package_local_setup_AMENT_CURRENT_PREFIX
|
||||
# list all environment hooks of this package
|
||||
|
||||
# source all shell-specific environment hooks of this package
|
||||
# if not returning them
|
||||
if [ -z "$AMENT_RETURN_ENVIRONMENT_HOOKS" ]; then
|
||||
_package_local_setup_IFS=$IFS
|
||||
IFS=":"
|
||||
for _hook in $AMENT_ENVIRONMENT_HOOKS; do
|
||||
# restore AMENT_CURRENT_PREFIX for each environment hook
|
||||
AMENT_CURRENT_PREFIX=$_package_local_setup_AMENT_CURRENT_PREFIX
|
||||
# restore IFS before sourcing other files
|
||||
IFS=$_package_local_setup_IFS
|
||||
. "$_hook"
|
||||
done
|
||||
unset _hook
|
||||
IFS=$_package_local_setup_IFS
|
||||
unset _package_local_setup_IFS
|
||||
unset AMENT_ENVIRONMENT_HOOKS
|
||||
fi
|
||||
|
||||
unset _package_local_setup_AMENT_CURRENT_PREFIX
|
||||
unset AMENT_CURRENT_PREFIX
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 223 KiB |
|
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 335 KiB After Width: | Height: | Size: 335 KiB |
|
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 660 KiB After Width: | Height: | Size: 660 KiB |
|
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |