Merge branch 'main' into 109-nix-jazzy

This commit is contained in:
Игорь Брылёв 2024-12-01 15:59:42 +03:00
commit ec2cebe5f1
46 changed files with 2696 additions and 1844 deletions

View file

@ -1,46 +1,65 @@
FROM billf1nger/ros2-humble-cuda:v12.2.2-cudnn8-ubuntu22.04-gz-nvidia
FROM nvidia/cuda:12.6.2-cudnn-devel-ubuntu22.04
ARG WSDIR=rbs_ws
ARG config_type=sim
ENV RBS_ASSEMBLY_DIR=/assembly
ENV DEBIAN_FRONTEND=noninteractive
# COPY /home/bill-finger/assembly /assembly
ENV IGN_GAZEBO_RESOURCE_PATH=/${WSDIR}/install/rbs_simulation/share/rbs_simulation/
RUN apt update && apt install -y \
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
git \
software-properties-common \
python3-pip \
lsb-release \
wget \
gnupg
curl \
wget
RUN pip install vcstool
WORKDIR /libs
RUN wget https://github.com/nlohmann/json/archive/refs/tags/v3.11.3.tar.gz &&\
tar -xf v3.11.3.tar.gz &&\
cd json-3.11.3 &&\
mkdir build &&\
cd build &&\
cmake .. &&\
make &&\
make install
# WORKDIR /libs
# RUN wget https://github.com/nlohmann/json/archive/refs/tags/v3.11.3.tar.gz &&\
# tar -xf v3.11.3.tar.gz &&\
# cd json-3.11.3 &&\
# mkdir build &&\
# cd build &&\
# cmake .. &&\
# make &&\
# make install
RUN git clone https://gitlab.com/robossembler/forks/megapose6d.git &&\
cd megapose6d &&\
pip install bokeh joblib pin torch transforms3d webdataset omegaconf tqdm &&\
pip install -e .
RUN git clone https://github.com/thodan/bop_toolkit &&\
cd bop_toolkit &&\
pip install -e .
RUN add-apt-repository universe
RUN curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null
RUN apt-get update && apt-get upgrade && apt-get install -y ros-humble-ros-base
# RUN git clone https://gitlab.com/robossembler/forks/megapose6d.git &&\
# cd megapose6d &&\
# pip install bokeh joblib pin torch transforms3d webdataset omegaconf tqdm &&\
# pip install -e .
# RUN git clone https://github.com/thodan/bop_toolkit &&\
# cd bop_toolkit &&\
# pip install -e .
WORKDIR /${WSDIR}
COPY . src/robossembler-ros2/
RUN vcs import src/. < src/robossembler-ros2/rbs.${config_type}.repos
RUN apt update && rosdep update && \
RUN pip install vcstool uv
# Install framework and dependencies
RUN vcs import src/. < src/robossembler-ros2/repos/all-deps.repos
RUN uv pip install --system -r src/robossembler-ros2/repos/requirements.txt
RUN apt-get update && rosdep update && \
rosdep install -y -r -q --from-paths src --ignore-src --rosdistro humble
RUN . /opt/ros/humble/setup.sh && \
colcon build --symlink-install --cmake-args -DCMAKE_EXPORT_COMPILE_COMMANDS=1
WORKDIR /${RBS_ASSEMBLY_DIR}
RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
RUN apt-get install git-lfs
RUN git clone https://github.com/solid-sinusoid/rbs_assets_library.git
RUN cd rbs_assets_library && git lfs pull && pip install -e .
WORKDIR /${WSDIR}

110
doc/en/add_new_robot.md Normal file
View file

