This commit is contained in:
hq 2026-07-26 13:40:02 +08:00
parent 2f6a498e4a
commit b98663e589
323 changed files with 80970 additions and 316 deletions

0
.gitattributes vendored Normal file
View File

22
.gitignore vendored
View File

@ -1,19 +1,7 @@
# Python build/
log/
autorun_logs/
__pycache__/ __pycache__/
*.pyc *.pyc
*.log
# ROS node_modules/
build/
devel/
logs/
install/
build_isolated/
devel_isolated/
*.bag
CATKIN_IGNORE
# Misc
.vscode/
*.swp
log/
test/

1
.space_id Normal file
View File

@ -0,0 +1 @@
2361156b428d4ec3b304debed63dfe7e

312
README.md
View File

@ -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) ![迷你仓库场景预览](doc/assets/warehouse_preview.png)
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 ```bash
# From the root directory of the workspace. This will install everything mentioned in package.xml ./gzsim_run.sh
rosdep install --from-paths src --ignore-src -r -y
| `./gzsim_stop.sh` | 停止仿真 |
``` ```
### Source Build **必须等到**终端出现:
```bash ```text
catkin build --packages-select bcr_bot [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):
![](res/gz.jpg)
2. Isaac Sim:
![](res/isaac.jpg)
3. Rviz (Depth camera) (small_warehouse World):
![](res/rviz.jpg)

3
autorun.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
# 容器 INIT_SCRIPT 入口 — 仅调用唯一启动脚本
exec /workspace/gzsim_run.sh

40
doc.md Normal file
View File

@ -0,0 +1,40 @@
# 仓库 3D 场景
## 场景预览
![迷你仓库场景预览](doc/assets/warehouse_preview.png)
---
## 启动(唯一命令,无需编译)
卡片内已包含预编译 `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
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

14
gzsim_check.sh Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
# 简要诊断 :9002 / gz-launchGzWeb 使用 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/"

56
gzsim_run.sh Executable file
View File

@ -0,0 +1,56 @@
#!/usr/bin/env bash
# GzWeb 仓库场景 — Gazebo Sim + gz-launch :9002GzWeb 连 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

52
gzsim_run.sh.bak.20260724034245 Executable file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env bash
# GzWeb 仓库场景 — Gazebo Sim + gz-launch :9002GzWeb 连 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

31
gzsim_stop.sh Executable file
View File

@ -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"

View File

@ -0,0 +1 @@
isolated

0
install/COLCON_IGNORE Normal file
View File

View File

@ -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)

View File

@ -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)

View File

View File

@ -0,0 +1 @@
ament_index_python;launch;launch_ros;robot_state_publisher;xacro

View File

@ -0,0 +1 @@
/workspace/install/bcr_bot:/opt/ros/humble

View File

@ -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()

View File

@ -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()

View File

@ -0,0 +1 @@
prepend-non-duplicate;AMENT_PREFIX_PATH;

View File

@ -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"

View File

@ -0,0 +1 @@
prepend-non-duplicate-if-exists;PATH;bin

View File

@ -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

View File

@ -0,0 +1 @@
prepend-non-duplicate;CMAKE_PREFIX_PATH;

View File

@ -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"

View File

@ -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"

View File

@ -19,7 +19,7 @@ def generate_launch_description():
gz_sim = IncludeLaunchDescription( gz_sim = IncludeLaunchDescription(
PythonLaunchDescriptionSource(join(gz_sim_share, "launch", "gz_sim.launch.py")), PythonLaunchDescriptionSource(join(gz_sim_share, "launch", "gz_sim.launch.py")),
launch_arguments={ launch_arguments={
"gz_args" : PythonExpression(["'", world_file, " -r'"]) "gz_args" : PythonExpression(["'", world_file, " -r -s'"])
}.items() }.items()
) )

View 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

View File

@ -0,0 +1,2 @@
source;share/bcr_bot/environment/ament_prefix_path.sh
source;share/bcr_bot/environment/path.sh

View File

@ -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

View File

@ -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

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Some files were not shown because too many files have changed in this diff Show More