@ -0,0 +1,110 @@
# Instructions for Adding a New Robot to the Robossembler ROS 2 Framework
First, you need to download the robot package containing `xacro` or `urdf` files, as well as geometry files in formats such as `.stl`, `.dae`, `.obj`, etc.
Before starting, it is important to understand the basics of the [xacro](https://github.com/ros/xacro/wiki) format. This format allows you to reuse existing fragments of a robot's URDF description, making it easier to create and modify descriptions.
### Steps for Adding a New Robot:
1. **Install the Robot Package**
After installing the robot package, create a file named `xacro_args.yaml` in the `{description_package}/config/` directory. This file should specify the arguments needed to convert the `xacro` file into a `urdf`.
2. **Configure the Launch File**
Edit the file [`rbs_bringup.launch.py`](../../rbs_bringup/launch/rbs_bringup.launch.py) to define the parameters required to launch the robot.
Example of a standard implementation:
```python
main_script = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[FindPackageShare("rbs_runtime"), "launch", "runtime.launch.py"]
)
]
),
launch_arguments={
"with_gripper": "true",
"gripper_name": "rbs_gripper",
"robot_type": "rbs_arm",
"description_package": "rbs_arm",
"description_file": "rbs_arm_modular.xacro",
"robot_name": "rbs_arm",
"use_moveit": "false",
"moveit_config_package": "rbs_arm",
"moveit_config_file": "rbs_arm.srdf.xacro",
"use_sim_time": "true",
"hardware": "gazebo",
"use_controllers": "true",
"scene_config_file": "",
"base_link_name": "base_link",
"ee_link_name": "gripper_grasp_point",
}.items(),
)
```
This configuration launches another file with specific arguments. Below is a description of each argument to help you decide whether it is needed.
### Parameter Descriptions:
- **`with_gripper`**
Indicates whether the robot has a gripper. If set to `true`, the `gripper_controller` will be configured and launched.
- **`gripper_name`**
Used as a keyword to identify links and joints related to the gripper. It is also applied in `xacro` arguments.
- **`robot_type`**
Specifies a group of robots of the same type, allowing you to semantically group robots with different names but similar designs.
- **`description_package`**
The package containing the robot's URDF description. This parameter is mandatory and is used to locate the URDF file and controller configuration files.
- **`description_file`**
The name of the description file, which should be located in `{description_package}/urdf/`.
- **`robot_name`**
A unique name for the robot to distinguish it from others in the scene.
- **`use_moveit`**
Indicates whether [MoveIt 2](https://moveit.picknik.ai/humble/index.html) should be used. While it is not required for basic movements, it is recommended when working with obstacles.
- **`moveit_config_package`**
The name of the MoveIt 2 configuration package generated based on the `{description_package}`. This parameter is required if you plan to use MoveIt 2.
- **`moveit_config_file`**
The MoveIt 2 launch file located in `{moveit_config_package}/launch/`.
- **`use_sim_time`**
A mandatory parameter for simulation. It ensures that time is synchronized with the simulator.
- **`hardware`**
Specifies the interface to be used for controlling the robot. For example, `gazebo`. This parameter is primarily used in `xacro` files.
- **`use_controllers`**
Indicates whether to use standard controllers. If set to `false`, the robot will not be able to move. This parameter controls the execution of the [control.launch.py](../../rbs_bringup/launch/control.launch.py) file. You can write a custom implementation instead of using this flag.
- **`scene_config_file`**
A YAML file that defines the scene configuration. A default example is available [here](../../env_manager/rbs_runtime/config/default-scene-config.yaml). Ensure that the degrees of freedom of your robot match the configuration file.
- **`base_link_name`**
The name of the robot's base link, which defines where the robot begins. This parameter is important for skill configuration. Review your robot's URDF to set this correctly.
- **`ee_link_name`**
The name of the end-effector link, which defines where the robot ends. This parameter is also important for skill configuration and should be set based on the URDF.
- **`control_space`**
Specifies the space in which the robot will be controlled.
Possible values:
- `task` — control in task space (e.g., using positions and orientations in the workspace).
- `joint` — control in joint space (e.g., using angular values for each robot joint).
Default value: `task`.
- **`control_strategy`**
Specifies the control strategy for the robot.
Possible values:
- `position` — position control, where desired positions are set for joints or the workspace target point.
- `velocity` — velocity control, where desired movement speeds are set.
- `effort` — effort control, where torques or forces applied to the joints are specified.
Default value: `position`.
- **`interactive`**
Specifies whether to run the `motion_control_handle` controller.
Default value: `true`.

18
doc/en/index.md Normal file
View file

@ -0,0 +1,18 @@
Robossembler ROS 2 Packages
- **`env_manager`** - virtual environment manager:
- **`env_manager`** - manages objects in Gazebo simulation scenes.
- **`env_manager_interfaces`** - ROS 2 interfaces for configuring, loading, activating, and unloading environments.
- **`rbs_gym`** - reinforcement learning module: training management, simulation environment creation, action and observation space handling, utilities.
- **`rbs_runtime`** - runs the main runtime using `env_manager`.
- **`rbs_bringup`** - launch scenarios: simulation, real robot, multi-robot configurations.
- **`rbs_bt_executor`** - executes behavior trees with Behavior Tree CPP v4.
- **`rbs_interface`** - interface linking behavior trees with skill servers (recommended to merge with `rbs_bt_executor`).
- **`rbs_perception`** - machine vision module with multiple implementations.
- **`rbs_simulation`** - simulation models (recommended to merge with `env_manager` or `rbs_gym`).
- **`rbs_skill_interfaces`** - common interfaces for interacting with skill servers and behavior trees.
- **`rbs_skill_servers`** - packages for skill servers (recommended to replace with individual packages for each server).
- **`rbs_task_planner`** - task planner based on PDDL.
- **`rbs_utils`** - utilities for working with configurations containing grasp positions.
- **`rbss_objectdetection`** - skill server for object detection using YOLOv8.

View file

@ -1,20 +0,0 @@
Robossembler ROS 2 Packages
- `env_manager` - менеджер переключения виртуальных сред
- `env_interface` - базовый класс для создания конкретной среды на базе ROS 2 LifeCycle Node
- `env_manager` - основной пакет менеджера переключения виртуальных сред
- `env_manager_interfaces` - интерфейсы ROS 2 для env_manager, описывают сообщения о состоянии среды, сервисы по конфигурации/загрузке/включению/выгрузке среды
- `gz_environment` - конкретный экземпляр `env_interface` для симулятора Gazebo
- `planning_scene_manager` - управление сценой планирования для MoveIt (среда для MoveIt)
- `rbs_gym` - модуль обучения с подреплением: управление процесом обучения, формирование сред симуляции, управление пространствами действий(actions) и восприятия(observation), управление задачами, утилиты
- `rbs_bringup` - пакет для запуска разных launch сценариев: симуляция, реальный робот, разные конфигурации оборудования (multi-robot)
- `rbs_bt_executor` - модуль запуска деревьев поведения на Behavior Tree CPP v4
- `rbs_interface` - пакет для связывания деревьев со скилл-серверами (объединить с - `rbs_bt_executor`)
- `rbs_perception` - модуль машинного восприятия, где реализованы разные версии
- `rbs_simulation` - модели для симуляции (к удалить или объединить с env_manager/rbs_gym)
- `rbs_skill_interfaces` - общеиспользуемые (common) интерфейсы для взаимодействия с Серверами Навыков и Деревом поведения (специфичные интерфейсы размещаются в пакетах Серверов Навыков)
- `rbs_skill_servers` - пакеты Серверов Навыков (упразднить, для каждого Сервера Навыков свой пакет)
- `rbs_task_planner` - планировщик задач на базе PDDL
- `rbs_utils` - работа с конфигом, содержащим позиции захвата для деталей
- `rbss_objectdetection` - Сервер Навыка обнаружения объектов с помощью YOLOv8

112
doc/ru/add_new_robot.md Normal file
View file

@ -0,0 +1,112 @@
# Инструкция по добавлению нового робота в фреймворк Robossembler ROS 2
Прежде всего необходимо скачать пакет робота, содержащий файлы `xacro` или `urdf`, а также файлы геометрии робота в формате `.stl`, `.dae`, `.obj` и других.
Перед началом работы важно ознакомиться с основными аспектами формата [xacro](https://github.com/ros/xacro/wiki). Этот формат позволяет переиспользовать существующие фрагменты URDF-описания робота, что упрощает создание и модификацию описания.
### Шаги по добавлению нового робота:
1. **Установка пакета робота**
После установки пакета робота создайте файл `xacro_args.yaml` в директории `{description_package}/config/`. В этом файле необходимо указать аргументы для преобразования xacro-файла в URDF.
2. **Настройка запуска**
Отредактируйте файл [`rbs_bringup.launch.py`](../../rbs_bringup/launch/rbs_bringup.launch.py), указав параметры для запуска робота.
Пример стандартной реализации:
```python
main_script = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[FindPackageShare("rbs_runtime"), "launch", "runtime.launch.py"]
)
]
),
launch_arguments={
"with_gripper": "true",
"gripper_name": "rbs_gripper",
"robot_type": "rbs_arm",
"description_package": "rbs_arm",
"description_file": "rbs_arm_modular.xacro",
"robot_name": "rbs_arm",
"use_moveit": "false",
"moveit_config_package": "rbs_arm",
"moveit_config_file": "rbs_arm.srdf.xacro",
"use_sim_time": "true",
"hardware": "gazebo",
"use_controllers": "true",
"scene_config_file": "",
"base_link_name": "base_link",
"ee_link_name": "gripper_grasp_point",
"control_space": "task",
"control_strategy": "position",
}.items(),
)
```
Здесь выполняется запуск другого launch-файла с указанными аргументами. Ниже приводится описание каждого аргумента.
### Описание параметров:
- **`with_gripper`**
Указывает, есть ли на роботе захватное устройство (гриппер). Если значение `true`, будет настроен и запущен `gripper_controller`.
- **`gripper_name`**
Используется как ключевое слово для указания линков и джоинтов, относящихся к грипперу. Также применяется в xacro-аргументах.
- **`robot_type`**
Обозначает группу роботов одного типа. Например, все роботы с разными именами, но одинаковой конструкцией.
- **`description_package`**
Пакет, содержащий описание URDF робота. Обязательный параметр. Используется для определения пути к файлу описания и конфигурации контроллеров.
- **`description_file`**
Имя файла описания, который должен находиться в `{description_package}/urdf/`.
- **`robot_name`**
Уникальное имя робота, которое позволяет отличить его от других в сцене.
- **`use_moveit`**
Указывает, нужно ли использовать [MoveIt 2](https://moveit.picknik.ai/humble/index.html). Для базовых перемещений MoveIt 2 не обязателен, но для работы с препятствиями рекомендуется его включить.
- **`moveit_config_package`**
Имя пакета конфигурации MoveIt 2, который генерируется на основе `{description_package}`. Обязательный параметр, если используется MoveIt 2.
- **`moveit_config_file`**
Файл запуска MoveIt 2, находящийся в `{moveit_config_package}/launch/`.
- **`use_sim_time`**
Обязательный параметр при работе в симуляции. Обеспечивает синхронизацию времени с симулятором.
- **`hardware`**
Указывает интерфейс для управления роботом. Например, `gazebo`. Используется в основном в xacro-файлах.
- **`use_controllers`**
Указывает, нужно ли использовать стандартные контроллеры. Если значение `false`, робот не сможет двигаться. Влияет на запуск файла [control.launch.py](../../rbs_bringup/launch/control.launch.py).
- **`scene_config_file`**
Файл конфигурации сцены в формате YAML. Пример можно найти [здесь](../../env_manager/rbs_runtime/config/default-scene-config.yaml). Обратите внимание на соответствие количества степеней свободы робота.
- **`base_link_name`**
Имя базового линка, от которого начинается робот. Важно для настройки навыков. Рекомендуется свериться с URDF.
- **`ee_link_name`**
Имя конечного линка (энд-эффектора), где заканчивается робот. Этот параметр также настраивается на основе URDF.
- **`control_space`**
Указывает, в каком пространстве робот будет управляться.
Возможные значения:
- `task` — управление в пространстве задач (например, с использованием позиций и ориентации в рабочем пространстве).
- `joint` — управление в пространстве суставов (например, с использованием угловых значений для каждого сустава робота).
Значение по умолчанию: `task`.
- **`control_strategy`**
Указывает стратегию управления роботом.
Возможные значения:
- `position` — управление положением, когда задаются желаемые позиции для суставов или рабочей точки.
- `velocity` — управление скоростью, когда задаются желаемые скорости движения.
- `effort` — управление усилием, когда задаются моменты или силы, прикладываемые к суставам.
Значение по умолчанию: `position`.
- **`interactive`**
Указывает, нужно ли запускать контроллер `motion_control_handle`.
Значение по умолчанию: `true`.

18
doc/ru/index.md Normal file
View file

@ -0,0 +1,18 @@
# Robossembler ROS 2 Packages
- **`env_manager`** - менеджер виртуальных сред:
- **`env_manager`** - управление объектами в сцене симуляции Gazebo.
- **`env_manager_interfaces`** - ROS 2 интерфейсы для конфигурации, загрузки, активации и выгрузки сред.
- **`rbs_gym`** - модуль обучения с подкреплением: управление обучением, создание симуляционных сред, управление пространствами действий и наблюдений, утилиты.
- **`rbs_runtime`** - запуск основного рантайма с использованием `env_manager`.
- **`rbs_bringup`** - запуск сценариев: симуляция, реальный робот, многороботные конфигурации.
- **`rbs_bt_executor`** - выполнение деревьев поведения с Behavior Tree CPP v4.
- **`rbs_interface`** - интерфейс для связи деревьев поведения со скилл-серверами (рекомендуется объединить с `rbs_bt_executor`).
- **`rbs_perception`** - модуль машинного зрения с различными версиями.
- **`rbs_simulation`** - модели для симуляции (рекомендуется объединить с `env_manager` или `rbs_gym`).
- **`rbs_skill_interfaces`** - общие интерфейсы для взаимодействия с скилл-серверами и деревьями поведения.
- **`rbs_skill_servers`** - пакеты для скилл-серверов (рекомендуется заменить на индивидуальные пакеты для каждого сервера).
- **`rbs_task_planner`** - планировщик задач на основе PDDL.
- **`rbs_utils`** - утилиты для работы с конфигурациями, содержащими позиции захвата.
- **`rbss_objectdetection`** - скилл-сервер для обнаружения объектов с YOLOv8.

32
doc/ru/installation.md Normal file
View file

@ -0,0 +1,32 @@
# Инструкция по установке фреймворка
Первым делом необходимо установить [ROS2 Humble](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debs.html). Рекомендуется минимальная установка.
Вторым делом надо собрать [`ros2_control`](https://github.com/ros-controls/ros2_control) из исходников из этого [форка](https://github.com/solid-sinusoid/ros2_control/tree/gz-ros2-cartesian-controllers) стоит отметить, что также существует альтернативная установка с использованием [`vsctool`](https://github.com/dirk-thomas/vcstool) который поставляется с базовыми пакетами ROS2.
Если устанавливать через `vcstool` тогда необходимые пакеты будут клонированы в тоже рабочее пространство, что и сам фреймворк. Сама команда будет выглядеть так
```sh
vcs import . < robossembler-ros2/repos/all-deps.repos
```
Заодно можно выполнить команду для установки всех требуемых библиотек Python
```shell
pip insatll -r robossembler-ros2/repos/requirements.txt
```
При этом команду надо выполнять в директории `{robossembler_ws}/src/`
Более четкая последовательность команд кому лень:
```sh
cd
mkdir -p robossembler-ros2/src && cd robossembler-ros2
git clone git clone https://seed.robossembler.org/z46gtVRpXaXrGQM7Fxiqu7pLy7kip.git robossembler-ros2
# Или если вы предпочитаете radicle
rad clone rad:z46gtVRpXaXrGQM7Fxiqu7pLy7kip
cd src
vcs import . < robossembler-ros2/repos/all-deps.repos
pip insatll -r robossembler-ros2/repos/requirements.txt
cd ..
rosdep install --from-paths src -y --ignore-src
colcon build --symlink-install
```

View file

@ -27,4 +27,7 @@ class TerrainData:
spawn_position: tuple[float, float, float] = field(default=(0, 0, 0))
spawn_quat_xyzw: tuple[float, float, float, float] = field(default=(0, 0, 0, 1))
size: tuple[float, float] = field(default=(1.5, 1.5))
ambient: tuple[float, float, float, float] = field(default=(0.8, 0.8, 0.8, 1.0))
specular: tuple[float, float, float, float] = field(default=(0.8, 0.8, 0.8, 1.0))
diffuse: tuple[float, float, float, float] = field(default=(0.8, 0.8, 0.8, 1.0))
model_rollouts_num: int = field(default=1)

View file

@ -20,6 +20,9 @@ class Ground(model_wrapper.ModelWrapper):
size (tuple[float, float], optional): The size of the ground plane. Defaults to (1.5, 1.5).
collision_thickness (float, optional): The thickness of the collision surface. Defaults to 0.05.
friction (float, optional): The friction coefficient for the ground surface. Defaults to 5.0.
ambient (tuple[float, float, float, float], optional): The ambient color of the material. Defaults to (0.8, 0.8, 0.8, 1.0).
specular (tuple[float, float, float, float], optional): The specular color of the material. Defaults to (0.8, 0.8, 0.8, 1.0).
diffuse (tuple[float, float, float, float], optional): The diffuse color of the material. Defaults to (0.8, 0.8, 0.8, 1.0).
**kwargs: Additional keyword arguments for future extensions.
Raises:
@ -35,6 +38,9 @@ class Ground(model_wrapper.ModelWrapper):
size: tuple[float, float] = (1.5, 1.5),
collision_thickness=0.05,
friction: float = 5.0,
ambient: tuple[float, float, float, float] = (0.8, 0.8, 0.8, 1.0),
specular: tuple[float, float, float, float] = (0.8, 0.8, 0.8, 1.0),
diffuse: tuple[float, float, float, float] = (0.8, 0.8, 0.8, 1.0),
**kwargs,
):
# Get a unique model name
@ -43,7 +49,7 @@ class Ground(model_wrapper.ModelWrapper):
# Initial pose
initial_pose = scenario_core.Pose(position, orientation)
# Create SDF string for the model
# Create SDF string for the model with the provided material properties
sdf = f"""<sdf version="1.9">
<model name="{model_name}">
<static>true</static>
@ -75,9 +81,9 @@ class Ground(model_wrapper.ModelWrapper):
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.8 0.8 0.8 1</specular>
<ambient>{' '.join(map(str, ambient))}</ambient>
<diffuse>{' '.join(map(str, diffuse))}</diffuse>
<specular>{' '.join(map(str, specular))}</specular>
</material>
</visual>
</link>

View file

@ -573,6 +573,9 @@ class Scene:
position=self.terrain.spawn_position,
orientation=quat_to_wxyz(self.terrain.spawn_quat_xyzw),
size=self.terrain.size,
ambient=self.terrain.ambient,
diffuse=self.terrain.diffuse,
specular=self.terrain.specular,
)
# Enable contact detection

View file

@ -65,7 +65,7 @@ def launch_setup(context, *args, **kwargs):
launch_simulation = LaunchConfiguration("launch_sim")
initial_joint_controllers_file_path = os.path.join(
get_package_share_directory('rbs_arm'), 'config', 'rbs_arm0_controllers.yaml'
get_package_share_directory('rbs_arm'), 'config', 'controllers.yaml'
)
single_robot_setup = IncludeLaunchDescription(
@ -176,7 +176,7 @@ def generate_launch_description():
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm_controllers_gazebosim.yaml",
default_value="controllers_gazebosim.yaml",
description="YAML file with the controllers configuration.",
)
)

View file

@ -70,7 +70,7 @@ def launch_setup(context, *args, **kwargs):
launch_simulation = LaunchConfiguration("launch_sim")
initial_joint_controllers_file_path = os.path.join(
get_package_share_directory('rbs_arm'), 'config', 'rbs_arm0_controllers.yaml'
get_package_share_directory('rbs_arm'), 'config', 'controllers.yaml'
)
single_robot_setup = IncludeLaunchDescription(
@ -195,7 +195,7 @@ def generate_launch_description():
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm_controllers_gazebosim.yaml",
default_value="controllers_gazebosim.yaml",
description="YAML file with the controllers configuration.",
)
)

View file

@ -52,7 +52,7 @@ def launch_setup(context, *args, **kwargs):
launch_simulation = LaunchConfiguration("launch_sim")
initial_joint_controllers_file_path = os.path.join(
get_package_share_directory("rbs_arm"), "config", "rbs_arm0_controllers.yaml"
get_package_share_directory("rbs_arm"), "config", "controllers.yaml"
)
xacro_file = os.path.join(
@ -158,7 +158,7 @@ def generate_launch_description():
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm_controllers_gazebosim.yaml",
default_value="controllers_gazebosim.yaml",
description="YAML file with the controllers configuration.",
)
)

View file

@ -69,7 +69,7 @@ def launch_setup(context, *args, **kwargs):
launch_simulation = LaunchConfiguration("launch_sim")
initial_joint_controllers_file_path = os.path.join(
get_package_share_directory('rbs_arm'), 'config', 'rbs_arm0_controllers.yaml'
get_package_share_directory('rbs_arm'), 'config', 'controllers.yaml'
)
single_robot_setup = IncludeLaunchDescription(
@ -196,7 +196,7 @@ def generate_launch_description():
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm_controllers_gazebosim.yaml",
default_value="controllers_gazebosim.yaml",
description="YAML file with the controllers configuration.",
)
)

View file

@ -7,7 +7,7 @@ import torch
from rclpy.node import Node
from sensor_msgs.msg import PointCloud2
from rbs_gym.envs.utils import Tf2Listener, conversions
from env_manager.utils import Tf2Listener, conversions
class OctreeCreator:

View file

@ -1,100 +1,129 @@
camera:
- clip_color: !tuple
- 0.01
- 1000.0
clip_depth: !tuple
- 0.05
- 10.0
enable: true
height: 128
horizontal_fov: 1.0471975511965976
image_format: R8G8B8
name: robot_camera
noise_mean: null
noise_stddev: null
publish_color: true
publish_depth: true
publish_points: true
random_pose_focal_point_z_offset: 0.0
random_pose_mode: orbit
random_pose_orbit_distance: 1.0
random_pose_orbit_height_range: !tuple
- 0.1
- 0.7
random_pose_orbit_ignore_arc_behind_robot: 0.39269908169872414
random_pose_rollout_counter: 0.0
random_pose_rollouts_num: 1
random_pose_select_position_options: []
relative_to: base_link
spawn_position: !tuple
- 0.0
- 0.0
- 1.0
spawn_quat_xyzw: !tuple
- 0.0
- 0.70710678118
- 0.0
- 0.70710678118
type: rgbd_camera
update_rate: 10
vertical_fov: 1.0471975511965976
width: 128
- clip_color: !tuple
- 0.01
- 1000.0
clip_depth: !tuple
- 0.05
- 10.0
enable: true
height: 128
horizontal_fov: 1.0471975511965976
image_format: R8G8B8
name: robot_camera
noise_mean: null
noise_stddev: null
publish_color: true
publish_depth: true
publish_points: true
random_pose_focal_point_z_offset: 0.0
random_pose_mode: orbit
random_pose_orbit_distance: 1.0
random_pose_orbit_height_range: !tuple
- 0.1
- 0.7
random_pose_orbit_ignore_arc_behind_robot: 0.39269908169872414
random_pose_rollout_counter: 0.0
random_pose_rollouts_num: 1
random_pose_select_position_options: []
relative_to: base_link
spawn_position: !tuple
- 0.0
- 0.0
- 1.0
spawn_quat_xyzw: !tuple
- 0.0
- 0.70710678118
- 0.0
- 0.70710678118
type: rgbd_camera
update_rate: 10
vertical_fov: 1.0471975511965976
width: 128
gravity: !tuple
- 0.0
- 0.0
- -9.80665
- 0.0
- 0.0
- -9.80665
gravity_std: !tuple
- 0.0
- 0.0
- 0.0232
- 0.0
- 0.0
- 0.0232
light:
color: !tuple
- 1.0
- 1.0
- 1.0
- 1.0
- 1.0
- 1.0
- 1.0
- 1.0
direction: !tuple
- 0.5
- -0.25
- -0.75
- 0.5
- -0.25
- -0.75
distance: 1000.0
model_rollouts_num: 1
radius: 25.0
random_minmax_elevation: !tuple
- -0.15
- -0.65
- -0.15
- -0.65
type: sun
visual: true
objects:
- color: null
name: bishop
orientation: !tuple
- 1.0
- 0.0
- 0.0
- 0.0
position: !tuple
- 0.0
- 1.0
- 0.3
randomize:
count: 0
models_rollouts_num: 0
random_color: false
random_model: false
random_orientation: false
random_pose: false
random_position: false
random_spawn_position_segments: []
random_spawn_position_update_workspace_centre: false
random_spawn_volume: !tuple
- 0.5
- 0.5
- 0.5
relative_to: world
static: false
texture: []
type: 'model'
- color: null
name: hole
orientation: !tuple
- 1.0
- 0.0
- 0.0
- 0.0
position: !tuple
- 0.1
- 0.3
- 0.1
randomize:
count: 0
models_rollouts_num: 0
random_color: false
random_model: false
random_orientation: false
random_pose: false
random_position: false
random_spawn_position_segments: []
random_spawn_position_update_workspace_centre: false
random_spawn_volume: !tuple
- 0.5
- 0.5
- 0.5
relative_to: world
static: false
texture: []
type: "model"
- color: null
name: peg
orientation: !tuple
- 1.0
- 0.0
- 0.0
- 0.0
position: !tuple
- 0.0
- 0.3
- 0.1
randomize:
count: 0
models_rollouts_num: 0
random_color: false
random_model: false
random_orientation: false
random_pose: false
random_position: false
random_spawn_position_segments: []
random_spawn_position_update_workspace_centre: false
random_spawn_volume: !tuple
- 0.5
- 0.5
- 0.5
relative_to: world
static: false
texture: []
type: "model"
physics_rollouts_num: 0
plugins:
fts_broadcaster: false
@ -104,13 +133,13 @@ plugins:
robot:
gripper_joint_positions: 0.0
joint_positions:
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- -1.57
- 0.5
- 3.14159
- 1.5
- 0.0
- 1.4
- 0.0
name: rbs_arm
randomizer:
joint_positions: false
@ -120,33 +149,33 @@ robot:
joint_positions_std: 0.1
pose: false
spawn_volume: !tuple
- 1.0
- 1.0
- 0.0
- 1.0
- 1.0
- 0.0
spawn_position: !tuple
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
- 0.0
spawn_quat_xyzw: !tuple
- 0.0
- 0.0
- 0.0
- 1.0
urdf_string: ''
- 0.0
- 0.0
- 0.0
- 1.0
urdf_string: ""
with_gripper: true
terrain:
model_rollouts_num: 1
name: ground
size: !tuple
- 1.5
- 1.5
- 1.5
- 1.5
spawn_position: !tuple
- 0
- 0
- 0
- 0
- 0
- 0
spawn_quat_xyzw: !tuple
- 0
- 0
- 0
- 1
- 0
- 0
- 0
- 1
type: flat

View file

@ -1,5 +1,6 @@
import os
from launch.launch_introspector import indent
import xacro
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
@ -14,55 +15,115 @@ from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
from robot_builder.parser.urdf import URDF_parser
from robot_builder.external.ros2_control import ControllerManager
import yaml
def launch_setup(context, *args, **kwargs):
# Initialize Arguments
robot_type = LaunchConfiguration("robot_type")
# General arguments
with_gripper_condition = LaunchConfiguration("with_gripper")
cartesian_controllers = LaunchConfiguration("cartesian_controllers")
description_package = LaunchConfiguration("description_package")
description_file = LaunchConfiguration("description_file")
robot_name = LaunchConfiguration("robot_name")
start_joint_controller = LaunchConfiguration("start_joint_controller")
initial_joint_controller = LaunchConfiguration("initial_joint_controller")
launch_simulation = LaunchConfiguration("launch_sim")
launch_moveit = LaunchConfiguration("launch_moveit")
launch_task_planner = LaunchConfiguration("launch_task_planner")
launch_perception = LaunchConfiguration("launch_perception")
use_moveit = LaunchConfiguration("use_moveit")
moveit_config_package = LaunchConfiguration("moveit_config_package")
moveit_config_file = LaunchConfiguration("moveit_config_file")
use_sim_time = LaunchConfiguration("use_sim_time")
sim_gazebo = LaunchConfiguration("sim_gazebo")
hardware = LaunchConfiguration("hardware")
env_manager = LaunchConfiguration("env_manager")
gazebo_gui = LaunchConfiguration("gazebo_gui")
gripper_name = LaunchConfiguration("gripper_name")
scene_config_file = LaunchConfiguration("scene_config_file").perform(context)
initial_joint_controllers_file_path = os.path.join(
get_package_share_directory("rbs_arm"), "config", "rbs_arm0_controllers.yaml"
ee_link_name = LaunchConfiguration("ee_link_name").perform(context)
base_link_name = LaunchConfiguration("base_link_name").perform(context)
control_space = LaunchConfiguration("control_space").perform(context)
control_strategy = LaunchConfiguration("control_strategy").perform(context)
interactive = LaunchConfiguration("interactive").perform(context)
if not scene_config_file == "":
config_file = {"config_file": scene_config_file}
else:
config_file = {}
description_package_abs_path = get_package_share_directory(
description_package.perform(context)
)
simulation_controllers = os.path.join(
description_package_abs_path, "config", "controllers.yaml"
)
xacro_file = os.path.join(
get_package_share_directory(description_package.perform(context)),
description_package_abs_path,
"urdf",
description_file.perform(context),
)
robot_description_doc = xacro.process_file(
xacro_file,
mappings={
"gripper_name": gripper_name.perform(context),
"hardware": hardware.perform(context),
"simulation_controllers": initial_joint_controllers_file_path,
"namespace": "",
},
)
xacro_config_file = f"{description_package_abs_path}/config/xacro_args.yaml"
# TODO: hide this to another place
# Load xacro_args
def param_constructor(loader, node, local_vars):
value = loader.construct_scalar(node)
return LaunchConfiguration(value).perform(
local_vars.get("context", "Launch context if not defined")
)
def variable_constructor(loader, node, local_vars):
value = loader.construct_scalar(node)
return local_vars.get(value, f"Variable '{value}' not found")
def load_xacro_args(yaml_file, local_vars):
# Get valut from ros2 argument
yaml.add_constructor(
"!param", lambda loader, node: param_constructor(loader, node, local_vars)
)
# Get value from local variable in this code
# The local variable should be initialized before the loader was called
yaml.add_constructor(
"!variable",
lambda loader, node: variable_constructor(loader, node, local_vars),
)
with open(yaml_file, "r") as file:
return yaml.load(file, Loader=yaml.FullLoader)
mappings_data = load_xacro_args(xacro_config_file, locals())
robot_description_doc = xacro.process_file(xacro_file, mappings=mappings_data)
robot_description_semantic_content = ""
if use_moveit.perform(context) == "true":
srdf_config_file = f"{description_package_abs_path}/config/srdf_xacro_args.yaml"
srdf_file = os.path.join(
get_package_share_directory(moveit_config_package.perform(context)),
"srdf",
moveit_config_file.perform(context),
)
srdf_mappings = load_xacro_args(srdf_config_file, locals())
robot_description_semantic_content = xacro.process_file(srdf_file, mappings=srdf_mappings)
robot_description_semantic_content = robot_description_semantic_content.toprettyxml(indent=" ")
control_space = "joint"
control_strategy = "position"
interactive = "false"
robot_description_content = robot_description_doc.toprettyxml(indent=" ")
robot_description = {"robot_description": robot_description_content}
single_robot_setup = IncludeLaunchDescription(
# Parse robot and configure controller's file for ControllerManager
robot = URDF_parser.load_string(
robot_description_content, ee_link_name=ee_link_name
)
ControllerManager.save_to_yaml(
robot, description_package_abs_path, "controllers.yaml"
)
rbs_robot_setup = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
@ -71,37 +132,31 @@ def launch_setup(context, *args, **kwargs):
]
),
launch_arguments={
"env_manager": env_manager,
"with_gripper": with_gripper_condition,
"gripper_name": gripper_name,
"controllers_file": initial_joint_controllers_file_path,
"controllers_file": simulation_controllers,
"robot_type": robot_type,
# "controllers_file": controller_paramfile,
"cartesian_controllers": cartesian_controllers,
"description_package": description_package,
"description_file": description_file,
"robot_name": robot_type,
"start_joint_controller": start_joint_controller,
"initial_joint_controller": initial_joint_controller,
"launch_simulation": launch_simulation,
"launch_moveit": launch_moveit,
"launch_task_planner": launch_task_planner,
"launch_perception": launch_perception,
"use_moveit": use_moveit,
"moveit_config_package": moveit_config_package,
"moveit_config_file": moveit_config_file,
"use_sim_time": use_sim_time,
"sim_gazebo": sim_gazebo,
"hardware": hardware,
"launch_controllers": "true",
"gazebo_gui": gazebo_gui,
"use_controllers": "true",
"robot_description": robot_description_content,
"robot_description_semantic": robot_description_semantic_content,
"base_link_name": base_link_name,
"ee_link_name": ee_link_name,
"control_space": control_space,
"control_strategy": control_strategy,
"interactive_control": interactive,
}.items(),
)
rbs_runtime = Node(
package="rbs_runtime",
executable="runtime",
parameters=[robot_description, {"use_sim_time": True}],
parameters=[robot_description, config_file, {"use_sim_time": True}],
)
clock_bridge = Node(
@ -111,9 +166,13 @@ def launch_setup(context, *args, **kwargs):
output="screen",
)
delay_robot_control_stack = TimerAction(period=10.0, actions=[single_robot_setup])
delay_robot_control_stack = TimerAction(period=10.0, actions=[rbs_robot_setup])
nodes_to_start = [rbs_runtime, clock_bridge, delay_robot_control_stack]
nodes_to_start = [
rbs_runtime,
clock_bridge,
delay_robot_control_stack
]
return nodes_to_start
@ -123,18 +182,20 @@ def generate_launch_description():
DeclareLaunchArgument(
"robot_type",
description="Type of robot by name",
choices=["rbs_arm", "ur3", "ur3e", "ur5", "ur5e", "ur10", "ur10e", "ur16e"],
choices=[
"rbs_arm",
"ar4",
"ur3",
"ur3e",
"ur5",
"ur5e",
"ur10",
"ur10e",
"ur16e",
],
default_value="rbs_arm",
)
)
# General arguments
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm0_controllers.yaml",
description="YAML file with the controllers configuration.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_package",
@ -157,20 +218,6 @@ def generate_launch_description():
description="Name for robot, used to apply namespace for specific robot in multirobot setup",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"start_joint_controller",
default_value="false",
description="Enable headless mode for robot control",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"initial_joint_controller",
default_value="joint_trajectory_controller",
description="Robot controller to start.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_package",
@ -194,14 +241,6 @@ def generate_launch_description():
This is needed for the trajectory planing in simulation.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gripper_name",
default_value="rbs_gripper",
choices=["rbs_gripper", ""],
description="choose gripper by name (leave empty if hasn't)",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"with_gripper", default_value="true", description="With gripper or not?"
@ -209,25 +248,7 @@ def generate_launch_description():
)
declared_arguments.append(
DeclareLaunchArgument(
"sim_gazebo", default_value="true", description="Gazebo Simulation"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"env_manager", default_value="true", description="Launch env_manager?"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_sim",
default_value="true",
description="Launch simulator (Gazebo)?\
Most general arg",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_moveit", default_value="false", description="Launch moveit?"
"use_moveit", default_value="false", description="Launch moveit?"
)
)
declared_arguments.append(
@ -237,39 +258,55 @@ def generate_launch_description():
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_task_planner",
default_value="false",
description="Launch task_planner?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"cartesian_controllers",
default_value="true",
description="Load cartesian\
controllers?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"hardware",
choices=["gazebo", "mock"],
default_value="gazebo",
description="Choose your harware_interface",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_controllers",
"use_controllers",
default_value="true",
description="Launch controllers?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gazebo_gui", default_value="true", description="Launch gazebo with gui?"
"scene_config_file",
default_value="",
description="Path to a scene configuration file",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"ee_link_name",
default_value="",
description="End effector name of robot arm",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"base_link_name",
default_value="",
description="Base link name if robot arm",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"control_space",
default_value="task",
choices=["task", "joint"],
description="Specify the control space for the robot (e.g., task space).",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"control_strategy",
default_value="position",
choices=["position", "velocity", "effort"],
description="Specify the control strategy (e.g., position control).",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"interactive",
default_value="true",
description="Wheter to run the motion_control_handle controller",
),
)
return LaunchDescription(
declared_arguments + [OpaqueFunction(function=launch_setup)]

View file

@ -4,6 +4,24 @@ import yaml
from dacite import from_dict
from env_manager.models.configs import SceneData
from typing import Dict, Any
from env_manager.models.configs import (
BoxObjectData, CylinderObjectData, MeshData, ModelData, ObjectData
)
def object_factory(obj_data: Dict[str, Any]) -> ObjectData:
obj_type = obj_data.get('type', '')
if obj_type == 'box':
return BoxObjectData(**obj_data)
elif obj_type == 'cylinder':
return CylinderObjectData(**obj_data)
elif obj_type == 'mesh':
return MeshData(**obj_data)
elif obj_type == 'model':
return ModelData(**obj_data)
else:
return ObjectData(**obj_data)
def scene_config_loader(file: str | Path) -> SceneData:
def tuple_constructor(loader, node):
@ -15,4 +33,8 @@ def scene_config_loader(file: str | Path) -> SceneData:
scene_data = from_dict(data_class=SceneData, data=scene_cfg)
scene_data.objects = [object_factory(obj) for obj in scene_cfg.get('objects', [])]
print(scene_data)
return scene_data

View file

@ -0,0 +1,87 @@
from launch_ros.actions import Node
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction
# from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
def create_spawner(controller_name, namespace, condition=None, inactive=False):
args = [controller_name, "-c", f"{namespace}/controller_manager"]
if inactive:
args.append("--inactive")
return Node(
package="controller_manager",
executable="spawner",
namespace=namespace,
arguments=args,
condition=condition,
)
def launch_setup(context, *args, **kwargs):
namespace = LaunchConfiguration("namespace").perform(context)
control_strategy = LaunchConfiguration("control_strategy").perform(context)
control_space = LaunchConfiguration("control_space").perform(context)
has_gripper = LaunchConfiguration("has_gripper").perform(context)
interactive_control = LaunchConfiguration("interactive_control").perform(context)
controllers_config = {
"joint_state_broadcaster": True,
"gripper_controller": has_gripper == "true",
"joint_trajectory_controller": control_strategy == "position"
and control_space == "joint",
"cartesian_motion_controller": control_strategy == "position"
and control_space == "task",
"cartesian_force_controller": control_strategy == "effort"
and control_space == "task",
"joint_effort_controller": control_strategy == "effort"
and control_space == "joint",
"force_torque_sensor_broadcaster": control_strategy == "effort"
and control_space == "task",
"motion_control_handle": interactive_control == "true"
and control_space == "task"
and control_strategy == "position",
}
nodes_to_start = []
for controller_name, should_start in controllers_config.items():
if should_start:
nodes_to_start.append(create_spawner(controller_name, namespace))
return nodes_to_start
def generate_launch_description():
declared_arguments = [
DeclareLaunchArgument(
"namespace", default_value="", description="A robot's namespace"
),
DeclareLaunchArgument(
"control_space",
default_value="task",
choices=["task", "joint"],
description="Control type: 'task' for Cartesian, 'joint' for joint space control.",
),
DeclareLaunchArgument(
"control_strategy",
default_value="position",
choices=["position", "velocity", "effort"],
description="Control strategy: 'position', 'velocity', or 'effort'.",
),
DeclareLaunchArgument(
"has_gripper",
default_value="true",
description="Whether to activate the gripper_controller.",
),
DeclareLaunchArgument(
"interactive_control",
default_value="true",
description="Wheter to run the motion_control_handle controller",
),
]
return LaunchDescription(
declared_arguments + [OpaqueFunction(function=launch_setup)]
)

View file

@ -1,254 +0,0 @@
from launch import LaunchDescription
from launch.actions import (
DeclareLaunchArgument,
IncludeLaunchDescription,
OpaqueFunction
)
from launch.conditions import IfCondition
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
from launch_ros.actions import Node
import os
from ament_index_python.packages import get_package_share_directory
from nav2_common.launch import RewrittenYaml
def launch_setup(context, *args, **kwargs):
# Initialize Arguments
robot_type = LaunchConfiguration("robot_type")
# General arguments
with_gripper_condition = LaunchConfiguration("with_gripper")
controllers_file = LaunchConfiguration("controllers_file")
cartesian_controllers = LaunchConfiguration("cartesian_controllers")
description_package = LaunchConfiguration("description_package")
description_file = LaunchConfiguration("description_file")
robot_name = LaunchConfiguration("robot_name")
start_joint_controller = LaunchConfiguration("start_joint_controller")
initial_joint_controller = LaunchConfiguration("initial_joint_controller")
launch_simulation = LaunchConfiguration("launch_sim")
launch_moveit = LaunchConfiguration("launch_moveit")
launch_task_planner = LaunchConfiguration("launch_task_planner")
launch_perception = LaunchConfiguration("launch_perception")
moveit_config_package = LaunchConfiguration("moveit_config_package")
moveit_config_file = LaunchConfiguration("moveit_config_file")
use_sim_time = LaunchConfiguration("use_sim_time")
sim_gazebo = LaunchConfiguration("sim_gazebo")
hardware = LaunchConfiguration("hardware")
env_manager = LaunchConfiguration("env_manager")
launch_controllers = LaunchConfiguration("launch_controllers")
gazebo_gui = LaunchConfiguration("gazebo_gui")
gripper_name = LaunchConfiguration("gripper_name")
sim_gazebo = LaunchConfiguration("sim_gazebo")
launch_simulation = LaunchConfiguration("launch_sim")
configured_params = RewrittenYaml(
source_file=os.path.join(
get_package_share_directory(
description_package.perform(context)),
"config",
controllers_file.perform(context)),
root_key=robot_name.perform(context),
param_rewrites={},
convert_types=True,
)
initial_joint_controllers_file_path = os.path.join(
get_package_share_directory('rbs_arm'), 'config', 'rbs_arm0_controllers.yaml'
)
controller_paramfile = configured_params.perform(context)
namespace = "/" + robot_name.perform(context)
# spawner = Node(
# package="gz_enviroment_python",
# executable="spawner.py",
# namespace=namespace
# )
single_robot_setup = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
PathJoinSubstitution([
FindPackageShare('rbs_bringup'),
"launch",
"rbs_robot.launch.py"
])
]),
launch_arguments={
"env_manager": env_manager,
"with_gripper": with_gripper_condition,
"gripper_name": gripper_name,
"controllers_file": controllers_file,
"robot_type": robot_type,
"controllers_file": initial_joint_controllers_file_path,
"cartesian_controllers": cartesian_controllers,
"description_package": description_package,
"description_file": description_file,
"robot_name": robot_name,
"start_joint_controller": start_joint_controller,
"initial_joint_controller": initial_joint_controller,
"launch_simulation": launch_simulation,
"launch_moveit": launch_moveit,
"launch_task_planner": launch_task_planner,
"launch_perception": launch_perception,
"moveit_config_package": moveit_config_package,
"moveit_config_file": moveit_config_file,
"use_sim_time": use_sim_time,
"sim_gazebo": sim_gazebo,
"hardware": hardware,
"launch_controllers": "true",
"gazebo_gui": gazebo_gui,
}.items()
)
nodes_to_start = [
# spawner,
single_robot_setup
]
return nodes_to_start
def generate_launch_description():
declared_arguments = []
declared_arguments.append(
DeclareLaunchArgument(
"robot_type",
description="Type of robot by name",
choices=["rbs_arm","ur3", "ur3e", "ur5", "ur5e", "ur10", "ur10e", "ur16e"],
default_value="rbs_arm",
)
)
# General arguments
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm_controllers_gazebosim.yaml",
description="YAML file with the controllers configuration.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_package",
default_value="rbs_arm",
description="Description package with robot URDF/XACRO files. Usually the argument \
is not set, it enables use of a custom description.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_file",
default_value="rbs_arm_modular.xacro",
description="URDF/XACRO description file with the robot.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"robot_name",
default_value="arm0",
description="Name for robot, used to apply namespace for specific robot in multirobot setup",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"start_joint_controller",
default_value="false",
description="Enable headless mode for robot control",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"initial_joint_controller",
default_value="joint_trajectory_controller",
description="Robot controller to start.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_package",
default_value="rbs_arm",
description="MoveIt config package with robot SRDF/XACRO files. Usually the argument \
is not set, it enables use of a custom moveit config.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_file",
default_value="rbs_arm.srdf.xacro",
description="MoveIt SRDF/XACRO description file with the robot.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"use_sim_time",
default_value="true",
description="Make MoveIt to use simulation time.\
This is needed for the trajectory planing in simulation.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gripper_name",
default_value="rbs_gripper",
choices=["rbs_gripper", ""],
description="choose gripper by name (leave empty if hasn't)",
)
)
declared_arguments.append(
DeclareLaunchArgument("with_gripper",
default_value="true",
description="With gripper or not?")
)
declared_arguments.append(
DeclareLaunchArgument("sim_gazebo",
default_value="true",
description="Gazebo Simulation")
)
declared_arguments.append(
DeclareLaunchArgument("env_manager",
default_value="false",
description="Launch env_manager?")
)
declared_arguments.append(
DeclareLaunchArgument("launch_sim",
default_value="true",
description="Launch simulator (Gazebo)?\
Most general arg")
)
declared_arguments.append(
DeclareLaunchArgument("launch_moveit",
default_value="false",
description="Launch moveit?")
)
declared_arguments.append(
DeclareLaunchArgument("launch_perception",
default_value="false",
description="Launch perception?")
)
declared_arguments.append(
DeclareLaunchArgument("launch_task_planner",
default_value="false",
description="Launch task_planner?")
)
declared_arguments.append(
DeclareLaunchArgument("cartesian_controllers",
default_value="true",
description="Load cartesian\
controllers?")
)
declared_arguments.append(
DeclareLaunchArgument("hardware",
choices=["gazebo", "mock"],
default_value="gazebo",
description="Choose your harware_interface")
)
declared_arguments.append(
DeclareLaunchArgument("launch_controllers",
default_value="true",
description="Launch controllers?")
)
declared_arguments.append(
DeclareLaunchArgument("gazebo_gui",
default_value="true",
description="Launch gazebo with gui?")
)
return LaunchDescription(declared_arguments + [OpaqueFunction(function=launch_setup)])

View file

@ -1,292 +0,0 @@
from launch import LaunchDescription
from launch.actions import (
DeclareLaunchArgument,
IncludeLaunchDescription,
OpaqueFunction,
)
from launch.conditions import IfCondition
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
from launch_ros.actions import Node
from nav2_common.launch import RewrittenYaml
import os
from ament_index_python import get_package_share_directory
from rbs_launch_utils.merged_yaml import MergedYaml
from rbs_launch_utils.launch_common import load_yaml
import yaml
def launch_setup(context, *args, **kwargs):
# Initialize Arguments
robot_type = LaunchConfiguration("robot_type")
# General arguments
with_gripper_condition = LaunchConfiguration("with_gripper")
controllers_file = LaunchConfiguration("controllers_file")
cartesian_controllers = LaunchConfiguration("cartesian_controllers")
description_package = LaunchConfiguration("description_package")
description_file = LaunchConfiguration("description_file")
robot_name = LaunchConfiguration("robot_name")
start_joint_controller = LaunchConfiguration("start_joint_controller")
initial_joint_controller = LaunchConfiguration("initial_joint_controller")
launch_simulation = LaunchConfiguration("launch_sim")
launch_moveit = LaunchConfiguration("launch_moveit")
launch_task_planner = LaunchConfiguration("launch_task_planner")
launch_perception = LaunchConfiguration("launch_perception")
moveit_config_package = LaunchConfiguration("moveit_config_package")
moveit_config_file = LaunchConfiguration("moveit_config_file")
use_sim_time = LaunchConfiguration("use_sim_time")
sim_gazebo = LaunchConfiguration("sim_gazebo")
hardware = LaunchConfiguration("hardware")
env_manager = LaunchConfiguration("env_manager")
launch_controllers = LaunchConfiguration("launch_controllers")
gazebo_gui = LaunchConfiguration("gazebo_gui")
gripper_name = LaunchConfiguration("gripper_name")
robots_config_file = LaunchConfiguration("robots_config_file")
gazebo_world_filename = LaunchConfiguration("gazebo_world_filename")
ld = []
ld.append(IncludeLaunchDescription(
PythonLaunchDescriptionSource([
PathJoinSubstitution([
FindPackageShare('rbs_simulation'),
'launch',
'simulation_gazebo.launch.py'
])
]),
launch_arguments={
'sim_gazebo': sim_gazebo,
'debugger': "false",
'launch_env_manager': "false",
"gazebo_world_filename": gazebo_world_filename
}.items(),
condition=IfCondition(launch_simulation)
))
scene_file = robots_config_file.perform(context)
robots = load_yaml("rbs_bringup", "config/" + scene_file)
description_package = description_package.perform(context)
controllers_file = controllers_file.perform(context)
config = MergedYaml(context,
os.path.join(get_package_share_directory(description_package), "config", controllers_file),
root_keys=[i["name"] for i in robots["scene_config"]],
param_rewrites={},
convert_types=False,
).merge_yamls()
for robot in robots["scene_config"]:
namespace: str = "/" + robot["name"]
ld.append(IncludeLaunchDescription(
PythonLaunchDescriptionSource([
PathJoinSubstitution([
FindPackageShare('rbs_bringup'),
"launch",
"rbs_robot.launch.py"
])
]),
launch_arguments={
"env_manager": env_manager,
"with_gripper": with_gripper_condition,
"gripper_name": gripper_name,
"controllers_file": controllers_file,
"robot_type": robot["type"],
"controllers_file": config,
"cartesian_controllers": cartesian_controllers,
"description_package": description_package,
"description_file": description_file,
"robot_name": robot["name"],
"start_joint_controller": start_joint_controller,
"initial_joint_controller": initial_joint_controller,
"launch_simulation": launch_simulation,
"launch_moveit": launch_moveit,
"launch_task_planner": launch_task_planner,
"launch_perception": launch_perception,
"moveit_config_package": moveit_config_package,
"moveit_config_file": moveit_config_file,
"use_sim_time": use_sim_time,
"sim_gazebo": sim_gazebo,
"hardware": hardware,
"launch_controllers": launch_controllers,
"gazebo_gui": gazebo_gui,
"namespace": namespace,
"x": str(robot["pose"]["position"]["x"]),
"y": str(robot["pose"]["position"]["y"]),
"z": str(robot["pose"]["position"]["z"]),
"roll": str(robot["pose"]["orientation"]["x"]),
"pitch": str(robot["pose"]["orientation"]["y"]),
"yaw": str(robot["pose"]["orientation"]["z"]),
}.items()
))
gz_spawner = Node(
package='ros_gz_sim',
executable='create',
arguments=[
'-name', robot_name,
# '-x', str(robot["pose"]["position"]["x"]),
# '-y', str(robot["pose"]["position"]["y"]),
# '-z', str(robot["pose"]["position"]["z"]),
# '-R', str(robot["pose"]["orientation"]["x"]),
# '-P', str(robot["pose"]["orientation"]["y"]),
# '-Y', str(robot["pose"]["orientation"]["z"]),
'-topic', namespace + '/robot_description'],
output='screen',
condition=IfCondition(sim_gazebo))
ld.append(gz_spawner)
return ld
def generate_launch_description():
declared_arguments = []
declared_arguments.append(
DeclareLaunchArgument(
"robot_type",
description="Type of robot by name",
choices=["rbs_arm","ur3", "ur3e", "ur5", "ur5e", "ur10", "ur10e", "ur16e"],
default_value="rbs_arm",
)
)
# General arguments
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm_controllers_gazebosim.yaml",
description="YAML file with the controllers configuration.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_package",
default_value="rbs_arm",
description="Description package with robot URDF/XACRO files. Usually the argument \
is not set, it enables use of a custom description.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_file",
default_value="rbs_arm_modular.xacro",
description="URDF/XACRO description file with the robot.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"robot_name",
default_value="arm0",
description="Name for robot, used to apply namespace for specific robot in multirobot setup",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"start_joint_controller",
default_value="false",
description="Enable headless mode for robot control",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"initial_joint_controller",
default_value="joint_trajectory_controller",
description="Robot controller to start.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_package",
default_value="rbs_arm",
description="MoveIt config package with robot SRDF/XACRO files. Usually the argument \
is not set, it enables use of a custom moveit config.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_file",
default_value="rbs_arm.srdf.xacro",
description="MoveIt SRDF/XACRO description file with the robot.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"use_sim_time",
default_value="true",
description="Make MoveIt to use simulation time.\
This is needed for the trajectory planing in simulation.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gripper_name",
default_value="rbs_gripper",
choices=["rbs_gripper", ""],
description="choose gripper by name (leave empty if hasn't)",
)
)
declared_arguments.append(
DeclareLaunchArgument("with_gripper",
default_value="true",
description="With gripper or not?")
)
declared_arguments.append(
DeclareLaunchArgument("sim_gazebo",
default_value="true",
description="Gazebo Simulation")
)
declared_arguments.append(
DeclareLaunchArgument("env_manager",
default_value="false",
description="Launch env_manager?")
)
declared_arguments.append(
DeclareLaunchArgument("launch_sim",
default_value="true",
description="Launch simulator (Gazebo)?\
Most general arg")
)
declared_arguments.append(
DeclareLaunchArgument("launch_moveit",
default_value="false",
description="Launch moveit?")
)
declared_arguments.append(
DeclareLaunchArgument("launch_perception",
default_value="false",
description="Launch perception?")
)
declared_arguments.append(
DeclareLaunchArgument("launch_task_planner",
default_value="false",
description="Launch task_planner?")
)
declared_arguments.append(
DeclareLaunchArgument("cartesian_controllers",
default_value="true",
description="Load cartesian\
controllers?")
)
declared_arguments.append(
DeclareLaunchArgument("hardware",
choices=["gazebo", "mock"],
default_value="gazebo",
description="Choose your harware_interface")
)
declared_arguments.append(
DeclareLaunchArgument("launch_controllers",
default_value="true",
description="Launch controllers?")
)
declared_arguments.append(
DeclareLaunchArgument("gazebo_gui",
default_value="true",
description="Launch gazebo with gui?")
)
declared_arguments.append(
DeclareLaunchArgument("gazebo_world_filename",
default_value="asm2.sdf",
description="Filename of Gazebo world file to launch")
)
declared_arguments.append(
DeclareLaunchArgument("robots_config_file",
default_value="roboclone.yaml",
description="Filename for config file with robots in scene")
)
return LaunchDescription(declared_arguments + [OpaqueFunction(function=launch_setup)])

View file

@ -0,0 +1,53 @@
from launch import LaunchDescription
from launch.actions import (
IncludeLaunchDescription,
OpaqueFunction,
)
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import (
PathJoinSubstitution,
)
from launch_ros.substitutions import FindPackageShare
def launch_setup(context, *args, **kwargs):
main_script = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[FindPackageShare("rbs_runtime"), "launch", "runtime.launch.py"]
)
]
),
launch_arguments={
"with_gripper": "true",
"robot_type": "rbs_arm",
"description_package": "rbs_arm",
"description_file": "rbs_arm_modular.xacro",
"robot_name": "rbs_arm",
"use_moveit": "true",
"moveit_config_package": "rbs_arm",
"moveit_config_file": "rbs_arm.srdf.xacro",
"use_sim_time": "true",
"use_controllers": "true",
"scene_config_file": "",
"base_link_name": "base_link",
"ee_link_name": "gripper_grasp_point",
"control_space": "task",
"control_strategy": "position",
"interactive": "false"
}.items(),
)
nodes_to_start = [
main_script,
]
return nodes_to_start
def generate_launch_description():
declared_arguments = []
return LaunchDescription(
declared_arguments + [OpaqueFunction(function=launch_setup)]
)

View file

@ -21,33 +21,15 @@ from launch_ros.substitutions import FindPackageShare
def launch_setup(context, *args, **kwargs):
# Initialize Arguments
robot_type = LaunchConfiguration("robot_type")
# General arguments
launch_rviz = LaunchConfiguration("launch_rviz")
with_gripper_condition = LaunchConfiguration("with_gripper")
controllers_file = LaunchConfiguration("controllers_file")
cartesian_controllers = LaunchConfiguration("cartesian_controllers")
description_package = LaunchConfiguration("description_package")
description_file = LaunchConfiguration("description_file")
robot_name = LaunchConfiguration("robot_name")
start_joint_controller = LaunchConfiguration("start_joint_controller")
initial_joint_controller = LaunchConfiguration("initial_joint_controller")
launch_moveit = LaunchConfiguration("launch_moveit")
launch_task_planner = LaunchConfiguration("launch_task_planner")
launch_perception = LaunchConfiguration("launch_perception")
use_moveit = LaunchConfiguration("use_moveit")
moveit_config_package = LaunchConfiguration("moveit_config_package")
moveit_config_file = LaunchConfiguration("moveit_config_file")
use_sim_time = LaunchConfiguration("use_sim_time")
hardware = LaunchConfiguration("hardware")
launch_controllers = LaunchConfiguration("launch_controllers")
gripper_name = LaunchConfiguration("gripper_name")
x_pos = LaunchConfiguration("x")
y_pos = LaunchConfiguration("y")
z_pos = LaunchConfiguration("z")
roll = LaunchConfiguration("roll")
pitch = LaunchConfiguration("pitch")
yaw = LaunchConfiguration("yaw")
use_controllers = LaunchConfiguration("use_controllers")
namespace = LaunchConfiguration("namespace")
multi_robot = LaunchConfiguration("multi_robot")
robot_name = robot_name.perform(context)
@ -55,83 +37,34 @@ def launch_setup(context, *args, **kwargs):
robot_type = robot_type.perform(context)
description_package = description_package.perform(context)
description_file = description_file.perform(context)
controllers_file = controllers_file.perform(context)
multi_robot = multi_robot.perform(context)
robot_description = LaunchConfiguration("robot_description")
robot_description_content = LaunchConfiguration("robot_description")
robot_description_semantic_content = LaunchConfiguration(
"robot_description_semantic"
)
control_space = LaunchConfiguration("control_space")
control_strategy = LaunchConfiguration("control_strategy")
ee_link_name = LaunchConfiguration("ee_link_name").perform(context)
base_link_name = LaunchConfiguration("base_link_name").perform(context)
remappings = []
if multi_robot == "true":
remappings.append([("/tf", "tf"), ("/tf_static", "tf_static")])
controllers_file = os.path.join(
get_package_share_directory(description_package), "config", controllers_file
)
if not robot_description.perform(context):
xacro_file = os.path.join(
get_package_share_directory(description_package), "urdf", description_file
)
robot_description_doc = xacro.process_file(
xacro_file,
mappings={
"gripper_name": gripper_name.perform(context),
"hardware": hardware.perform(context),
"simulation_controllers": controllers_file,
"namespace": namespace,
"x": x_pos.perform(context),
"y": y_pos.perform(context),
"z": z_pos.perform(context),
"roll": roll.perform(context),
"pitch": pitch.perform(context),
"yaw": yaw.perform(context),
},
)
robot_description_content = robot_description_doc.toprettyxml(indent=" ")
else:
robot_description_content = robot_description.perform(context)
robot_description = {"robot_description": robot_description_content}
robot_description_semantic_content = Command(
[
PathJoinSubstitution([FindExecutable(name="xacro")]),
" ",
PathJoinSubstitution(
[
FindPackageShare(moveit_config_package),
"config/moveit",
"rbs_arm.srdf.xacro",
]
),
" ",
"name:=",
robot_type,
" ",
"with_gripper:=",
with_gripper_condition,
" ",
"gripper_name:=",
gripper_name,
" ",
]
)
robot_description_semantic = {
"robot_description_semantic": robot_description_semantic_content
robot_description = {
"robot_description": robot_description_content.perform(context)
}
robot_description_kinematics = PathJoinSubstitution(
[FindPackageShare(moveit_config_package), "config", "kinematics.yaml"]
robot_description_kinematics_filepath = os.path.join(
get_package_share_directory(moveit_config_package.perform(context)),
"config",
"kinematics.yaml",
)
# kinematics_yaml = load_yaml("rbs_arm", "config/kinematics.yaml")
# robot_description_kinematics = {
# "robot_description_kinematics": robot_description_kinematics
# }
robot_description_kinematics = {
"robot_description_kinematics": robot_description_kinematics
}
rviz_config_file = PathJoinSubstitution(
[FindPackageShare("rbs_bringup"), "config", "rbs.rviz"]
)
robot_state_publisher = Node(
package="robot_state_publisher",
executable="robot_state_publisher",
@ -141,32 +74,12 @@ def launch_setup(context, *args, **kwargs):
parameters=[{"use_sim_time": use_sim_time}, robot_description],
)
rviz_config_file = PathJoinSubstitution(
[FindPackageShare("rbs_bringup"), "config", "rbs.rviz"]
)
rviz = Node(
package="rviz2",
executable="rviz2",
name="rviz2",
output="log",
namespace=namespace,
arguments=["-d", rviz_config_file],
parameters=[
robot_description,
robot_description_semantic,
robot_description_kinematics,
{"use_sim_time": use_sim_time},
],
condition=IfCondition(launch_rviz),
)
control = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[
FindPackageShare(description_package),
FindPackageShare("rbs_bringup"),
"launch",
"control.launch.py",
]
@ -174,12 +87,12 @@ def launch_setup(context, *args, **kwargs):
]
),
launch_arguments={
"control_space": "task",
"control_strategy": "position",
"has_gripper": "true",
"control_space": control_space,
"control_strategy": control_strategy,
"has_gripper": with_gripper_condition,
"namespace": namespace,
}.items(),
condition=IfCondition(launch_controllers),
condition=IfCondition(use_controllers),
)
moveit = IncludeLaunchDescription(
@ -195,16 +108,17 @@ def launch_setup(context, *args, **kwargs):
]
),
launch_arguments={
"robot_description": robot_description_content,
"moveit_config_package": moveit_config_package,
"moveit_config_file": moveit_config_file,
# "moveit_config_file": moveit_config_file,
"use_sim_time": use_sim_time,
"tf_prefix": robot_name,
"with_gripper": with_gripper_condition,
"robot_description": robot_description_content,
"robot_description_semantic": robot_description_semantic_content,
"robot_description_kinematics": robot_description_kinematics_filepath,
"namespace": namespace,
}.items(),
condition=IfCondition(launch_moveit),
condition=IfCondition(use_moveit),
)
skills = IncludeLaunchDescription(
@ -222,287 +136,222 @@ def launch_setup(context, *args, **kwargs):
launch_arguments={
"robot_description": robot_description_content,
"robot_description_semantic": robot_description_semantic_content,
"robot_description_kinematics": robot_description_kinematics,
"robot_description_kinematics": robot_description_kinematics_filepath,
"use_sim_time": use_sim_time,
"with_gripper_condition": with_gripper_condition,
"namespace": namespace,
"use_moveit": use_moveit,
"ee_link_name": ee_link_name,
"base_link_name": base_link_name,
}.items(),
)
task_planner = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[
FindPackageShare("rbs_task_planner"),
"launch",
"task_planner.launch.py",
]
)
]
),
launch_arguments={
# TBD
}.items(),
condition=IfCondition(launch_task_planner),
)
perception = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[
FindPackageShare("rbs_perception"),
"launch",
"perception.launch.py",
]
)
]
),
launch_arguments={
# TBD
}.items(),
condition=IfCondition(launch_perception),
)
asm_config = Node(
package="rbs_utils",
namespace=namespace,
executable="assembly_config_service.py",
)
nodes_to_start = [
robot_state_publisher,
control,
moveit,
skills,
asm_config,
# task_planner,
# perception,
rviz,
]
return nodes_to_start
def generate_launch_description():
declared_arguments = []
declared_arguments.append(
DeclareLaunchArgument(
"robot_type",
description="Type of robot by name",
choices=["rbs_arm", "ur3", "ur3e", "ur5", "ur5e", "ur10", "ur10e", "ur16e"],
description="Type of robot to launch, specified by name.",
choices=[
"rbs_arm",
"ar4",
"ur3",
"ur3e",
"ur5",
"ur5e",
"ur10",
"ur10e",
"ur16e",
],
default_value="rbs_arm",
)
)
# General arguments
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm0_controllers.yaml",
description="YAML file with the controllers configuration.",
default_value="controllers.yaml",
description="YAML file containing configuration settings for the controllers.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_package",
default_value="rbs_arm",
description="Description package with robot URDF/XACRO files. Usually the argument \
is not set, it enables use of a custom description.",
description="Package containing the robot's URDF/XACRO description files. Can be set to use a custom description.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_file",
default_value="rbs_arm_modular.xacro",
description="URDF/XACRO description file with the robot.",
description="URDF/XACRO file describing the robot's model.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"robot_name",
default_value="arm0",
description="tf_prefix of the joint names, useful for \
multi-robot setup. If changed than also joint names in the controllers' configuration \
have to be updated.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"start_joint_controller",
default_value="true",
description="Enable headless mode for robot control",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"initial_joint_controller",
default_value="joint_trajectory_controller",
description="Robot controller to start.",
description="Prefix for joint names to support multi-robot setups. If changed, ensure joint names in controllers configuration are updated accordingly.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_package",
default_value="rbs_arm",
description="MoveIt config package with robot SRDF/XACRO files. Usually the argument \
is not set, it enables use of a custom moveit config.",
description="Package containing the MoveIt configuration files (SRDF/XACRO) for the robot. Can be customized.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_file",
default_value="rbs_arm.srdf.xacro",
description="MoveIt SRDF/XACRO description file with the robot.",
description="MoveIt SRDF/XACRO file for robot configuration.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"use_sim_time",
default_value="true",
description="Make MoveIt to use simulation time.\
This is needed for the trajectory planing in simulation.",
description="Enables simulation time in MoveIt, needed for trajectory planning in simulation.",
)
)
# declared_arguments.append(
# DeclareLaunchArgument(
# "gripper_name",
# default_value="",
# choices=["rbs_gripper", ""],
# description="Specify gripper name (leave empty if none).",
# )
# )
declared_arguments.append(
DeclareLaunchArgument(
"with_gripper",
default_value="true",
description="Specify if the robot includes a gripper.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gripper_name",
"use_moveit",
default_value="true",
description="Specify if MoveIt should be launched.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"use_controllers",
default_value="true",
description="Specify if controllers should be launched.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"namespace",
default_value="",
choices=["rbs_gripper", ""],
description="choose gripper by name (leave empty if hasn't)",
description="ROS 2 namespace for the robot.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"with_gripper", default_value="true", description="With gripper or not?"
"x",
default_value="0.0",
description="X-coordinate for the robot's position in the world.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_rviz", default_value="false", description="Launch RViz?"
"y",
default_value="0.0",
description="Y-coordinate for the robot's position in the world.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"sim_gazebo", default_value="true", description="Gazebo Simulation"
"z",
default_value="0.0",
description="Z-coordinate for the robot's position in the world.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_sim",
default_value="true",
description="Launch simulator (Gazebo)?\
Most general arg",
"roll",
default_value="0.0",
description="Roll orientation of the robot in the world.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_moveit", default_value="true", description="Launch moveit?"
"pitch",
default_value="0.0",
description="Pitch orientation of the robot in the world.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_perception", default_value="false", description="Launch perception?"
"yaw",
default_value="0.0",
description="Yaw orientation of the robot in the world.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_task_planner",
default_value="false",
description="Launch task_planner?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"cartesian_controllers",
default_value="false",
description="Load cartesian\
controllers?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"hardware",
choices=["gazebo", "mock"],
default_value="gazebo",
description="Choose your harware_interface",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_controllers",
default_value="true",
description="Launch controllers?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gazebo_gui", default_value="false", description="Launch gazebo with gui?"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"namespace", default_value="", description="The ROS2 namespace of a robot"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"x", default_value="0.0", description="Position of robot in world by X"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"y", default_value="0.0", description="Position of robot in world by Y"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"z", default_value="0.0", description="Position of robot in world by Z"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"roll", default_value="0.0", description="Position of robot in world by Z"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"pitch", default_value="0.0", description="Position of robot in world by Z"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"yaw", default_value="0.0", description="Position of robot in world by Z"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"roll", default_value="0.0", description="Position of robot in world by Z"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"pitch", default_value="0.0", description="Position of robot in world by Z"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"yaw", default_value="0.0", description="Position of robot in world by Z"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"multi_robot",
default_value="false",
description="Flag if you use multi robot setup",
description="Specify if the setup is for multiple robots.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"robot_description",
default_value="",
description="Robot description that override internal robot desctioption",
description="Custom robot description that overrides the internal default.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"control_space",
default_value="task",
choices=["task", "joint"],
description="Specify the control space for the robot (e.g., task space).",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"control_strategy",
default_value="position",
choices=["position", "velocity", "effort"],
description="Specify the control strategy (e.g., position control).",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"robot_description_semantic",
default_value="",
description="Custom semantic robot description (SRDF) to override the default.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"ee_link_name",
default_value="",
description="End effector name of robot arm",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"base_link_name",
default_value="",
description="Base link name if robot arm",
)
)

View file

@ -1,301 +0,0 @@
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import (
DeclareLaunchArgument,
IncludeLaunchDescription,
OpaqueFunction,
)
from launch.conditions import IfCondition
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
def launch_setup(context, *args, **kwargs):
# Initialize Arguments
robot_type = LaunchConfiguration("robot_type")
# General arguments
with_gripper_condition = LaunchConfiguration("with_gripper")
controllers_file = LaunchConfiguration("controllers_file")
cartesian_controllers = LaunchConfiguration("cartesian_controllers")
description_package = LaunchConfiguration("description_package")
description_file = LaunchConfiguration("description_file")
robot_name = LaunchConfiguration("robot_name")
start_joint_controller = LaunchConfiguration("start_joint_controller")
initial_joint_controller = LaunchConfiguration("initial_joint_controller")
launch_simulation = LaunchConfiguration("launch_sim")
launch_moveit = LaunchConfiguration("launch_moveit")
launch_task_planner = LaunchConfiguration("launch_task_planner")
launch_perception = LaunchConfiguration("launch_perception")
moveit_config_package = LaunchConfiguration("moveit_config_package")
moveit_config_file = LaunchConfiguration("moveit_config_file")
use_sim_time = LaunchConfiguration("use_sim_time")
sim_gazebo = LaunchConfiguration("sim_gazebo")
hardware = LaunchConfiguration("hardware")
env_manager = LaunchConfiguration("env_manager")
launch_controllers = LaunchConfiguration("launch_controllers")
gazebo_gui = LaunchConfiguration("gazebo_gui")
gripper_name = LaunchConfiguration("gripper_name")
sim_gazebo = LaunchConfiguration("sim_gazebo")
launch_simulation = LaunchConfiguration("launch_sim")
simulation = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[
FindPackageShare("rbs_simulation"),
"launch",
"simulation_gazebo.launch.py",
]
)
]
),
launch_arguments={
"sim_gazebo": sim_gazebo,
"debugger": "false",
"launch_env_manager": env_manager,
"gazebo_world_filename": "asm2.sdf",
}.items(),
condition=IfCondition(launch_simulation),
)
# FIXME: namespaces
# configured_params = RewrittenYaml(
# source_file=os.path.join(
# get_package_share_directory(
# description_package.perform(context)),
# "config",
# controllers_file.perform(context)),
# root_key=robot_name.perform(context),
# param_rewrites={},
# convert_types=True,
# )
initial_joint_controllers_file_path = os.path.join(
get_package_share_directory("rbs_arm"), "config", "rbs_arm0_controllers.yaml"
)
# controller_paramfile = configured_params.perform(context)
# controller_paramfile = PathJoinSubstitution([
# FindPackageShare(robot_type), "config", "rbs_arm0_controllers.yaml"
# ])
# namespace = "/" + robot_name.perform(context)
namespace = ""
gz_spawner = Node(
package="ros_gz_sim",
executable="create",
# prefix=['gdbserver localhost:1234'],
arguments=[
"-name",
robot_name.perform(context),
"-topic",
namespace + "/robot_description",
],
output="screen",
condition=IfCondition(sim_gazebo),
)
single_robot_setup = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[FindPackageShare("rbs_bringup"), "launch", "rbs_robot.launch.py"]
)
]
),
launch_arguments={
"env_manager": env_manager,
"with_gripper": with_gripper_condition,
"gripper_name": gripper_name,
"controllers_file": initial_joint_controllers_file_path,
"robot_type": robot_type,
# "controllers_file": controller_paramfile,
"cartesian_controllers": cartesian_controllers,
"description_package": description_package,
"description_file": description_file,
"robot_name": robot_type,
"start_joint_controller": start_joint_controller,
"initial_joint_controller": initial_joint_controller,
"launch_simulation": launch_simulation,
"launch_moveit": launch_moveit,
"launch_task_planner": launch_task_planner,
"launch_perception": launch_perception,
"moveit_config_package": moveit_config_package,
"moveit_config_file": moveit_config_file,
"use_sim_time": use_sim_time,
"sim_gazebo": sim_gazebo,
"hardware": hardware,
"launch_controllers": "true",
"gazebo_gui": gazebo_gui,
# "x": "0.5",
# "y": "0.5",
# "z": "0.5"
}.items(),
)
nodes_to_start = [simulation, gz_spawner, single_robot_setup]
return nodes_to_start
def generate_launch_description():
declared_arguments = []
declared_arguments.append(
DeclareLaunchArgument(
"robot_type",
description="Type of robot by name",
choices=["rbs_arm", "ur3", "ur3e", "ur5", "ur5e", "ur10", "ur10e", "ur16e"],
default_value="rbs_arm",
)
)
# General arguments
declared_arguments.append(
DeclareLaunchArgument(
"controllers_file",
default_value="rbs_arm0_controllers.yaml",
description="YAML file with the controllers configuration.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_package",
default_value="rbs_arm",
description="Description package with robot URDF/XACRO files. Usually the argument \
is not set, it enables use of a custom description.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"description_file",
default_value="rbs_arm_modular.xacro",
description="URDF/XACRO description file with the robot.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"robot_name",
default_value="arm0",
description="Name for robot, used to apply namespace for specific robot in multirobot setup",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"start_joint_controller",
default_value="false",
description="Enable headless mode for robot control",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"initial_joint_controller",
default_value="joint_trajectory_controller",
description="Robot controller to start.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_package",
default_value="rbs_arm",
description="MoveIt config package with robot SRDF/XACRO files. Usually the argument \
is not set, it enables use of a custom moveit config.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"moveit_config_file",
default_value="rbs_arm.srdf.xacro",
description="MoveIt SRDF/XACRO description file with the robot.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"use_sim_time",
default_value="true",
description="Make MoveIt to use simulation time.\
This is needed for the trajectory planing in simulation.",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gripper_name",
default_value="rbs_gripper",
choices=["rbs_gripper", ""],
description="choose gripper by name (leave empty if hasn't)",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"with_gripper", default_value="true", description="With gripper or not?"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"sim_gazebo", default_value="true", description="Gazebo Simulation"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"env_manager", default_value="true", description="Launch env_manager?"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_sim",
default_value="true",
description="Launch simulator (Gazebo)?\
Most general arg",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_moveit", default_value="false", description="Launch moveit?"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_perception", default_value="false", description="Launch perception?"
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_task_planner",
default_value="false",
description="Launch task_planner?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"cartesian_controllers",
default_value="true",
description="Load cartesian\
controllers?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"hardware",
choices=["gazebo", "mock"],
default_value="gazebo",
description="Choose your harware_interface",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"launch_controllers",
default_value="true",
description="Launch controllers?",
)
)
declared_arguments.append(
DeclareLaunchArgument(
"gazebo_gui", default_value="true", description="Launch gazebo with gui?"
)
)
return LaunchDescription(
declared_arguments + [OpaqueFunction(function=launch_setup)]
)

View file

@ -22,6 +22,7 @@ public:
bool setGoal(RosActionNode::Goal& goal) override {
getInput("robot_name", goal.robot_name);
getInput("pose", goal.target_pose);
goal.duration = 2.0;
return true;
}

View file

@ -34,6 +34,7 @@ public:
goal.target_pose = m_pose_vec->poses[0];
goal.end_effector_velocity = 0.3;
goal.end_effector_acceleration = 0.3;
goal.duration = 2.0;
m_pose_vec->poses.erase(m_pose_vec->poses.begin());
setOutput("pose_vec_out", m_pose_vec);

View file

@ -6,7 +6,7 @@ rbs_skill_interfaces/PropertyValuePair[] joint_pairs # list of joint_pairs (join
float64[] joint_values
float32 joints_velocity_scaling_factor
float32 joints_acceleration_scaling_factor
float32 timeout_seconds #if this action cannot be completed within this time period it should be considered failed.
float32 duration #if this action cannot be completed within this time period it should be considered failed.
---
#result definition
bool success

View file

@ -11,7 +11,7 @@ geometry_msgs/Pose target_pose
string robot_name
float32 end_effector_velocity
float32 end_effector_acceleration
float32 timeout_seconds #if this action cannot be completed within this time period it should be considered failed.
float32 duration #if this action cannot be completed within this time period it should be considered failed.
---
#result definition
bool success

View file

@ -1,12 +1,10 @@
cmake_minimum_required(VERSION 3.8)
project(rbs_skill_servers)
# Default to C99
# Set default standards
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
@ -15,7 +13,9 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS TRUE)
# Find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_components REQUIRED)
@ -30,126 +30,89 @@ find_package(rbs_skill_interfaces REQUIRED)
find_package(rmw REQUIRED)
find_package(tf2_eigen REQUIRED)
find_package(tf2_msgs REQUIRED)
find_package(tinyxml2_vendor REQUIRED)
find_package(TinyXML2 REQUIRED)
find_package(Eigen3 3.3 REQUIRED)
find_package(rbs_utils REQUIRED)
# find_package(moveit_servo REQUIRED)
find_package(controller_manager_msgs REQUIRED)
find_package(control_msgs REQUIRED)
# Default to Fortress
set(SDF_VER 12)
# If the user didn't specify a GZ distribution, pick the one matching the ROS
# distribution according to REP 2000
if(NOT DEFINED ENV{GZ_VERSION} AND DEFINED ENV{ROS_DISTRO})
if("$ENV{ROS_DISTRO}" STREQUAL "humble")
set(ENV{GZ_VERSION} "fortress")
endif()
endif()
# Find libsdformat matching the picked GZ distribution
if("$ENV{GZ_VERSION}" STREQUAL "fortress")
find_package(sdformat12 REQUIRED)
set(SDF_VER ${sdformat12_VERSION_MAJOR})
message(STATUS "Compiling against Gazebo Fortress (libSDFormat 12)")
elseif("$ENV{GZ_VERSION}" STREQUAL "garden")
find_package(sdformat13 REQUIRED)
set(SDF_VER ${sdformat13_VERSION_MAJOR})
message(STATUS "Compiling against Gazebo Garden (libSDFormat 13)")
# No GZ distribution specified, find any version of libsdformat we can
else()
foreach(major RANGE 13 9)
find_package(sdformat${major} QUIET)
if(sdformat${major}_FOUND)
# Next `find_package` call will be a noop
set(SDF_VER ${major})
message(STATUS "Compiling against libSDFormat ${major}")
break()
endif()
endforeach()
endif()
include_directories(SYSTEM ${TINYXML2_INCLUDE_DIR})
link_directories(${TINYXML2_LIBRARY_DIRS})
set(deps
set(DEPS
rclcpp
rclcpp_action
moveit_core
moveit_ros_planning
moveit_ros_planning_interface
control_msgs
controller_manager_msgs
moveit_msgs
# moveit_servo
geometry_msgs
tf2_ros
rclcpp_components
rbs_skill_interfaces
tf2_eigen
tf2_msgs
tinyxml2_vendor
geometric_shapes
sdformat${SDF_VER})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()
# -- GripperActionServer --
add_library(gripper_action_server SHARED src/gripper_control_action_server.cpp)
target_include_directories(
gripper_action_server
PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_definitions(gripper_action_server
PRIVATE "GRIPPER_ACTION_SERVER_CPP_BUILDING_DLL")
ament_target_dependencies(gripper_action_server ${deps})
rclcpp_components_register_node(
gripper_action_server PLUGIN "rbs_skill_actions::GripperControlActionServer"
EXECUTABLE gripper_control_action_server)
# -- PickPlacePoseLoader --
# add_library(pick_place_pose_loader SHARED src/pick_place_pose_loader.cpp)
# target_include_directories(
# pick_place_pose_loader
# PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
# $<INSTALL_INTERFACE:include>)
# target_compile_definitions(pick_place_pose_loader
# PRIVATE "PICK_PLACE_POSE_LOADER_CPP_BUILDING_DLL")
# ament_target_dependencies(pick_place_pose_loader ${deps} Eigen3
# rbs_utils)
# rclcpp_components_register_node(
# pick_place_pose_loader PLUGIN "rbs_skill_actions::GetGraspPickPoseServer"
# EXECUTABLE pick_place_pose_loader_service_server)
# -- MoveitActionServers --
add_executable(move_to_joint_states_action_server
src/move_to_joint_states_action_server.cpp)
ament_target_dependencies(move_to_joint_states_action_server ${deps})
add_executable(move_topose_action_server src/move_topose_action_server.cpp)
ament_target_dependencies(move_topose_action_server ${deps})
add_executable(move_cartesian_path_action_server
src/move_cartesian_path_action_server.cpp)
ament_target_dependencies(move_cartesian_path_action_server ${deps})
)
# add_executable(servo_action_server
# src/moveit_servo_skill_server.cpp)
# ament_target_dependencies(servo_action_server ${deps})
#
macro(add_ros2_component target_name source_file plugin_name executable_name)
add_library(${target_name} SHARED ${source_file})
target_include_directories(${target_name}
PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_definitions(${target_name} PRIVATE "${target_name}_BUILDING_DLL")
ament_target_dependencies(${target_name} ${DEPS})
rclcpp_components_register_node(${target_name} PLUGIN ${plugin_name} EXECUTABLE ${executable_name})
endmacro()
# Add components
add_ros2_component(gripper_action_server
src/gripper_command.cpp
"rbs_skill_actions::GripperControlActionServer"
gripper_command)
add_ros2_component(cartesian_move_to_pose
src/mtp_cart.cpp
"rbs_skill_actions::CartesianMoveToPose"
mtp_cart)
add_ros2_component(move_to_joint_states
src/mtjs_jtc.cpp
"rbs_skill_actions::MoveToJointStateActionServer"
mtjs_jtc)
add_ros2_component(move_to_pose
src/mtp_jtc.cpp
"rbs_skill_actions::MoveToPose"
mtp_jtc)
add_ros2_component(move_to_pose_cartesian
src/mtp_jtc_cart.cpp
"rbs_skill_actions::MoveToPoseJtcCartesian"
mtp_jtc_cart)
add_ros2_component(move_to_pose_moveit
src/mtp_moveit.cpp
"rbs_skill_actions::MoveitMtp"
mtp_moveit)
add_ros2_component(move_to_pose_moveit_cartesian
src/mtp_moveit_cart.cpp
"rbs_skill_actions::MoveitMtpCart"
mtp_moveit_cart)
# Install directories and targets
install(DIRECTORY include/ DESTINATION include)
install(DIRECTORY launch config DESTINATION share/${PROJECT_NAME})
install(
TARGETS move_topose_action_server
TARGETS
gripper_action_server
move_to_joint_states_action_server
move_cartesian_path_action_server
# servo_action_server
cartesian_move_to_pose
move_to_joint_states
move_to_pose
move_to_pose_cartesian
move_to_pose_moveit_cartesian
move_to_pose_moveit
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION lib/${PROJECT_NAME})

View file

@ -1,73 +0,0 @@
box1:
PreGraspPose: [0.25, 0.55, 0.6515, -0.707, 0.0, 0.0, 0.707]
GraspPose: [0.25, 0.655, 0.6515, -0.707, 0.0, 0.0, 0.707]
PostGraspPose: [0.25, 0.655, 0.67, -0.707, 0.0, 0.0, 0.707]
PostGraspPose2: [0.25, 0.5, 0.67, -0.707, 0.0, 0.0, 0.707]
PrePlacePose: [-0.4500, -0.055, 0.6, 1.0, 0.0, 0.0, 0.0]
PlacePose: [-0.4500, -0.055, 0.46, 1.0, 0.0, 0.0, 0.0]
PostPlacePose: [-0.4500, -0.055, 0.6, 1.0, 0.0, 0.0, 0.0]
box2:
PreGraspPose: [0.0, 0.55, 0.6515, -0.707, 0.0, 0.0, 0.707]
GraspPose: [0.0, 0.655, 0.6515, -0.707, 0.0, 0.0, 0.707]
PostGraspPose: [0.0, 0.655, 0.67, -0.707, 0.0, 0.0, 0.707]
PostGraspPose2: [0.0, 0.5, 0.67, -0.707, 0.0, 0.0, 0.707]
PrePlacePose: [-0.4500, 0.0, 0.6, 1.0, 0.0, 0.0, 0.0]
PlacePose: [-0.4500, 0.0, 0.46, 1.0, 0.0, 0.0, 0.0]
PostPlacePose: [-0.4500, 0.0, 0.6, 1.0, 0.0, 0.0, 0.0]
box3:
PreGraspPose: [-0.25, 0.55, 0.6515, -0.707, 0.0, 0.0, 0.707]
GraspPose: [-0.25, 0.655, 0.6515, -0.707, 0.0, 0.0, 0.707]
PostGraspPose: [-0.25, 0.655, 0.67, -0.707, 0.0, 0.0, 0.707]
PostGraspPose2: [-0.25, 0.5, 0.67, -0.707, 0.0, 0.0, 0.707]
PrePlacePose: [-0.4500, 0.055, 0.6, 1.0, 0.0, 0.0, 0.0]
PlacePose: [-0.4500, 0.055, 0.46, 1.0, 0.0, 0.0, 0.0]
PostPlacePose: [-0.4500, 0.055, 0.6, 1.0, 0.0, 0.0, 0.0]
box4:
PreGraspPose: [0.25, 0.55, 0.3015, -0.707, 0.0, 0.0, 0.707]
GraspPose: [0.25, 0.655, 0.3015, -0.707, 0.0, 0.0, 0.707]
PostGraspPose: [0.25, 0.655, 0.32, -0.707, 0.0, 0.0, 0.707]
PostGraspPose2: [0.25, 0.5, 0.32, -0.707, 0.0, 0.0, 0.707]
PrePlacePose: [-0.4500, 0.0275, 0.6, 1.0, 0.0, 0.0, 0.0]
PlacePose: [-0.4500, 0.0275, 0.49, 1.0, 0.0, 0.0, 0.0]
PostPlacePose: [-0.4500, 0.0275, 0.6, 1.0, 0.0, 0.0, 0.0]
box5:
PreGraspPose: [0.0, 0.55, 0.3015, -0.707, 0.0, 0.0, 0.707]
GraspPose: [0.0, 0.655, 0.3015, -0.707, 0.0, 0.0, 0.707]
PostGraspPose: [0.0, 0.655, 0.32, -0.707, 0.0, 0.0, 0.707]
PostGraspPose2: [0.0, 0.5, 0.32, -0.707, 0.0, 0.0, 0.707]
PrePlacePose: [-0.4500, -0.0275, 0.6, 1.0, 0.0, 0.0, 0.0]
PlacePose: [-0.4500, -0.0275, 0.49, 1.0, 0.0, 0.0, 0.0]
PostPlacePose: [-0.4500, -0.0275, 0.6, 1.0, 0.0, 0.0, 0.0]
box6:
PreGraspPose: [-0.25, 0.55, 0.3015, -0.707, 0.0, 0.0, 0.707]
GraspPose: [-0.25, 0.655, 0.3015, -0.707, 0.0, 0.0, 0.707]
PostGraspPose: [-0.25, 0.655, 0.32, -0.707, 0.0, 0.0, 0.707]
PostGraspPose2: [-0.25, 0.5, 0.32, -0.707, 0.0, 0.0, 0.707]
PrePlacePose: [-0.4500, 0.0, 0.6, 1.0, 0.0, 0.0, 0.0]
PlacePose: [-0.4500, 0.0, 0.56, 1.0, 0.0, 0.0, 0.0]
PostPlacePose: [-0.4500, 0.0, 0.6, 1.0, 0.0, 0.0, 0.0]
pre_place_joint_states:
- 0.11030024152330242
- 0.8306162497371689
- -1.7680363334650195
- -0.6262361658856159
- 1.4713289344704141
- -0.11066274809566562
scene_objects:
- box1
- box2
- box3
- box4
- box5
- box6
- last

View file

View file

@ -0,0 +1,456 @@
#include <algorithm>
#include <controller_manager_msgs/srv/detail/configure_controller__struct.hpp>
#include <controller_manager_msgs/srv/detail/list_controllers__struct.hpp>
#include <controller_manager_msgs/srv/detail/load_controller__struct.hpp>
#include <controller_manager_msgs/srv/detail/switch_controller__struct.hpp>
#include <memory>
#include <rclcpp/callback_group.hpp>
#include <rclcpp/node.hpp>
#include <rclcpp/node_options.hpp>
#include <rclcpp/parameter_client.hpp>
#include <rclcpp_action/create_server.hpp>
#include <rclcpp_action/server.hpp>
#include <rclcpp_action/server_goal_handle.hpp>
#include <rmw/qos_profiles.h>
#include <string>
#include <thread>
#include <vector>
namespace rbs_skill_actions {
template <typename ActionT> class SkillBase : public rclcpp::Node {
public:
explicit SkillBase(const std::string &node_name,
const std::string &action_server_name,
const rclcpp::NodeOptions &options)
: Node(node_name, options) {
auto act_cbg =
this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
m_action_server = rclcpp_action::create_server<ActionT>(
this, action_server_name,
std::bind(&SkillBase::handle_goal, this, std::placeholders::_1,
std::placeholders::_2),
std::bind(&SkillBase::handle_canceled, this, std::placeholders::_1),
std::bind(&SkillBase::handle_accepted, this, std::placeholders::_1));
m_load_controller_client =
this->create_client<controller_manager_msgs::srv::LoadController>(
"/controller_manager/load_controller");
m_switch_controller_client =
create_client<controller_manager_msgs::srv::SwitchController>(
"/controller_manager/switch_controller");
m_list_controllers_client =
create_client<controller_manager_msgs::srv::ListControllers>(
"/controller_manager/list_controllers");
m_configure_controller_client =
create_client<controller_manager_msgs::srv::ConfigureController>(
"/controller_manager/configure_controller");
}
explicit SkillBase(const std::string &node_name,
const rclcpp::NodeOptions &options)
: SkillBase(node_name, node_name, options) {}
protected:
std::shared_ptr<const typename ActionT::Goal> m_current_goal;
std::shared_ptr<typename ActionT::Result> m_current_result;
std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>>
m_current_goal_handle;
bool m_interfaces_checked{false};
virtual rclcpp_action::GoalResponse
handle_goal(const rclcpp_action::GoalUUID &uuid,
std::shared_ptr<const typename ActionT::Goal> goal) {
RCLCPP_INFO(this->get_logger(), "Received goal request for robot [%s]",
goal->robot_name.c_str());
(void)uuid;
m_current_goal = goal;
m_current_result = std::make_shared<typename ActionT::Result>();
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
}
virtual rclcpp_action::CancelResponse handle_canceled(
const std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>>
goal_handle) {
RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
(void)goal_handle;
return rclcpp_action::CancelResponse::ACCEPT;
}
void handle_accepted(
const std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>>
goal_handle) {
auto execution_thread = [this, goal_handle]() {
this->execute(goal_handle);
};
std::thread{execution_thread}.detach();
}
void execute(const std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>>
goal_handle) {
m_current_goal_handle = goal_handle;
m_required_controllers = requiredStateControllers();
m_required_controllers.push_back(requiredActionController());
m_required_controllers.erase(std::remove_if(
m_required_controllers.begin(), m_required_controllers.end(),
[](const std::string &str) { return str.empty(); }));
if (m_required_controllers.empty()) {
RCLCPP_ERROR(this->get_logger(), "Required controllers is empty");
m_current_goal_handle->abort(m_current_result);
return;
}
updateControllersMap();
if (m_controllers_map.count(requiredActionController()) &&
m_controllers_map[requiredActionController()] == "inactive") {
switchController(requiredActionController());
} else if (m_controllers_map.count(requiredActionController()) == 0) {
loadConfigureSwitchExecuteController({requiredActionController()});
} else if (!checkParameters()) {
getRequirementParametersAndExecute(requiredActionController());
} else {
executeAction();
}
}
void updateControllersMap() {
using namespace std::chrono_literals;
RCLCPP_INFO(this->get_logger(), "Called list_controllers service to check "
"if required controllers are loaded");
auto list_controllers_request = std::make_shared<
controller_manager_msgs::srv::ListControllers::Request>();
auto list_controllers_future =
m_list_controllers_client->async_send_request(list_controllers_request);
if (list_controllers_future.wait_for(3s) != std::future_status::ready) {
RCLCPP_ERROR(this->get_logger(),
"Timeout waiting for list_controllers response.");
return;
}
auto response = list_controllers_future.get();
m_controllers_map.clear();
std::unordered_set<std::string> loaded_controllers;
loaded_controllers.reserve(response->controller.size());
for (const auto &controller : response->controller) {
m_controllers_map[controller.name] = controller.state;
}
// if (m_missing_controllers.empty()) {
// RCLCPP_INFO(this->get_logger(), "All required controllers are
// loaded."); m_interfaces_checked = true; return true;
// } else {
// RCLCPP_WARN(this->get_logger(), "Missing required controllers:");
// for (const auto &missing_controller : m_missing_controllers) {
// RCLCPP_WARN(this->get_logger(), "\t- %s",
// missing_controller.c_str());
// }
// m_interfaces_checked = false;
// return false;
// }
}
void loadConfigureSwitchExecuteController(
const std::vector<std::string> &controller_names) {
for (auto &controller_name : controller_names) {
RCLCPP_WARN(this->get_logger(), "Attempting to load controller [%s]",
controller_name.c_str());
auto load_request = std::make_shared<
controller_manager_msgs::srv::LoadController::Request>();
load_request->name = controller_name;
auto load_future = m_load_controller_client->async_send_request(
load_request,
[this, controller_name](
rclcpp::Client<controller_manager_msgs::srv::LoadController>::
SharedFuture future) {
if (future.get()->ok) {
RCLCPP_INFO(this->get_logger(),
"Controller %s successfully loaded",
controller_name.c_str());
configureController(controller_name);
} else {
RCLCPP_ERROR(this->get_logger(), "Failed to load controller %s",
controller_name.c_str());
m_current_goal_handle->abort(m_current_result);
}
});
}
}
void configureController(const std::string &controller_name) {
auto configure_request = std::make_shared<
controller_manager_msgs::srv::ConfigureController::Request>();
configure_request->name = controller_name;
auto configure_future = m_configure_controller_client->async_send_request(
configure_request,
[this, controller_name](
rclcpp::Client<controller_manager_msgs::srv::ConfigureController>::
SharedFuture future) {
if (future.get()->ok) {
RCLCPP_INFO(this->get_logger(),
"Controller %s successfully configured",
controller_name.c_str());
switchController(controller_name);
} else {
RCLCPP_ERROR(this->get_logger(),
"Failed to configure controller %s",
controller_name.c_str());
m_current_goal_handle->abort(m_current_result);
}
});
}
void switchController(const std::string &controller_name) {
detectResourceConflict(controller_name, [this, controller_name](
const std::vector<std::string>
&conflicted_controllers) {
auto switch_request = std::make_shared<
controller_manager_msgs::srv::SwitchController::Request>();
switch_request->activate_controllers = {controller_name};
switch_request->deactivate_controllers = conflicted_controllers;
switch_request->strictness =
controller_manager_msgs::srv::SwitchController::Request::STRICT;
auto switch_future = m_switch_controller_client->async_send_request(
switch_request,
[this, controller_name](
rclcpp::Client<controller_manager_msgs::srv::SwitchController>::
SharedFuture future) {
if (future.get()->ok) {
RCLCPP_INFO(this->get_logger(),
"Controller %s successfully switched",
controller_name.c_str());
if (!checkParameters()) {
getRequirementParametersAndExecute(controller_name);
} else {
if (controller_name == requiredActionController()) {
executeAction();
}
}
} else {
RCLCPP_ERROR(this->get_logger(), "Failed to switch controller %s",
controller_name.c_str());
m_current_goal_handle->abort(m_current_result);
}
});
});
}
bool checkParameters() {
std::ostringstream missing_params_stream;
std::ostringstream empty_params_stream;
for (const auto &name : requiredParameters()) {
if (!this->has_parameter(name)) {
missing_params_stream << "\n\t- " << name;
continue;
}
const auto &parameter = this->get_parameter(name);
if (isEmptyParameter(parameter)) {
empty_params_stream << "\n\t- " << name;
}
}
if (missing_params_stream.tellp() > 0) {
RCLCPP_WARN(this->get_logger(),
"The following required parameters are missing:%s",
missing_params_stream.str().c_str());
}
if (empty_params_stream.tellp() > 0) {
RCLCPP_WARN(this->get_logger(),
"The following required parameters are empty:%s",
empty_params_stream.str().c_str());
}
return missing_params_stream.tellp() == 0 &&
empty_params_stream.tellp() == 0;
}
bool isEmptyParameter(const rclcpp::Parameter &parameter) {
switch (parameter.get_type()) {
case rclcpp::ParameterType::PARAMETER_STRING:
return parameter.as_string().empty();
case rclcpp::ParameterType::PARAMETER_STRING_ARRAY:
return parameter.as_string_array().empty();
case rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY:
return parameter.as_integer_array().empty();
case rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY:
return parameter.as_double_array().empty();
default:
return false;
}
}
virtual std::string requiredActionController() = 0;
virtual std::vector<std::string> requiredStateControllers() { return {""}; }
virtual std::vector<std::string> requiredParameters() { return {}; }
virtual void executeAction() = 0;
void getRequirementParametersAndExecute(const std::string &controller_name) {
RCLCPP_INFO(this->get_logger(),
"Connected to service %s, asking for parameters:",
controller_name.c_str());
for (const auto &param : requiredParameters()) {
RCLCPP_INFO(this->get_logger(), "\t- %s", param.c_str());
}
auto parameter_callback =
[this, controller_name](
const std::shared_future<std::vector<rclcpp::Parameter>> &future) {
try {
auto parameters = future.get();
if (parameters.empty()) {
RCLCPP_ERROR(this->get_logger(),
"No parameter found or empty array received");
m_current_goal_handle->abort(m_current_result);
} else {
for (const auto &param : parameters) {
switch (param.get_type()) {
case rclcpp::ParameterType::PARAMETER_BOOL:
this->declare_parameter(param.get_name(), param.as_bool());
break;
case rclcpp::ParameterType::PARAMETER_INTEGER:
this->declare_parameter(param.get_name(), param.as_int());
break;
case rclcpp::ParameterType::PARAMETER_DOUBLE:
this->declare_parameter(param.get_name(), param.as_double());
break;
case rclcpp::ParameterType::PARAMETER_STRING:
this->declare_parameter(param.get_name(), param.as_string());
break;
case rclcpp::ParameterType::PARAMETER_STRING_ARRAY:
this->declare_parameter(param.get_name(),
param.as_string_array());
break;
case rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY:
this->declare_parameter(param.get_name(),
param.as_integer_array());
break;
case rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY:
this->declare_parameter(param.get_name(),
param.as_double_array());
break;
default:
RCLCPP_WARN(this->get_logger(),
"Unsupported parameter type for parameter '%s'",
param.get_name().c_str());
break;
}
}
if (controller_name == requiredActionController()) {
executeAction();
}
}
} catch (const std::exception &e) {
RCLCPP_ERROR(this->get_logger(), "Failed to get parameter: %s",
e.what());
}
};
m_parameter_client =
std::make_shared<rclcpp::AsyncParametersClient>(this, controller_name);
auto future = m_parameter_client->get_parameters(
requiredParameters(), std::move(parameter_callback));
RCLCPP_INFO(this->get_logger(),
"Asynchronous request sent for required parameters");
}
void detectResourceConflict(
const std::string &new_controller,
std::function<void(const std::vector<std::string> &)> callback) {
auto list_controllers_request = std::make_shared<
controller_manager_msgs::srv::ListControllers::Request>();
m_list_controllers_client->async_send_request(
list_controllers_request,
[this, new_controller,
callback](const rclcpp::Client<
controller_manager_msgs::srv::ListControllers>::SharedFuture
future) {
std::vector<std::string> conflicted_controller;
auto it_new_controller = std::find_if(
future.get()->controller.begin(), future.get()->controller.end(),
[&new_controller](
const controller_manager_msgs::msg::ControllerState
controller) {
return controller.name == new_controller;
});
if (it_new_controller != future.get()->controller.end()) {
auto new_controller_interface =
it_new_controller->required_command_interfaces;
RCLCPP_INFO(this->get_logger(), "Received list of controllers");
for (const auto &controller : future.get()->controller) {
if (controller.state == "active") {
RCLCPP_INFO(this->get_logger(), "Checking controller: %s",
controller.name.c_str());
bool has_conflict = std::any_of(
controller.required_command_interfaces.begin(),
controller.required_command_interfaces.end(),
[&new_controller_interface](const std::string &interface) {
return std::find(new_controller_interface.begin(),
new_controller_interface.end(),
interface) !=
new_controller_interface.end();
});
if (has_conflict) {
conflicted_controller.push_back(controller.name);
RCLCPP_WARN(this->get_logger(), "Conflicted controller: %s",
controller.name.c_str());
}
}
}
} else {
RCLCPP_WARN(this->get_logger(),
"New controller not found in loaded controllers");
}
callback(conflicted_controller);
});
}
private:
rclcpp::Client<controller_manager_msgs::srv::LoadController>::SharedPtr
m_load_controller_client;
rclcpp::Client<controller_manager_msgs::srv::SwitchController>::SharedPtr
m_switch_controller_client;
rclcpp::Client<controller_manager_msgs::srv::ListControllers>::SharedPtr
m_list_controllers_client;
rclcpp::Client<controller_manager_msgs::srv::ConfigureController>::SharedPtr
m_configure_controller_client;
rclcpp::AsyncParametersClient::SharedPtr m_parameter_client;
typename rclcpp_action::Server<ActionT>::SharedPtr m_action_server;
std::vector<std::string> m_required_controllers{};
std::vector<std::string> m_missing_controllers{};
std::unordered_map<std::string, std::string> m_controllers_map;
};
} // namespace rbs_skill_actions

View file

@ -2,82 +2,98 @@ from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, OpaqueFunction
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from rbs_launch_utils.launch_common import load_yaml
from launch_ros.actions import ComposableNodeContainer, Node
from launch_ros.actions.composable_node_container import ComposableNode
from rbs_launch_utils.launch_common import load_yaml, load_yaml_abs
def launch_setup(context, *args, **kwargs):
robot_description_decl = LaunchConfiguration("robot_description")
robot_description_semantic_decl = LaunchConfiguration("robot_description_semantic")
robot_description_kinematics = LaunchConfiguration("robot_description_kinematics")
robot_description_content = LaunchConfiguration("robot_description")
robot_description_semantic_content = LaunchConfiguration("robot_description_semantic")
robot_description_kinematics_filepath = LaunchConfiguration("robot_description_kinematics")
use_sim_time = LaunchConfiguration("use_sim_time")
with_gripper_condition = LaunchConfiguration("with_gripper_condition")
points_params_filepath_decl = LaunchConfiguration("points_params_filepath")
robot_description = {"robot_description": robot_description_decl}
use_moveit = LaunchConfiguration("use_moveit")
ee_link_name = LaunchConfiguration("ee_link_name").perform(context)
base_link_name = LaunchConfiguration("base_link_name").perform(context)
# with_gripper_condition = LaunchConfiguration("with_gripper_condition")
robot_description = {"robot_description": robot_description_content}
robot_description_semantic = {
"robot_description_semantic": robot_description_semantic_decl
"robot_description_semantic": robot_description_semantic_content
}
namespace = LaunchConfiguration("namespace")
points_params = load_yaml("rbs_skill_servers", "config/gripperPositions.yaml")
kinematics_yaml = load_yaml("rbs_arm", "config/kinematics.yaml")
kinematics_yaml = load_yaml_abs(robot_description_kinematics_filepath.perform(context))
robot_description_kinematics = {"robot_description_kinematics": kinematics_yaml}
move_topose_action_server = Node(
package="rbs_skill_servers",
executable="move_topose_action_server",
skills_container = ComposableNodeContainer(
name="skills",
namespace=namespace,
parameters=[
robot_description,
robot_description_semantic,
robot_description_kinematics,
{"use_sim_time": use_sim_time},
],
)
gripper_control_node = Node(
package="rbs_skill_servers",
executable="gripper_control_action_server",
namespace=namespace,
parameters=[
robot_description,
robot_description_semantic,
robot_description_kinematics,
{"use_sim_time": use_sim_time},
],
condition=IfCondition(with_gripper_condition),
)
move_cartesian_path_action_server = Node(
package="rbs_skill_servers",
executable="move_cartesian_path_action_server",
namespace=namespace,
parameters=[
robot_description,
robot_description_semantic,
robot_description_kinematics,
{"use_sim_time": use_sim_time},
],
)
cartesian_move_to_pose_action_server = Node(
package="rbs_skill_servers",
executable="move_to_pose.py",
namespace=namespace,
parameters=[{"use_sim_time": use_sim_time}, {"robot_name": namespace}],
)
move_joint_state_action_server = Node(
package="rbs_skill_servers",
executable="move_to_joint_states_action_server",
namespace=namespace,
parameters=[
robot_description,
robot_description_semantic,
robot_description_kinematics,
{"use_sim_time": use_sim_time},
package="rclcpp_components",
# prefix=['gdbserver localhost:1234'],
executable="component_container_mt",
composable_node_descriptions=[
ComposableNode(
package="rbs_skill_servers",
plugin="rbs_skill_actions::MoveToJointStateActionServer",
name="mtjs_jtc",
parameters=[{"use_sim_time": use_sim_time}],
),
ComposableNode(
package="rbs_skill_servers",
plugin="rbs_skill_actions::CartesianMoveToPose",
name="mtp_cart",
parameters=[
{"use_sim_time": use_sim_time},
{"robot_name": namespace},
],
),
ComposableNode(
package="rbs_skill_servers",
plugin="rbs_skill_actions::MoveToPose",
name="mtp_jtc",
parameters=[
{"use_sim_time": use_sim_time},
{"robot_name": namespace},
robot_description,
],
),
ComposableNode(
package="rbs_skill_servers",
plugin="rbs_skill_actions::MoveToPoseJtcCartesian",
name="mtp_jtc_cart",
parameters=[
{"use_sim_time": use_sim_time},
{"robot_name": namespace},
{"base_link": base_link_name},
{"robot_ee_link": ee_link_name},
robot_description,
],
),
ComposableNode(
package="rbs_skill_servers",
plugin="rbs_skill_actions::MoveitMtp",
name="mtp_moveit",
parameters=[
robot_description,
robot_description_semantic,
robot_description_kinematics,
{"use_sim_time": use_sim_time},
],
condition=IfCondition(use_moveit),
),
ComposableNode(
package="rbs_skill_servers",
plugin="rbs_skill_actions::MoveitMtpCart",
name="mtp_moveit_cart",
parameters=[
robot_description,
robot_description_semantic,
robot_description_kinematics,
{"use_sim_time": use_sim_time},
],
condition=IfCondition(use_moveit),
),
],
)
@ -90,12 +106,7 @@ def launch_setup(context, *args, **kwargs):
nodes_to_start = [
assembly_config,
move_topose_action_server,
gripper_control_node,
move_cartesian_path_action_server,
move_joint_state_action_server,
cartesian_move_to_pose_action_server,
# grasp_pose_loader
skills_container,
]
return nodes_to_start
@ -116,15 +127,24 @@ def generate_launch_description():
declared_arguments.append(
DeclareLaunchArgument("robot_description_kinematics", default_value="")
)
declared_arguments.append(DeclareLaunchArgument("use_sim_time", default_value=""))
declared_arguments.append(
DeclareLaunchArgument("use_sim_time", default_value="false")
)
declared_arguments.append(
DeclareLaunchArgument("use_moveit", default_value="false")
)
declared_arguments.append(
DeclareLaunchArgument("with_gripper_condition", default_value="")
)
declared_arguments.append(
DeclareLaunchArgument("points_params_filepath", default_value="")
DeclareLaunchArgument("namespace", default_value="")
)
declared_arguments.append(
DeclareLaunchArgument("ee_link_name", default_value="")
)
declared_arguments.append(
DeclareLaunchArgument("base_link_name", default_value="")
)
declared_arguments.append(DeclareLaunchArgument("namespace", default_value=""))
return LaunchDescription(
declared_arguments + [OpaqueFunction(function=launch_setup)]
)

View file

@ -23,6 +23,7 @@
<depend>rbs_skill_interfaces</depend>
<depend>tf2_eigen</depend>
<depend>rbs_utils</depend>
<depend>rclcpp_components</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

View file

@ -1,164 +0,0 @@
#include <cinttypes>
#include <functional>
#include <memory>
#include <thread>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp_components/register_node_macro.hpp"
// action libs
#include "rbs_skill_interfaces/action/moveit_send_joint_states.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "geometry_msgs/msg/pose_stamped.hpp"
#include "geometry_msgs/msg/quaternion.hpp"
#include "geometry_msgs/msg/transform.hpp"
// moveit libs
#include "moveit/move_group_interface/move_group_interface.h"
#include "moveit/planning_interface/planning_interface.h"
/*
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
#include <tf2_ros/transform_listener.h>
*/
// For Visualization
// #include <eigen_conversions/eigen_msg.h>
#include "moveit_msgs/action/move_group.hpp"
#include "moveit_msgs/msg/display_robot_state.hpp"
#include "moveit_msgs/msg/display_trajectory.hpp"
#include "moveit_msgs/msg/robot_trajectory.hpp"
namespace rbs_skill_actions {
class MoveToJointStateActionServer : public rclcpp::Node {
public:
using MoveitSendJointStates =
rbs_skill_interfaces::action::MoveitSendJointStates;
// explicit MoveToPoseActionServer(const rclcpp::Node::SharedPtr& node)
explicit MoveToJointStateActionServer(const rclcpp::Node::SharedPtr &node)
: Node("move_to_joint_states_action_server"), node_(node) {
// using namespace std::placeholders;
// this->action_server_ = rclcpp_action::create_server<MoveitSendPose>(
// this->get_node_base_interface(),
// this->get_node_clock_interface(),
// this->get_node_logging_interface(),
// this->get_node_waitables_interface(),
// "move_topose",
// std::bind(&MoveToPoseActionServer::goal_callback, this, _1, _2),
// std::bind(&MoveToPoseActionServer::cancel_callback, this, _1),
// std::bind(&MoveToPoseActionServer::accepted_callback, this, _1));
}
void init() {
action_server_ = rclcpp_action::create_server<MoveitSendJointStates>(
node_->get_node_base_interface(), node_->get_node_clock_interface(),
node_->get_node_logging_interface(),
node_->get_node_waitables_interface(), "move_to_joint_states",
std::bind(&MoveToJointStateActionServer::goal_callback, this,
std::placeholders::_1, std::placeholders::_2),
std::bind(&MoveToJointStateActionServer::cancel_callback, this,
std::placeholders::_1),
std::bind(&MoveToJointStateActionServer::accepted_callback, this,
std::placeholders::_1));
}
private:
rclcpp::Node::SharedPtr node_;
rclcpp_action::Server<MoveitSendJointStates>::SharedPtr action_server_;
using ServerGoalHandle =
rclcpp_action::ServerGoalHandle<MoveitSendJointStates>;
rclcpp_action::GoalResponse
goal_callback(const rclcpp_action::GoalUUID &uuid,
std::shared_ptr<const MoveitSendJointStates::Goal> goal) {
RCLCPP_INFO(this->get_logger(), "Goal received for robot [%s]",
goal->robot_name.c_str());
(void)uuid;
if (false) {
return rclcpp_action::GoalResponse::REJECT;
}
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
}
rclcpp_action::CancelResponse
cancel_callback(const std::shared_ptr<ServerGoalHandle> goal_handle) {
RCLCPP_INFO(this->get_logger(), "Received cancel request");
(void)goal_handle;
return rclcpp_action::CancelResponse::ACCEPT;
}
void accepted_callback(const std::shared_ptr<ServerGoalHandle> goal_handle) {
using namespace std::placeholders;
std::thread(std::bind(&MoveToJointStateActionServer::execute, this, _1),
goal_handle)
.detach();
}
void execute(const std::shared_ptr<ServerGoalHandle> goal_handle) {
RCLCPP_INFO(this->get_logger(), "Executing action goal");
const auto goal = goal_handle->get_goal();
auto result = std::make_shared<MoveitSendJointStates::Result>();
moveit::planning_interface::MoveGroupInterface move_group_interface(
node_, goal->robot_name);
move_group_interface.startStateMonitor();
std::vector<double> joint_states = goal->joint_values;
for (auto &joint : joint_states) {
RCLCPP_INFO(this->get_logger(), "Joint value %f", joint);
}
move_group_interface.setJointValueTarget(goal->joint_values);
move_group_interface.setMaxVelocityScalingFactor(
goal->joints_velocity_scaling_factor);
move_group_interface.setMaxAccelerationScalingFactor(
goal->joints_acceleration_scaling_factor);
moveit::planning_interface::MoveGroupInterface::Plan plan;
bool success = (move_group_interface.plan(plan) ==
moveit::core::MoveItErrorCode::SUCCESS);
if (success) {
RCLCPP_INFO(this->get_logger(), "Planning success");
move_group_interface.execute(plan);
// move_group_interface.move();
} else {
RCLCPP_WARN(this->get_logger(), "Failed to generate plan");
}
if (goal_handle->is_canceling()) {
goal_handle->canceled(result);
RCLCPP_ERROR(this->get_logger(), "Action goal canceled");
return;
}
goal_handle->succeed(result);
RCLCPP_INFO(this->get_logger(), "Successfully executed action goal");
}
}; // class MoveToJointStateActionServer
} // namespace rbs_skill_actions
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
rclcpp::NodeOptions node_options;
node_options.automatically_declare_parameters_from_overrides(true);
auto node =
rclcpp::Node::make_shared("move_to_joint_states", "", node_options);
rbs_skill_actions::MoveToJointStateActionServer server(node);
std::thread run_server([&server]() {
rclcpp::sleep_for(std::chrono::seconds(3));
server.init();
});
rclcpp::spin(node);
run_server.join();
return 0;
}

View file

@ -0,0 +1,155 @@
#include "control_msgs/action/follow_joint_trajectory.hpp"
#include "rbs_skill_servers/base_skill.hpp"
#include <memory>
#include <rbs_skill_interfaces/action/detail/moveit_send_joint_states__struct.hpp>
#include <rclcpp/logging.hpp>
#include <rclcpp_action/client.hpp>
#include <rclcpp_action/client_goal_handle.hpp>
#include <rclcpp_action/create_client.hpp>
#include <sensor_msgs/msg/joint_state.hpp>
#include <string>
#include <vector>
namespace rbs_skill_actions {
using MoveitSendJointStates =
rbs_skill_interfaces::action::MoveitSendJointStates;
using GoalHandleMoveitSendJointStates =
rclcpp_action::ServerGoalHandle<MoveitSendJointStates>;
using FollowJointTrajectory = control_msgs::action::FollowJointTrajectory;
using FollowJointTrajectoryGoalHandle =
rclcpp_action::ClientGoalHandle<FollowJointTrajectory>;
class MoveToJointStateActionServer : public SkillBase<MoveitSendJointStates> {
public:
explicit MoveToJointStateActionServer(
const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
: SkillBase<MoveitSendJointStates>("mtjs_jtc", options) {
m_joint_trajectory_client =
rclcpp_action::create_client<FollowJointTrajectory>(
this, "/joint_trajectory_controller/follow_joint_trajectory");
auto cbg =
this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
rclcpp::SubscriptionOptions s_options;
s_options.callback_group = cbg;
m_joint_state_subscriber =
this->create_subscription<sensor_msgs::msg::JointState>(
"/joint_states", 10,
std::bind(&MoveToJointStateActionServer::jointStateCallback, this,
std::placeholders::_1),
s_options);
}
protected:
std::string requiredActionController() override {
return "joint_trajectory_controller";
}
std::vector<std::string> requiredParameters() override { return {"joints"}; }
void executeAction() override {
RCLCPP_INFO(this->get_logger(), "Starting executing action goal");
auto trajectory_goal = FollowJointTrajectory::Goal();
auto joints = this->get_parameters(requiredParameters());
m_joint_names = joints.at(0).as_string_array();
trajectory_goal.trajectory.joint_names = m_joint_names;
// TODO: Better sync solution
while (m_current_joint_positions.empty()) {
}
trajectory_goal.trajectory.points = generate_trajectory(
m_current_joint_positions, m_current_goal->joint_values,
m_current_goal->duration);
auto send_goal_options =
rclcpp_action::Client<FollowJointTrajectory>::SendGoalOptions();
send_goal_options.result_callback =
[this](const FollowJointTrajectoryGoalHandle::WrappedResult
&wrapped_result) {
if (wrapped_result.code == rclcpp_action::ResultCode::SUCCEEDED) {
RCLCPP_INFO(this->get_logger(), "Goal succeeded");
m_current_goal_handle->succeed(m_current_result);
} else {
RCLCPP_ERROR(this->get_logger(), "Goal failed");
m_current_goal_handle->abort(m_current_result);
}
};
m_joint_trajectory_client->async_send_goal(trajectory_goal,
send_goal_options);
}
private:
void jointStateCallback(const sensor_msgs::msg::JointState::SharedPtr msg) {
if (m_joint_names.empty()) {
return;
}
// RCLCPP_INFO(this->get_logger(), "Called joint positions");
if (m_joint_mame_to_index.empty()) {
m_joint_mame_to_index.reserve(m_joint_names.size());
for (size_t j = 0; j < m_joint_names.size(); ++j) {
auto it =
std::find(msg->name.begin(), msg->name.end(), m_joint_names[j]);
if (it != msg->name.end()) {
size_t index = std::distance(msg->name.begin(), it);
m_joint_mame_to_index[m_joint_names[j]] = index;
}
}
}
if (m_current_joint_positions.size() != m_joint_names.size()) {
m_current_joint_positions.resize(m_joint_names.size(), 0.0);
}
for (size_t j = 0; j < m_joint_names.size(); ++j) {
auto index_it = m_joint_mame_to_index.find(m_joint_names[j]);
if (index_it != m_joint_mame_to_index.end()) {
m_current_joint_positions[j] = msg->position[index_it->second];
}
}
}
std::vector<trajectory_msgs::msg::JointTrajectoryPoint>
generate_trajectory(const std::vector<double> &start_joint_values,
const std::vector<double> &target_joint_values,
const double duration) {
const int num_points = 100;
std::vector<trajectory_msgs::msg::JointTrajectoryPoint> points;
for (int i = 0; i <= num_points; ++i) {
trajectory_msgs::msg::JointTrajectoryPoint point;
double t = static_cast<double>(i) / num_points;
for (size_t j = 0; j < target_joint_values.size(); ++j) {
double position = start_joint_values[j] +
t * (target_joint_values[j] - start_joint_values[j]);
point.positions.push_back(position);
}
point.time_from_start = rclcpp::Duration::from_seconds(t * duration);
points.push_back(point);
}
return points;
}
rclcpp_action::Client<FollowJointTrajectory>::SharedPtr
m_joint_trajectory_client;
rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr
m_joint_state_subscriber;
std::vector<double> m_current_joint_positions;
std::unordered_map<std::string, size_t> m_joint_mame_to_index;
std::vector<std::string> m_joint_names;
};
} // namespace rbs_skill_actions
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(
rbs_skill_actions::MoveToJointStateActionServer);

View file

@ -0,0 +1,183 @@
#include "Eigen/Dense"
#include <geometry_msgs/msg/pose_stamped.hpp>
#include <rclcpp/logging.hpp>
// Action libs
#include "rbs_skill_interfaces/action/moveit_send_pose.hpp"
#include "rbs_skill_servers/base_skill.hpp"
namespace rbs_skill_actions {
using MoveitSendPose = rbs_skill_interfaces::action::MoveitSendPose;
using GoalHandleMoveitSendPose =
rclcpp_action::ServerGoalHandle<MoveitSendPose>;
class CartesianMoveToPose : public SkillBase<MoveitSendPose> {
public:
explicit CartesianMoveToPose(
const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
: SkillBase<MoveitSendPose>("mtp_cart", options), m_current_step(0) {
// Initialize publisher for target poses
auto cbg =
this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
rclcpp::PublisherOptions p_options;
p_options.callback_group = cbg;
m_publisher = this->create_publisher<geometry_msgs::msg::PoseStamped>(
"cartesian_motion_controller/target_frame", 10, p_options);
m_current_pose = std::make_shared<geometry_msgs::msg::PoseStamped>();
rclcpp::SubscriptionOptions s_options;
s_options.callback_group = cbg;
m_current_pose_subscriber =
this->create_subscription<geometry_msgs::msg::PoseStamped>(
"cartesian_motion_controller/current_pose", 10,
std::bind(&CartesianMoveToPose::on_pose_callback, this,
std::placeholders::_1),
s_options);
}
protected:
std::string requiredActionController() override {
return "cartesian_motion_controller";
}
std::vector<std::string> requiredParameters() override {
return {"end_effector_link", "robot_base_link"};
}
void executeAction() override {
m_base_link = this->get_parameter("robot_base_link").as_string();
m_trajectory =
interpolate(m_current_pose->pose, m_current_goal->target_pose);
m_current_step = 0;
m_total_time = m_current_goal->duration;
m_step_time =
m_total_time / static_cast<double>(m_trajectory.size()) * 1000.0;
m_trajectory_timer = this->create_wall_timer(
std::chrono::milliseconds(static_cast<int>(m_step_time)),
[this]() { adjust_and_publish_pose(); });
}
private:
rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr m_publisher;
rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr
m_current_pose_subscriber;
geometry_msgs::msg::PoseStamped::SharedPtr m_current_pose;
std::string m_base_link;
double m_threshold_distance = 0.02;
std::vector<geometry_msgs::msg::Pose> m_trajectory;
size_t m_current_step;
rclcpp::TimerBase::SharedPtr m_trajectory_timer;
double m_total_time;
double m_step_time;
void adjust_and_publish_pose() {
if (m_current_step < m_trajectory.size()) {
publish_pose(m_trajectory[m_current_step++]);
} else {
double distance =
calculate_distance(m_current_pose->pose, m_current_goal->target_pose);
if (distance <= m_threshold_distance) {
m_current_result->success = true;
m_current_goal_handle->succeed(m_current_result);
RCLCPP_INFO(this->get_logger(), "Goal successfully completed");
m_trajectory_timer->cancel();
} else {
publish_pose(m_trajectory.back());
}
}
}
double calculate_distance(const geometry_msgs::msg::Pose &p1,
const geometry_msgs::msg::Pose &p2) {
Eigen::Vector3d pos1(p1.position.x, p1.position.y, p1.position.z);
Eigen::Vector3d pos2(p2.position.x, p2.position.y, p2.position.z);
double position_distance = (pos1 - pos2).norm();
Eigen::Quaterniond orient1 = normalize_orientation(p1.orientation);
Eigen::Quaterniond orient2 = normalize_orientation(p2.orientation);
return position_distance + orient1.angularDistance(orient2);
}
Eigen::Quaterniond
normalize_orientation(const geometry_msgs::msg::Quaternion &q) {
Eigen::Quaterniond orientation(q.w, q.x, q.y, q.z);
orientation.normalize();
if (orientation.norm() == 0) {
RCLCPP_FATAL(this->get_logger(),
"Quaternion has zero norm; normalization failed.");
throw std::runtime_error("Quaternion normalization failed.");
}
return orientation;
}
std::vector<geometry_msgs::msg::Pose>
interpolate(const geometry_msgs::msg::Pose &start_pose,
const geometry_msgs::msg::Pose &end_pose) {
std::vector<geometry_msgs::msg::Pose> trajectory;
Eigen::Vector3d start_position(start_pose.position.x, start_pose.position.y,
start_pose.position.z);
Eigen::Vector3d end_position(end_pose.position.x, end_pose.position.y,
end_pose.position.z);
Eigen::Quaterniond start_orientation =
normalize_orientation(start_pose.orientation);
Eigen::Quaterniond end_orientation =
normalize_orientation(end_pose.orientation);
double distance = (end_position - start_position).norm();
int num_steps = static_cast<int>(distance / 0.01);
for (int i = 0; i <= num_steps; ++i) {
double t = static_cast<double>(i) / num_steps;
Eigen::Vector3d interpolated_position =
start_position + t * (end_position - start_position);
Eigen::Quaterniond interpolated_orientation =
start_orientation.slerp(t, end_orientation);
geometry_msgs::msg::Pose interpolated_pose;
interpolated_pose.position.x = interpolated_position.x();
interpolated_pose.position.y = interpolated_position.y();
interpolated_pose.position.z = interpolated_position.z();
interpolated_pose.orientation.x = interpolated_orientation.x();
interpolated_pose.orientation.y = interpolated_orientation.y();
interpolated_pose.orientation.z = interpolated_orientation.z();
interpolated_pose.orientation.w = interpolated_orientation.w();
trajectory.push_back(interpolated_pose);
}
return trajectory;
}
void publish_pose(const geometry_msgs::msg::Pose &pose) {
geometry_msgs::msg::PoseStamped tp;
tp.pose = pose;
tp.header.stamp = this->now();
tp.header.frame_id = m_base_link;
m_publisher->publish(tp);
}
void on_pose_callback(const geometry_msgs::msg::PoseStamped::SharedPtr msg) {
m_current_pose = msg;
}
};
} // namespace rbs_skill_actions
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(rbs_skill_actions::CartesianMoveToPose);

View file

@ -0,0 +1,224 @@
#include "Eigen/Dense"
#include "control_msgs/action/follow_joint_trajectory.hpp"
#include "kdl/chainiksolverpos_lma.hpp"
#include "rbs_skill_servers/base_skill.hpp"
#include <cstddef>
#include <iterator>
#include <kdl/chain.hpp>
#include <kdl/chainiksolver.hpp>
#include <kdl/chainiksolvervel_wdls.hpp>
#include <kdl/chainjnttojacsolver.hpp>
#include <kdl/frames.hpp>
#include <kdl/jntarray.hpp>
#include <kdl/tree.hpp>
#include <kdl_parser/kdl_parser.hpp>
#include <memory>
#include <rbs_skill_interfaces/action/detail/moveit_send_pose__struct.hpp>
#include <rclcpp/logging.hpp>
#include <rclcpp/parameter_client.hpp>
#include <rclcpp_action/client.hpp>
#include <rclcpp_action/client_goal_handle.hpp>
#include <rclcpp_action/create_client.hpp>
#include <sensor_msgs/msg/joint_state.hpp>
#include <string>
#include <tf2_eigen/tf2_eigen.hpp>
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
#include <vector>
namespace rbs_skill_actions {
using MoveitSendPose = rbs_skill_interfaces::action::MoveitSendPose;
using GoalHandleMoveitSendJointStates =
rclcpp_action::ServerGoalHandle<MoveitSendPose>;
using FollowJointTrajectory = control_msgs::action::FollowJointTrajectory;
using FollowJointTrajectoryGoalHandle =
rclcpp_action::ClientGoalHandle<FollowJointTrajectory>;
class MoveToPose : public SkillBase<MoveitSendPose> {
public:
explicit MoveToPose(
const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
: SkillBase<MoveitSendPose>("mtp_jtc", options) {
m_joint_trajectory_client =
rclcpp_action::create_client<FollowJointTrajectory>(
this, "/joint_trajectory_controller/follow_joint_trajectory");
auto cbg =
this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
rclcpp::SubscriptionOptions s_options;
s_options.callback_group = cbg;
m_joint_state_subscriber =
this->create_subscription<sensor_msgs::msg::JointState>(
"/joint_states", 10,
std::bind(&MoveToPose::jointStateCallback, this,
std::placeholders::_1),
s_options);
this->declare_parameter("robot_description", "");
}
protected:
std::string requiredActionController() override {
return "joint_trajectory_controller";
}
std::vector<std::string> requiredParameters() override { return {"joints"}; }
void executeAction() override {
RCLCPP_INFO(this->get_logger(), "Starting executing action goal");
auto trajectory_goal = FollowJointTrajectory::Goal();
auto joints = this->get_parameters(requiredParameters());
m_joint_names = joints.at(0).as_string_array();
trajectory_goal.trajectory.joint_names = m_joint_names;
// TODO: Better sync solution
while (m_current_joint_positions.empty()) {
}
std::vector<double> target_joint_values;
solveIK(target_joint_values);
trajectory_goal.trajectory.points =
generate_trajectory(m_current_joint_positions, target_joint_values,
m_current_goal->duration);
auto send_goal_options =
rclcpp_action::Client<FollowJointTrajectory>::SendGoalOptions();
send_goal_options.result_callback =
[this](const FollowJointTrajectoryGoalHandle::WrappedResult
&wrapped_result) {
if (wrapped_result.code == rclcpp_action::ResultCode::SUCCEEDED) {
RCLCPP_INFO(this->get_logger(), "Goal succeeded");
m_current_goal_handle->succeed(m_current_result);
} else {
RCLCPP_ERROR(this->get_logger(), "Goal failed");
m_current_goal_handle->abort(m_current_result);
}
};
m_joint_trajectory_client->async_send_goal(trajectory_goal,
send_goal_options);
}
private:
void jointStateCallback(const sensor_msgs::msg::JointState::SharedPtr msg) {
if (m_joint_names.empty()) {
return;
}
RCLCPP_WARN(this->get_logger(), "Called joint positions");
if (m_joint_mame_to_index.empty()) {
m_joint_mame_to_index.reserve(m_joint_names.size());
for (size_t j = 0; j < m_joint_names.size(); ++j) {
auto it =
std::find(msg->name.begin(), msg->name.end(), m_joint_names[j]);
if (it != msg->name.end()) {
size_t index = std::distance(msg->name.begin(), it);
m_joint_mame_to_index[m_joint_names[j]] = index;
}
}
}
if (m_current_joint_positions.size() != m_joint_names.size()) {
m_current_joint_positions.resize(m_joint_names.size(), 0.0);
}
for (size_t j = 0; j < m_joint_names.size(); ++j) {
auto index_it = m_joint_mame_to_index.find(m_joint_names[j]);
if (index_it != m_joint_mame_to_index.end()) {
m_current_joint_positions[j] = msg->position[index_it->second];
}
}
}
std::vector<trajectory_msgs::msg::JointTrajectoryPoint>
generate_trajectory(const std::vector<double> &start_joint_values,
const std::vector<double> &target_joint_values,
const double duration) {
const int num_points = 100;
std::vector<trajectory_msgs::msg::JointTrajectoryPoint> points;
for (int i = 0; i <= num_points; ++i) {
trajectory_msgs::msg::JointTrajectoryPoint point;
double t = static_cast<double>(i) / num_points;
for (size_t j = 0; j < target_joint_values.size(); ++j) {
double position = start_joint_values[j] +
t * (target_joint_values[j] - start_joint_values[j]);
point.positions.push_back(position);
}
point.time_from_start = rclcpp::Duration::from_seconds(t * duration);
points.push_back(point);
}
return points;
}
void solveIK(std::vector<double> &out) {
KDL::JntArray q_in(m_joint_names.size());
for (size_t i = 0; i < m_joint_names.size(); ++i) {
q_in(i) = m_current_joint_positions[i];
}
KDL::JntArray q_out(m_joint_names.size());
Eigen::Affine3d target_pose;
Eigen::fromMsg(m_current_goal->target_pose, target_pose);
KDL::Frame target_pose_kdl(
KDL::Rotation(target_pose(0, 0), target_pose(0, 1), target_pose(0, 2),
target_pose(1, 0), target_pose(1, 1), target_pose(1, 2),
target_pose(2, 0), target_pose(2, 1), target_pose(2, 2)),
KDL::Vector(target_pose.translation().x(),
target_pose.translation().y(),
target_pose.translation().z()));
const std::string m_base_link = "base_link";
const std::string m_ee_link = "gripper_grasp_point";
auto robot_description =
this->get_parameter("robot_description").as_string();
KDL::Tree kdl_tree;
if (!kdl_parser::treeFromString(robot_description, kdl_tree)) {
RCLCPP_ERROR(this->get_logger(),
"Failed to parse KDL tree from robot description.");
return;
}
KDL::Chain kdl_chain;
if (!kdl_tree.getChain(m_base_link, m_ee_link, kdl_chain)) {
RCLCPP_ERROR(this->get_logger(),
"Failed to get KDL chain from base to end-effector.");
return;
}
auto ik_solver =
std::make_unique<KDL::ChainIkSolverPos_LMA>(kdl_chain, 1e-5, 500);
if (ik_solver->CartToJnt(q_in, target_pose_kdl, q_out) >= 0) {
out.resize(q_out.rows());
for (size_t i = 0; i < out.size(); i++) {
out[i] = q_out(i);
}
} else {
RCLCPP_ERROR(this->get_logger(), "IK solution not found.");
}
}
rclcpp_action::Client<FollowJointTrajectory>::SharedPtr
m_joint_trajectory_client;
rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr
m_joint_state_subscriber;
std::vector<double> m_current_joint_positions;
std::unordered_map<std::string, size_t> m_joint_mame_to_index;
std::vector<std::string> m_joint_names;
};
} // namespace rbs_skill_actions
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(rbs_skill_actions::MoveToPose);

View file

@ -0,0 +1,324 @@
#include "Eigen/Dense"
#include "control_msgs/action/follow_joint_trajectory.hpp"
#include "kdl/chainfksolverpos_recursive.hpp"
#include "kdl/chainiksolverpos_lma.hpp"
#include "rbs_skill_servers/base_skill.hpp"
#include <Eigen/src/Geometry/Transform.h>
#include <cstddef>
#include <iterator>
#include <kdl/chain.hpp>
#include <kdl/chainiksolver.hpp>
#include <kdl/chainiksolvervel_wdls.hpp>
#include <kdl/chainjnttojacsolver.hpp>
#include <kdl/frames.hpp>
#include <kdl/jntarray.hpp>
#include <kdl/tree.hpp>
#include <kdl_parser/kdl_parser.hpp>
#include <memory>
#include <rbs_skill_interfaces/action/detail/moveit_send_pose__struct.hpp>
#include <rclcpp/logging.hpp>
#include <rclcpp/parameter_client.hpp>
#include <rclcpp_action/client.hpp>
#include <rclcpp_action/client_goal_handle.hpp>
#include <rclcpp_action/create_client.hpp>
#include <sensor_msgs/msg/joint_state.hpp>
#include <string>
#include <tf2_eigen/tf2_eigen.hpp>
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
#include <vector>
namespace rbs_skill_actions {
using MoveitSendPose = rbs_skill_interfaces::action::MoveitSendPose;
using GoalHandleMoveitSendJointStates =
rclcpp_action::ServerGoalHandle<MoveitSendPose>;
using FollowJointTrajectory = control_msgs::action::FollowJointTrajectory;
using FollowJointTrajectoryGoalHandle =
rclcpp_action::ClientGoalHandle<FollowJointTrajectory>;
class MoveToPoseJtcCartesian : public SkillBase<MoveitSendPose> {
public:
explicit MoveToPoseJtcCartesian(
const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
: SkillBase<MoveitSendPose>("mtp_jtc_cart", options) {
m_joint_trajectory_client =
rclcpp_action::create_client<FollowJointTrajectory>(
this, "/joint_trajectory_controller/follow_joint_trajectory");
auto cbg =
this->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
rclcpp::SubscriptionOptions s_options;
s_options.callback_group = cbg;
m_joint_state_subscriber =
this->create_subscription<sensor_msgs::msg::JointState>(
"/joint_states", 10,
std::bind(&MoveToPoseJtcCartesian::jointStateCallback, this,
std::placeholders::_1),
s_options);
this->declare_parameter("robot_description", "");
this->declare_parameter("base_link", "");
this->declare_parameter("robot_ee_link", "");
auto robot_description =
this->get_parameter("robot_description").as_string();
KDL::Tree kdl_tree;
if (!kdl_parser::treeFromString(robot_description, kdl_tree)) {
RCLCPP_ERROR(this->get_logger(),
"Failed to obtain KDL tree from the robot description.");
throw std::runtime_error("KDL Tree initialization failed");
}
auto base_link = this->get_parameter("base_link").as_string();
auto robot_ee_link = this->get_parameter("robot_ee_link").as_string();
if (base_link.empty() or robot_ee_link.empty()) {
RCLCPP_ERROR(this->get_logger(),
"Describe robot end-effector link and base link to continue");
throw std::runtime_error("Describe robot end-effector link and base link to continue");
}
if (!kdl_tree.getChain(base_link, robot_ee_link, m_kdl_chain)) {
RCLCPP_ERROR(this->get_logger(),
"Failed to obtain KDL chain from base to end-effector.");
throw std::runtime_error("KDL Chain initialization failed");
}
}
protected:
std::string requiredActionController() override {
return "joint_trajectory_controller";
}
std::vector<std::string> requiredParameters() override { return {"joints"}; }
void executeAction() override {
RCLCPP_INFO(this->get_logger(), "Starting executing action goal");
auto trajectory_goal = FollowJointTrajectory::Goal();
auto joints = this->get_parameters(requiredParameters());
m_joint_names = joints.at(0).as_string_array();
trajectory_goal.trajectory.joint_names = m_joint_names;
const int max_wait_iterations = 100;
int wait_count = 0;
while (m_current_joint_positions.empty() &&
wait_count++ < max_wait_iterations) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (m_current_joint_positions.empty()) {
RCLCPP_ERROR(this->get_logger(),
"Joint positions were not received in time");
return;
}
std::vector<double> target_joint_values;
Eigen::Affine3d target_pose;
Eigen::fromMsg(m_current_goal->target_pose, target_pose);
if (!solveIK(target_pose, target_joint_values)) {
RCLCPP_ERROR(this->get_logger(),
"IK solution not found for goal position");
m_current_goal_handle->abort(m_current_result);
}
trajectory_goal.trajectory.points =
generate_trajectory(m_current_joint_positions, target_joint_values,
m_current_goal->duration);
auto send_goal_options =
rclcpp_action::Client<FollowJointTrajectory>::SendGoalOptions();
send_goal_options.result_callback =
[this](const FollowJointTrajectoryGoalHandle::WrappedResult
&wrapped_result) {
if (wrapped_result.code == rclcpp_action::ResultCode::SUCCEEDED) {
RCLCPP_INFO(this->get_logger(), "Goal succeeded");
m_current_goal_handle->succeed(m_current_result);
} else {
RCLCPP_ERROR(this->get_logger(), "Goal failed");
m_current_goal_handle->abort(m_current_result);
}
};
m_joint_trajectory_client->async_send_goal(trajectory_goal,
send_goal_options);
}
private:
void jointStateCallback(const sensor_msgs::msg::JointState::SharedPtr msg) {
if (m_joint_names.empty()) {
return;
}
if (m_joint_name_to_index.empty()) {
m_joint_name_to_index.reserve(m_joint_names.size());
for (size_t j = 0; j < m_joint_names.size(); ++j) {
auto it =
std::find(msg->name.begin(), msg->name.end(), m_joint_names[j]);
if (it != msg->name.end()) {
size_t index = std::distance(msg->name.begin(), it);
m_joint_name_to_index[m_joint_names[j]] = index;
}
}
}
if (m_current_joint_positions.size() != m_joint_names.size()) {
m_current_joint_positions.resize(m_joint_names.size(), 0.0);
}
for (size_t j = 0; j < m_joint_names.size(); ++j) {
auto index_it = m_joint_name_to_index.find(m_joint_names[j]);
if (index_it != m_joint_name_to_index.end()) {
m_current_joint_positions[j] = msg->position[index_it->second];
}
}
}
std::vector<trajectory_msgs::msg::JointTrajectoryPoint>
generate_trajectory(const std::vector<double> &start_joint_values,
const std::vector<double> &target_joint_values,
const double duration) {
const int num_points = 100;
std::vector<trajectory_msgs::msg::JointTrajectoryPoint> points;
KDL::Frame start_pose_kdl, target_pose_kdl;
if (!getEndEffectorPose(start_joint_values, start_pose_kdl) ||
!getEndEffectorPose(target_joint_values, target_pose_kdl)) {
RCLCPP_ERROR(this->get_logger(),
"Failed to get initial or target end-effector pose");
return points;
}
Eigen::Affine3d start_pose = KDLFrameToEigen(start_pose_kdl);
Eigen::Affine3d target_pose = KDLFrameToEigen(target_pose_kdl);
for (int i = 0; i <= num_points; ++i) {
trajectory_msgs::msg::JointTrajectoryPoint point;
double t = static_cast<double>(i) / num_points;
Eigen::Vector3d start_translation = start_pose.translation();
Eigen::Vector3d target_translation = target_pose.translation();
Eigen::Vector3d interpolated_translation =
(1.0 - t) * start_translation + t * target_translation;
Eigen::Translation3d interpolated_translation_transform(
interpolated_translation);
Eigen::Quaterniond start_quaternion(start_pose.rotation());
Eigen::Quaterniond target_quaternion(target_pose.rotation());
Eigen::Quaterniond interpolated_quaternion =
start_quaternion.slerp(t, target_quaternion);
Eigen::Affine3d interpolated_pose =
interpolated_translation_transform * interpolated_quaternion;
std::vector<double> ik_joint_values;
if (!solveIK(interpolated_pose, ik_joint_values)) {
RCLCPP_ERROR(this->get_logger(), "IK solution not found for point %d",
i);
return {};
}
point.positions = ik_joint_values;
point.time_from_start = rclcpp::Duration::from_seconds(t * duration);
points.push_back(point);
}
return points;
}
bool getEndEffectorPose(const std::vector<double> &joint_positions,
KDL::Frame &end_effector_pose) {
if (joint_positions.size() != m_joint_names.size()) {
RCLCPP_ERROR(this->get_logger(), "Mismatch between provided joint "
"positions and expected joint names.");
RCLCPP_ERROR(this->get_logger(), "Joint pos size: %zu",
joint_positions.size());
RCLCPP_ERROR(this->get_logger(), "Joint names size: %zu",
m_joint_names.size());
return false;
}
std::unordered_set<std::string> available_joints(m_joint_names.begin(),
m_joint_names.end());
if (available_joints.size() != m_joint_names.size()) {
RCLCPP_ERROR(this->get_logger(),
"Duplicate joints detected in joint names list.");
return false;
}
KDL::JntArray q_in(joint_positions.size());
for (size_t i = 0; i < joint_positions.size(); ++i) {
q_in(i) = joint_positions[i];
}
KDL::ChainFkSolverPos_recursive fk_solver(m_kdl_chain);
if (fk_solver.JntToCart(q_in, end_effector_pose) < 0) {
RCLCPP_ERROR(this->get_logger(),
"Failed to compute FK for the specified joint positions.");
return false;
}
return true;
}
Eigen::Affine3d KDLFrameToEigen(const KDL::Frame &frame) {
Eigen::Affine3d transform;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
transform(i, j) = frame.M(i, j);
}
transform(i, 3) = frame.p[i];
}
transform(3, 3) = 1.0;
return transform;
}
bool solveIK(const Eigen::Affine3d &target_pose, std::vector<double> &out) {
KDL::JntArray q_in(m_joint_names.size());
for (size_t i = 0; i < m_joint_names.size(); ++i) {
q_in(i) = m_current_joint_positions[i];
}
KDL::JntArray q_out(m_joint_names.size());
KDL::Frame target_pose_kdl(
KDL::Rotation(target_pose(0, 0), target_pose(0, 1), target_pose(0, 2),
target_pose(1, 0), target_pose(1, 1), target_pose(1, 2),
target_pose(2, 0), target_pose(2, 1), target_pose(2, 2)),
KDL::Vector(target_pose.translation().x(),
target_pose.translation().y(),
target_pose.translation().z()));
auto ik_solver =
std::make_unique<KDL::ChainIkSolverPos_LMA>(m_kdl_chain, 1e-5, 500);
if (ik_solver->CartToJnt(q_in, target_pose_kdl, q_out) >= 0) {
out.resize(q_out.rows());
for (size_t i = 0; i < out.size(); i++) {
out[i] = q_out(i);
}
return true;
} else {
RCLCPP_ERROR(this->get_logger(), "IK solution not found.");
return false;
}
}
rclcpp_action::Client<FollowJointTrajectory>::SharedPtr
m_joint_trajectory_client;
rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr
m_joint_state_subscriber;
std::vector<double> m_current_joint_positions;
std::unordered_map<std::string, size_t> m_joint_name_to_index;
std::vector<std::string> m_joint_names;
KDL::Chain m_kdl_chain;
};
} // namespace rbs_skill_actions
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(rbs_skill_actions::MoveToPoseJtcCartesian);

View file

@ -0,0 +1,68 @@
#include "moveit/move_group_interface/move_group_interface.h"
#include "rbs_skill_interfaces/action/moveit_send_pose.hpp"
#include "rbs_skill_servers/base_skill.hpp"
namespace rbs_skill_actions {
using MoveitSendPose = rbs_skill_interfaces::action::MoveitSendPose;
class MoveitMtp : public SkillBase<MoveitSendPose> {
public:
explicit MoveitMtp(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
: SkillBase("mtp_moveit", options) {}
private:
std::string requiredActionController() override {
return "joint_trajectory_controller";
}
void executeAction() override {
RCLCPP_INFO(this->get_logger(), "Executing action goal");
moveit::planning_interface::MoveGroupInterface move_group_interface(
this->shared_from_this(), m_current_goal->robot_name);
move_group_interface.startStateMonitor();
move_group_interface.setPoseTarget(m_current_goal->target_pose);
move_group_interface.setMaxVelocityScalingFactor(
m_current_goal->end_effector_velocity);
move_group_interface.setMaxAccelerationScalingFactor(
m_current_goal->end_effector_acceleration);
moveit::planning_interface::MoveGroupInterface::Plan plan;
moveit::core::MoveItErrorCode plan_err_code =
move_group_interface.plan(plan);
if (plan_err_code == moveit::core::MoveItErrorCode::INVALID_MOTION_PLAN) {
move_group_interface.plan(plan);
}
if (plan_err_code == moveit::core::MoveItErrorCode::SUCCESS) {
RCLCPP_INFO(this->get_logger(), "Planning success");
// move_group_interface.execute(plan);
moveit::core::MoveItErrorCode move_err_code =
move_group_interface.execute(plan);
if (move_err_code == moveit::core::MoveItErrorCode::SUCCESS) {
m_current_result->success = true;
m_current_goal_handle->succeed(m_current_result);
RCLCPP_INFO(this->get_logger(), "Successfully executed action goal");
} else if (move_err_code == moveit::core::MoveItErrorCode::FAILURE) {
RCLCPP_ERROR(this->get_logger(), "Failure in move:");
}
} else {
RCLCPP_WARN_STREAM(this->get_logger(),
"Failed to generate plan because "
<< error_code_to_string(plan_err_code));
m_current_goal_handle->abort(m_current_result);
}
if (m_current_goal_handle->is_canceling()) {
m_current_goal_handle->canceled(m_current_result);
RCLCPP_ERROR(this->get_logger(), "Action goal canceled");
return;
}
}
}; // class MoveToPoseActionServer
} // namespace rbs_skill_actions
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(rbs_skill_actions::MoveitMtp);

View file

@ -0,0 +1,95 @@
#include "moveit/move_group_interface/move_group_interface.h"
#include "rbs_skill_interfaces/action/moveit_send_pose.hpp"
#include "rbs_skill_servers/base_skill.hpp"
#include <moveit/robot_trajectory/robot_trajectory.h>
#include <moveit/trajectory_processing/time_optimal_trajectory_generation.h>
#include <rclcpp/logging.hpp>
namespace rbs_skill_actions {
using MoveitSendPose = rbs_skill_interfaces::action::MoveitSendPose;
class MoveitMtpCart : public SkillBase<MoveitSendPose> {
public:
explicit MoveitMtpCart(const rclcpp::NodeOptions &options = rclcpp::NodeOptions())
: SkillBase("mtp_moveit_cart", options) {}
private:
std::string requiredActionController() override {
return "joint_trajectory_controller";
}
void executeAction() override {
RCLCPP_INFO(this->get_logger(), "Executing action goal");
moveit::planning_interface::MoveGroupInterface move_group_interface(
this->shared_from_this(), m_current_goal->robot_name);
move_group_interface.startStateMonitor();
moveit::core::RobotState start_state(
*move_group_interface.getCurrentState());
std::vector<geometry_msgs::msg::Pose> waypoints;
auto current_pose = move_group_interface.getCurrentPose();
geometry_msgs::msg::Pose target_pose = m_current_goal->target_pose;
waypoints.push_back(target_pose);
RCLCPP_INFO(this->get_logger(), "New cartesian target pose [%f, %f, %f]",
target_pose.position.x, target_pose.position.y,
target_pose.position.z);
moveit_msgs::msg::RobotTrajectory trajectory;
const double jump_threshold = 0.0;
const double eef_step = 0.001;
double fraction = move_group_interface.computeCartesianPath(
waypoints, eef_step, jump_threshold, trajectory);
robot_trajectory::RobotTrajectory rt(
move_group_interface.getCurrentState()->getRobotModel(),
m_current_goal->robot_name);
rt.setRobotTrajectoryMsg(*move_group_interface.getCurrentState(), trajectory);
trajectory_processing::TimeOptimalTrajectoryGeneration tp;
bool su = tp.computeTimeStamps(rt);
if (!su) {
RCLCPP_ERROR(this->get_logger(), "Failed to compute timestamp of trajectory");
m_current_goal_handle->abort(m_current_result);
}
rt.getRobotTrajectoryMsg(trajectory);
moveit::planning_interface::MoveGroupInterface::Plan plan;
plan.trajectory_ = trajectory;
if (fraction > 0) {
RCLCPP_INFO(this->get_logger(), "Planning success");
moveit::core::MoveItErrorCode execute_err_code =
move_group_interface.execute(plan);
if (execute_err_code == moveit::core::MoveItErrorCode::SUCCESS) {
m_current_result->success = true;
m_current_goal_handle->succeed(m_current_result);
RCLCPP_INFO(this->get_logger(), "Successfully executed action goal");
} else if (execute_err_code == moveit::core::MoveItErrorCode::FAILURE) {
RCLCPP_ERROR(this->get_logger(), "Failure in move:");
}
// move_group_interface.move();
} else {
RCLCPP_WARN(this->get_logger(), "Failed to generate plan");
m_current_goal_handle->abort(m_current_result);
}
if (m_current_goal_handle->is_canceling()) {
m_current_goal_handle->canceled(m_current_result);
RCLCPP_ERROR(this->get_logger(), "Action goal canceled");
return;
}
}
}; // class MoveToPoseActionServer
} // namespace rbs_skill_actions
#include "rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(rbs_skill_actions::MoveitMtpCart);

View file

@ -1,3 +1,4 @@
// FIXME: This code currently not used
#include <functional>
#include <geometry_msgs/msg/detail/pose_stamped__struct.hpp>
#include <geometry_msgs/msg/detail/transform_stamped__struct.hpp>

View file

@ -21,7 +21,7 @@
<depend>rbs_utils_interfaces</depend>
<depend>dynmsg</depend>
<depend>sensor_msgs</depend>
<depend>nlohmann_json</depend>
<depend>nlohmann-json-dev</depend>
<depend>rosbag2_cpp</depend>
<test_depend>ament_lint_auto</test_depend>

37
repos/all-deps.repos Normal file
View file

@ -0,0 +1,37 @@
repositories:
rbs_arm:
type: git
url: https://github.com/solid-sinusoid/rbs-arm.git
version: main
robot_builder:
type: git
url: https://github.com/solid-sinusoid/robot-builder.git
version: main
rbs_gripper:
type: git
url: https://github.com/solid-sinusoid/rbs-gripper.git
version: main
behavior_tree:
type: git
url: https://github.com/BehaviorTree/BehaviorTree.ROS2.git
version: humble
dynamic_message_introspection:
type: git
url: https://github.com/osrf/dynamic_message_introspection.git
version: main
robot_builder:
type: git
url: https://github.com/solid-sinusoid/robot-builder.git
version: main
cartesian_controllers:
type: git
url: https://github.com/solid-sinusoid/cartesian_controllers.git
version: gazebo-simulation
ros2_control:
type: git
url: https://github.com/solid-sinusoid/ros2_control.git
version: gz-ros2-cartesian-controllers
gz_ros2_control:
type: git
url: https://github.com/solid-sinusoid/gz_ros2_control.git
version: fts-sensor

29
repos/requirements.txt Normal file
View file

@ -0,0 +1,29 @@
trimesh
pcg-gazebo
loguru
# markupsafe==2.0.1
# Jinja2==2.6
numpy==1.24.0
flask==3.0.3
Jinja2>=3.1.2
docutils<0.18,>=0.15
markdown-it-py<3.0.0,>=1.0.0
# setuptools-scm
dacite>=1.8.1
gymnasium==0.29.1
numpy>=1.24.0
open3d>=0.18.0
scipy>=1.14.1
tensorflow>=2.17.0
torch>=2.4.1
torchvision>=0.19.1
trimesh>=4.4.9
wandb>=0.18.6
# Packages from devpi custom repository
scenario @ https://devpi.solid-sinusoid.duckdns.org/narmak/dev/+f/63e/86b0583c22e52/scenario-1.4.0-cp310-cp310-linux_x86_64.whl#sha256=63e86b0583c22e52c299b9a25e74a26178fc7dbc423f661bf34e4dd26543d11f
gym-gz @ https://devpi.solid-sinusoid.duckdns.org/narmak/dev/+f/539/1f448c1391486/gym_gz-1.4.0-py3-none-any.whl#sha256=5391f448c13914860e2a65904f6d0fac7eba71daaa3327d8399d7ae516471a68
gym-gz-models @ https://devpi.solid-sinusoid.duckdns.org/narmak/dev/+f/f42/4784934183e88/gym_gz_models-1.2.0-cp310-cp310-linux_x86_64.whl#sha256=f424784934183e88541c703c789315ba6118661bd221a4bf9135c6a0ee012e96
rbs_asstss_library @ https://devpi.solid-sinusoid.duckdns.org/narmak/dev/+f/165/dd2476d9dc455/rbs_assets_library-0.1.0-py2.py3-none-any.whl#sha256=165dd2476d9dc455b425a8c8d3e09a9a9541d54c1f900a3a0e63526c6118de6d