first commit
BIN
04-Конкурсное-задание (17) (1).pdf
Normal file
230
README.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# Модуль В. Система технического зрения с использованием инструментов ИИ
|
||||
|
||||
## Описание задачи
|
||||
|
||||
На специальной полке на соревновательном поле расположены N > 3 коробок с рисунками инструментов. РМК-1 с манипулятором смотрит на полку сверху (камера на манипуляторе направлена вертикально вниз). Эксперт с помощью генератора случайных чисел выбирает целевую деталь. Алгоритм должен:
|
||||
|
||||
1. Распознать все коробки в кадре камеры
|
||||
2. Определить координаты целевой коробки относительно базы манипулятора (Base_link)
|
||||
3. Направить манипулятор к коробке, схватить её и поднять в стартовое положение
|
||||
4. Опустить коробку на свободное место на полке
|
||||
|
||||
## Классы объектов
|
||||
|
||||
| ID | Название | Описание |
|
||||
|----|----------|----------|
|
||||
| 1 | Молоток (hammer) | Коробка с изображением молотка |
|
||||
| 2 | Гаечный ключ (wrench) | Коробка с изображением гаечного ключа |
|
||||
| 3 | Пассатижи (pliers) | Коробка с изображением пассатижей |
|
||||
|
||||
## Архитектура решения
|
||||
|
||||
- **Модель**: YOLOv8n-cls (nano classification) — легковесная модель для классификации изображений
|
||||
- **Фреймворк**: Ultralytics / PyTorch
|
||||
- **Размер входа**: 224x224 px
|
||||
- **Размер модели**: ~5.3 MB (PyTorch), ~5.5 MB (ONNX)
|
||||
- **Скорость инференса**: ~1.6 мс на CPU
|
||||
|
||||
### Пайплайн обработки кадра
|
||||
|
||||
```
|
||||
Кадр с камеры манипулятора
|
||||
|
|
||||
v
|
||||
Сегментация коробок (OpenCV: пороговая фильтрация + контурный анализ)
|
||||
|
|
||||
v
|
||||
Классификация каждой коробки (YOLOv8n-cls)
|
||||
|
|
||||
v
|
||||
Поиск целевой коробки (по ID класса + порог уверенности > 0.7)
|
||||
|
|
||||
v
|
||||
Пересчёт пиксельных координат в координаты Base_link
|
||||
|
|
||||
v
|
||||
Отправка координат манипулятору (MoveIt2 API)
|
||||
```
|
||||
|
||||
## Структура файлов
|
||||
|
||||
```
|
||||
module_v/
|
||||
├── images/ # Исходные изображения инструментов
|
||||
│ ├── Hammer.jpg
|
||||
│ ├── Wrench.jpg
|
||||
│ └── Pliers.jpg
|
||||
├── dataset/ # Сгенерированный датасет
|
||||
│ ├── train/ # 900 изображений (300 на класс)
|
||||
│ │ ├── hammer/
|
||||
│ │ ├── wrench/
|
||||
│ │ └── pliers/
|
||||
│ └── val/ # 180 изображений (60 на класс)
|
||||
│ ├── hammer/
|
||||
│ ├── wrench/
|
||||
│ └── pliers/
|
||||
├── runs/module_v_cls/weights/ # Результаты обучения
|
||||
│ ├── best.pt
|
||||
│ └── best.onnx
|
||||
├── best.pt # Обученная модель (копия)
|
||||
├── generate_dataset.py # Скрипт генерации датасета
|
||||
├── train_model.py # Скрипт обучения модели
|
||||
├── detect_box.py # Основной скрипт инференса + ROS2
|
||||
├── test_detect.py # Тестовый скрипт с визуализацией
|
||||
├── README.md # Общая инструкция по симулятору
|
||||
└── README_MODULE_V.md # Данный файл
|
||||
```
|
||||
|
||||
## Установка зависимостей
|
||||
|
||||
```bash
|
||||
pip install ultralytics opencv-python-headless Pillow albumentations
|
||||
```
|
||||
|
||||
## Генерация датасета
|
||||
|
||||
Датасет генерируется из 3 исходных изображений с помощью аугментаций:
|
||||
- Композитинг инструментов на различные фоны (имитация полки)
|
||||
- Повороты, отражения, перспективные искажения
|
||||
- Изменение яркости, контраста, насыщенности
|
||||
- Размытие, шум, JPEG-компрессия
|
||||
|
||||
```bash
|
||||
python3 generate_dataset.py
|
||||
```
|
||||
|
||||
Результат: 900 train + 180 val изображений (по 300/60 на класс).
|
||||
|
||||
## Обучение модели
|
||||
|
||||
```bash
|
||||
python3 train_model.py
|
||||
```
|
||||
|
||||
Параметры обучения:
|
||||
- Базовая модель: `yolov8n-cls.pt` (предобученная на ImageNet)
|
||||
- Эпохи: до 80 (с early stopping, patience=15)
|
||||
- Размер изображения: 224x224
|
||||
- Batch size: 32
|
||||
|
||||
Результат: **100% top-1 accuracy** на валидации.
|
||||
|
||||
Модель автоматически экспортируется в ONNX формат.
|
||||
|
||||
## Запуск
|
||||
|
||||
### Тест на отдельном изображении
|
||||
|
||||
```bash
|
||||
python3 detect_box.py --target 1 --image path/to/image.jpg
|
||||
```
|
||||
|
||||
Где `--target` — ID целевой детали (1=молоток, 2=ключ, 3=пассатижи).
|
||||
|
||||
### Тест на всех исходных изображениях
|
||||
|
||||
```bash
|
||||
python3 detect_box.py --target 2
|
||||
```
|
||||
|
||||
### Тест с визуализацией на кадре с камеры
|
||||
|
||||
```bash
|
||||
python3 test_detect.py
|
||||
```
|
||||
|
||||
Результат сохраняется в `test_result.png` с аннотированными рамками и подписями классов.
|
||||
|
||||
### Запуск в режиме ROS2
|
||||
|
||||
Предварительно запустите симуляцию модуля В:
|
||||
|
||||
```bash
|
||||
# Терминал 1: запуск симулятора
|
||||
ros2 launch ar_webots_fms_ros2 module3.launch.py
|
||||
|
||||
# Терминал 2: запуск детектора (указать целевую деталь)
|
||||
python3 detect_box.py --target 1 --ros
|
||||
```
|
||||
|
||||
Скрипт подписывается на топик `/RMC1/arm95/camera_gripper/image_color`, распознаёт коробки и выводит координаты целевой коробки относительно Base_link.
|
||||
|
||||
## Результаты тестирования
|
||||
|
||||
### На исходных изображениях
|
||||
|
||||
| Изображение | Предсказание | Уверенность |
|
||||
|-------------|-------------|-------------|
|
||||
| Hammer.jpg | hammer (молоток) | 99.98% |
|
||||
| Wrench.jpg | wrench (гаечный ключ) | 99.99% |
|
||||
| Pliers.jpg | pliers (пассатижи) | 100.00% |
|
||||
|
||||
### На тестовом кадре с камеры (test.png)
|
||||
|
||||
5 коробок на полке (молоток, ключ, 2 пассатижей + объект на краю):
|
||||
|
||||
| Коробка | Класс | Уверенность |
|
||||
|---------|-------|-------------|
|
||||
| Box 1 | wrench | 99.51% |
|
||||
| Box 2 | pliers | 100.00% |
|
||||
| Box 3 | wrench | 65.81% (край кадра, фильтруется порогом) |
|
||||
| Box 4 | hammer | 79.42% |
|
||||
| Box 5 | pliers | 99.93% |
|
||||
|
||||
Рекомендуемый порог уверенности для фильтрации: **> 0.7**
|
||||
|
||||
## Интеграция с манипулятором
|
||||
|
||||
Пример полного цикла (распознавание + захват):
|
||||
|
||||
```python
|
||||
import rclpy
|
||||
from detect_box import load_model, find_target_box, pixel_to_base_link
|
||||
from geometry_msgs.msg import PoseStamped
|
||||
from tf_transformations import quaternion_from_euler
|
||||
from moveit.planning import MoveItPy
|
||||
|
||||
# Инициализация
|
||||
rclpy.init()
|
||||
model = load_model("best.pt")
|
||||
arm95 = MoveItPy(node_name="moveit_py", name_space="/RMC1/arm95")
|
||||
arm95_arm = arm95.get_planning_component("arm95_group")
|
||||
gripper = arm95.get_planning_component("gripper")
|
||||
|
||||
# 1. Получить кадр с камеры (через ROS2 subscriber)
|
||||
# frame = ... (cv2 image from /RMC1/arm95/camera_gripper/image_color)
|
||||
|
||||
# 2. Найти целевую коробку
|
||||
target_id = 1 # молоток
|
||||
result = find_target_box(model, frame, target_id)
|
||||
if result:
|
||||
cx, cy, conf, bbox = result
|
||||
h, w = frame.shape[:2]
|
||||
wx, wy, wz = pixel_to_base_link(cx, cy, w, h)
|
||||
|
||||
# 3. Переместить манипулятор к коробке
|
||||
q = quaternion_from_euler(3.14, 0.0, 1.57)
|
||||
pose_goal = PoseStamped()
|
||||
pose_goal.header.frame_id = "Base_link"
|
||||
pose_goal.pose.orientation.x = q[0]
|
||||
pose_goal.pose.orientation.y = q[1]
|
||||
pose_goal.pose.orientation.z = q[2]
|
||||
pose_goal.pose.orientation.w = q[3]
|
||||
pose_goal.pose.position.x = wx
|
||||
pose_goal.pose.position.y = wy
|
||||
pose_goal.pose.position.z = 0.3 # высота над коробкой
|
||||
|
||||
arm95_arm.set_start_state_to_current_state()
|
||||
arm95_arm.set_goal_state(pose_stamped_msg=pose_goal, pose_link="gripper_base")
|
||||
plan_result = arm95_arm.plan()
|
||||
if plan_result:
|
||||
arm95.execute(plan_result.trajectory, controllers=[])
|
||||
|
||||
# 4. Захватить коробку
|
||||
gripper.set_goal_state(configuration_name="closed")
|
||||
plan_result = gripper.plan()
|
||||
if plan_result:
|
||||
arm95.execute(plan_result.trajectory, controllers=[])
|
||||
```
|
||||
|
||||
**Важно**: координаты `pixel_to_base_link()` требуют калибровки параметров камеры (FOV, высота) под конкретную установку.
|
||||
540
README_bots.md
Normal file
@@ -0,0 +1,540 @@
|
||||
# Требования
|
||||
## Требования к устройству
|
||||
* Процессор - 4 и более ядер
|
||||
* Оперативная память - 8 ГБ и более
|
||||
* Графика - Минимально: любая интегрированная графика (Intel HD * Graphics, AMD Radeon Vega), поддерживающая OpenGL 3.3. Чем мощнее, тем лучше
|
||||
* Место на диске - 50 ГБ или более
|
||||
## Требования к системе
|
||||
* Операционная система - Ubuntu 24.04 LTS Desktop (64 bit)
|
||||
|
||||
Рекомендуется установить на устройство отдельной системой в режиме dualboot или использовать виртуальную машину для установки. В случае виртуальной машины, важно выделить ей минимальные требуемые ресурсы на вашем устройстве из списка выше. Производительность в виртуальной машине может быть ниже, чем при нативной установке.
|
||||
|
||||
# Установка
|
||||
### 1. Установка ROS2 Jazzy:
|
||||
Данная инструкция дублирует команды из [официальной документации ROS2](https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debs.html) по установке.
|
||||
|
||||
Подготавливаем систему к установке
|
||||
``` bash
|
||||
sudo apt update && sudo apt install locales
|
||||
sudo locale-gen en_US en_US.UTF-8
|
||||
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
|
||||
export LANG=en_US.UTF-8
|
||||
```
|
||||
|
||||
Устанавливаем зависимости
|
||||
``` bash
|
||||
sudo apt install software-properties-common
|
||||
sudo add-apt-repository universe
|
||||
```
|
||||
``` bash
|
||||
sudo apt update && sudo apt install curl -y
|
||||
export ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F\" '{print $4}')
|
||||
curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}})_all.deb"
|
||||
sudo dpkg -i /tmp/ros2-apt-source.deb
|
||||
```
|
||||
|
||||
Устанавливаем полную версию ROS2 Jazzy
|
||||
``` bash
|
||||
sudo apt install ros-jazzy-desctop-full
|
||||
```
|
||||
|
||||
(Опционально) Можно добавить сурс (source) команду для ROS2 в ```~/.bashrc```, чтобы не нужно каждый раз в новом терминале вводить ```source /opt/ros/jazzy/setup.bash```
|
||||
``` bash
|
||||
echo 'source /opt/ros/jazzy/setup.bash' >> ~/.bashrc
|
||||
```
|
||||
|
||||
Устанавливаем инструмент сборки colcon
|
||||
``` bash
|
||||
sudo apt install python3-colcon-common-extensions
|
||||
```
|
||||
|
||||
### 2. Установка симулятора Webots:
|
||||
|
||||
Данная инструкция дублирует команды из [официальной документации Webots](https://cyberbotics.com/doc/guide/installation-procedure#installing-the-debian-package-with-the-advanced-packaging-tool-apt) по установке.
|
||||
|
||||
Устанавливаем файл подписи Cyberbotics
|
||||
```bash
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
|
||||
cd /etc/apt/keyrings
|
||||
|
||||
sudo wget -q https://cyberbotics.com/Cyberbotics.asc
|
||||
```
|
||||
|
||||
Конфигурируем менеджер пакетов
|
||||
```bash
|
||||
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/Cyberbotics.asc] https://cyberbotics.com/debian binary-amd64/" | sudo tee /etc/apt/sources.list.d/Cyberbotics.list
|
||||
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
Устанаваливаем Webots
|
||||
```bash
|
||||
sudo apt install webots
|
||||
```
|
||||
|
||||
Настраиваем переменную окружения
|
||||
```bash
|
||||
echo "export WEBOTS_HOME=/snap/webots/current/usr/share/webots" >> ~/.bashrc
|
||||
```
|
||||
|
||||
### 3. Установка ROS2 пакетов симулятора
|
||||
|
||||
Создаем папку рабочего пространства с любым именем в домашней директории, в данном примере используем папку `ros2_ws`
|
||||
```bash
|
||||
mkdir ~/ros2_ws/src -p
|
||||
```
|
||||
|
||||
Скачиваем требуемые пакеты
|
||||
```bash
|
||||
cd ~/ros2_ws/src
|
||||
|
||||
git clone https://gitlab.mobird.dev/fms_group/ar_webots_fms_ros2.git
|
||||
|
||||
git clone https://gitlab.mobird.dev/fms_group/ar_arm95_moveit_config.git
|
||||
|
||||
git clone https://gitlab.mobird.dev/fms_group/ar_aruco_detect_ros2.git
|
||||
|
||||
git clone https://gitlab.mobird.dev/fms_group/ar_dual_lidar_merge_ros2.git
|
||||
|
||||
git clone https://gitlab.mobird.dev/fms_group/ar_nav_ros2.git
|
||||
```
|
||||
|
||||
Устанавливаем зависимости через инструмент rosdep
|
||||
```bash
|
||||
cd ~/ros2_ws
|
||||
|
||||
sudo rosdep init
|
||||
rosdep update
|
||||
rosdep install --from-paths src -y --ignore-src
|
||||
```
|
||||
|
||||
Собираем пакеты
|
||||
|
||||
```bash
|
||||
cd ~/ros2_ws
|
||||
colcon build --symlink-install
|
||||
```
|
||||
Перед запуском симулятора необходимо выполнить сурс (source) собранных файлов из папки `ros2_ws`, **это необходимо делать в каждом новом открытом терминале**
|
||||
```bash
|
||||
source /ros2_ws/install/setup.bash
|
||||
```
|
||||
|
||||
(Опционально) данный сурс можно также добавить в ```~/.bashrc```
|
||||
|
||||
### 4. Установка пакетов навигации и slam для RMC1
|
||||
Создайте отдельное рабочее пространство для пакетов навигации, в данном примере это будет `nav2_ws`. Клонируем в него файлы Nav2.
|
||||
```bash
|
||||
mkdir ~/nav2_ws/src -p
|
||||
git clone https://github.com/ros-planning/navigation2.git -b 1.3.10
|
||||
```
|
||||
Устанавливаем зависимости через инструмент rosdep
|
||||
```bash
|
||||
cd ~/nav2_ws
|
||||
|
||||
sudo rosdep init
|
||||
rosdep update
|
||||
rosdep install -y -r -q --from-paths src --ignore-src --rosdistro jazzy
|
||||
```
|
||||
После этого собираем пакеты. Сборка может занять некоторое время, ~30 минут в зависимости от мощности ПК
|
||||
```bash
|
||||
cd ~/nav2_ws
|
||||
colcon build --symlink-install
|
||||
```
|
||||
Далее создаем новую папку, в данном примере это будет `slam_ws` и загружаем в нее файлы SLAM
|
||||
```bash
|
||||
mkdir ~/slam_ws/src -p
|
||||
git clone https://github.com/SteveMacenski/slam_toolbox.git -b 2.8.3
|
||||
```
|
||||
Устанавливаем зависимости через инструмент rosdep
|
||||
```bash
|
||||
cd ~/slam_ws
|
||||
|
||||
sudo rosdep init
|
||||
rosdep update
|
||||
rosdep install -y -r -q --from-paths src --ignore-src --rosdistro jazzy
|
||||
```
|
||||
После этого собираем пакеты. Сборка может занять некоторое время, ~5 минут в зависимости от мощности ПК
|
||||
```bash
|
||||
cd ~/slam_ws
|
||||
colcon build --symlink-install
|
||||
```
|
||||
Перед запуском симулятора необходимо выполнить сурс (source) собранных файлов из папок `nav2_ws` и `nav2_ws`, **это необходимо делать в каждом новом открытом терминале**
|
||||
```bash
|
||||
source /nav2_ws/install/setup.bash
|
||||
source /slam_ws/install/setup.bash
|
||||
```
|
||||
(Опционально) данный сурс можно также добавить в ```~/.bashrc```
|
||||
|
||||
# Запуск модулей
|
||||
## Модуль Б. Разработка и настройка навигационных алгоритмов для РМК
|
||||
```
|
||||
Задание:
|
||||
1) РМК-2 стоит на точке старта над стартовым aruco-маркером.
|
||||
Необходимо по команде старта эксперта отправить роботу целевую точку, в которую должен
|
||||
приехать РМК-2.
|
||||
2) После прибытия к целевой точке, РМК-2 должен вернуться в точку
|
||||
старта, однако в этот раз перед стартом робота эксперт выставит на маршрут
|
||||
робота препятствие, которое необходимо обнаружить и объехать.
|
||||
```
|
||||
|
||||
Чтобы запустить симуляцию данного задания, запустите launch файл:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_webots_fms_ros2 module2.launch.py
|
||||
```
|
||||
|
||||
При первом запуске мира могут долго скачиваться некоторые ассеты для карты, поэтому, если робот не появился, то перезапустите симулятор.
|
||||
|
||||
При успешном запуске в симуляторе должна быть такая картина:
|
||||

|
||||
|
||||
В окне симулятора будут также отображаться изображения с камер робота. Предупреждения (warning) в консоли симулятора можно игнорировать.
|
||||
|
||||
Для визуальной оценки данных, которые получают датчики робота RMC2, можно использовать программу Rviz2. В пакете есть готовый скрипт для запуска настроенного под робота окна Rviz2.
|
||||
|
||||
Для запуска откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_webots_fms_ros2 rviz_rmc2.launch.py
|
||||
```
|
||||
Откроется следующее окно:
|
||||

|
||||
|
||||
Красные и синие точки отображают данные переднего и заднего лидара соответственно. Белые точки - объедененный скан переднего и заднего лидара.
|
||||
|
||||
Слева снизу можно видеть изображение, которое передает камера, расположенная на дне робота. Поверх этого изображения также отрисовываются визуальные данные из Rviz2, которые попадают в поле зрения визуализируемой камеры. На скриншоте выше, например, видно, что камера "видит" некоторые оси координат робота. Но пусть вас не смущают эти визуализации, на самом изображении это все отсутствует.
|
||||
|
||||
Чтобы управлять роботом RMC2 в ручном режиме, можно запустить скрипт телеопераций, который позволит задавать скорость и направление робота через клавиатуру. Для запуска откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 run ar_nav_ros2 teleop --ros-args -r __ns:=/RMC2
|
||||
```
|
||||
|
||||
Перед вами появится инструкция с клавишами клавиатуры в следующем формате:
|
||||
|
||||
```txt
|
||||
Control Your Robot!
|
||||
---------------------------
|
||||
Moving around:
|
||||
q w e
|
||||
a s d
|
||||
x
|
||||
w/x : increase/decrease linear X velocity
|
||||
q/e : increase/decrease linear Y velocity
|
||||
a/d : increase/decrease angular velocity
|
||||
space key, s : force stop
|
||||
CTRL-C to quit
|
||||
```
|
||||
|
||||
Чтобы заспавнить препятствие на карте, воспользуйтесь launch файлом в новом терминале:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_webots_fms_ros2 spawn_object.launch.py x:=-4.0 y:=1.0 angle_z:=0.0 object_name:=obstacle
|
||||
```
|
||||
В качестве аргументов `x`,`y` и `angle_z` в виде чисел с плавающей точкой можно задать координаты и ориентацию объекта. Чтобы задать уникальное имя объекта, укажите его в виде аргумента `name`.
|
||||
|
||||
## Модуль В. Системы технического зрения с использованием инструментов искусственного интеллекта
|
||||
|
||||
```
|
||||
Этот модуль направлен на обучение и интеграцию нейросетевой модели для автоматического распознавания. Конкурсанты должны самостоятельно собрать и разметить датасет, выбрать подходящую архитектуру нейросети, обучить ее и интегрировать в систему управления манипулятором.
|
||||
|
||||
Задание:
|
||||
На специальной полке на соревновательном поле будут лежать N > 3 коробок. РМК-1 с манипулятором в стартовом положении около полки перпендикулярно ей (камера на манипуляторе смотрит вертикально вниз) смотрит на эту полку сверху.
|
||||
С помощью генератора случайных чисел эксперт выбирает деталь, необходимую для захвата манипулятором. Конкурсанты должны запустить свой разработанный алгоритм, указать целевую деталь (1 - молоток, 2 - гаечный ключ, 3 - пассатижи) и начать выполнение.
|
||||
РМК-1 должен автономно определить с помощью размеченного датасета, какая коробка его интересует, определить ее местоположение относительно базы манипулятора, направить манипулятор в нужную точку, схватить коробку схватом и поднять в стартовое положение.
|
||||
После этого опустить коробку на пустое место на этой же полке.
|
||||
```
|
||||
|
||||
Чтобы запустить симуляцию данного задания, запустите launch файл:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_webots_fms_ros2 module3.launch.py
|
||||
```
|
||||
|
||||
При первом запуске мира могут долго скачиваться некоторые ассеты для карты, поэтому, если робот не появился, то перезапустите симулятор.
|
||||
|
||||
При успешном запуске в симуляторе должна быть такая картина:
|
||||

|
||||
|
||||
Предупреждения (warning) в консоли симулятора можно игнорировать.
|
||||
|
||||
Для визуальной оценки данных, которые получают датчики робота RMC1, можно использовать программу Rviz2. В пакете есть готовый скрипт для запуска настроенного под робота окна Rviz2.
|
||||
|
||||
Для запуска откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_webots_fms_ros2 rviz_rmc1.launch.py
|
||||
```
|
||||
|
||||
Откроется следующее окно:
|
||||

|
||||
|
||||
Данные для обучения нейросети можно собрать, перемещая камеру и объекты в симуляторе и делая скриншоты.
|
||||
|
||||
Красные и синие точки отображают данные переднего и заднего лидара соответственно. Белые точки - объедененный скан переднего и заднего лидара.
|
||||
|
||||
Слева снизу можно видеть изображение, которое передает камера, расположенная на захвате манипулятора. Поверх этого изображения также отрисовываются визуальные данные из Rviz2, которые попадают в поле зрения визуализируемой камеры. На скриншоте выше, например, видно, что камера "видит" некоторые оси координат робота. Но пусть вас не смущают эти визуализации, на самом изображении это все отсутствует.
|
||||
|
||||
Чтобы управлять роботом RMC1 в ручном режиме, можно запустить скрипт телеопераций, который позволит задавать скорость и направление робота через клавиатуру. Для запуска откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 run ar_nav_ros2 teleop --ros-args -r __ns:=/RMC1
|
||||
```
|
||||
|
||||
Перед вами появится инструкция с клавишами клавиатуры в следующем формате:
|
||||
|
||||
```txt
|
||||
Control Your Robot!
|
||||
---------------------------
|
||||
Moving around:
|
||||
q w e
|
||||
a s d
|
||||
x
|
||||
w/x : increase/decrease linear X velocity
|
||||
q/e : increase/decrease linear Y velocity
|
||||
a/d : increase/decrease angular velocity
|
||||
space key, s : force stop
|
||||
CTRL-C to quit
|
||||
```
|
||||
|
||||
Чтобы запустить готовый пакет навигации Nav2, откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_nav_ros2 bringup_launch.py
|
||||
```
|
||||
Запуск может занять около 15 секунд.
|
||||
|
||||
После того, как стек навигации успешно запуститься, можно воспользоваться визуализацией Rviz2. Для запуска откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_nav_ros2 rviz.launch.py
|
||||
```
|
||||
Откроется следующее окно:
|
||||

|
||||
|
||||
В данном окне отображается 2D карта поля, показания лидара, локальная и глобальная карты занятости, границы робота и его траектории во время движения. Первоначально роботу необходимо задать начальную позицию, если его позиция на карте отличается от реальной. Для этого в верхней панели выберите инструмент `2D Pose Estimate`, кликните им в нужную точку и задайте ориентацию с помощью стрелки.
|
||||
|
||||
Чтобы задать целевую точку, выберите инструмент `2D Goal Pose`, кликните им в нужную точку и задайте ориентацию с помощью стрелки. Робот начнет движение по отрисованной траектории.
|
||||
|
||||
Для визуальной отладки манипулятора Arm95 и его управления через графический интерфейс, есть еще один готовый конфиг для Rviz2. Для запуска откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_webots_fms_ros2 rviz_arm95.launch.py
|
||||
```
|
||||
|
||||
Откроется следующее окно:
|
||||

|
||||
|
||||
Для ручного управления манипулятором в поле `Planning Group` выбираем *arm95_group*.
|
||||
|
||||
Теперь в визуализации можно потянуть за стрелки или за голубую сферу и задать конечное положение манипулятора.
|
||||
Чтобы переместить манипулятор в заданное положение нажимаем кнопку `Plan`, затем `Execute`. Либо одной кнопкой сразу: `Plan & Execute`. Если удалось построить траекторию в заданну. точку, манипулятор должен переместиться. Можно проверить это в симуляторе Webots.
|
||||
|
||||
Для ручного управления схватом в поле `Planning Group` выбираем *gripper*.
|
||||
Затем в поле `Goal State` выбираем `open` или `close` и затем нажимаем `Plan & Execute`.
|
||||
|
||||
## Модуль Д. Решение складского кейса гетерогенной группой РМК
|
||||
|
||||
```
|
||||
Конкурсанты должны обеспечить взаимодействие РМК-1 (оснащенного
|
||||
манипулятором) и РМК-2 (оснащенного подъемным механизмом) для
|
||||
выполнения последовательных (или параллельных) операций по
|
||||
транспортировке стеллажа и комплектации заказа
|
||||
|
||||
Задание:
|
||||
|
||||
1) РМК-2 выполняет транспортировку стеллажа из точки хранения в
|
||||
точку комплектации.
|
||||
2) РМК-1 выполняет операцию комплектации (picking) требуемой
|
||||
детали со стеллажа.
|
||||
3) РМК-1 доставляет деталь в точку сдачи.
|
||||
4) РМК-2 выполняет транспортировку стеллажа из точки комплектации
|
||||
в точку хранения.
|
||||
5) Оба РМК возвращаются в исходные позиции
|
||||
```
|
||||
|
||||
Чтобы запустить симуляцию данного задания, запустите launch файл:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_webots_fms_ros2 module5.launch.py
|
||||
```
|
||||
|
||||
При первом запуске мира могут долго скачиваться некоторые ассеты для карты, поэтому, если робот не появился, то перезапустите симулятор.
|
||||
|
||||
При успешном запуске в симуляторе должна быть такая картина:
|
||||

|
||||
|
||||
Предупреждения (warning) в консоли симулятора можно игнорировать.
|
||||
|
||||
Далее запустите пакеты наыигации Nav2, откройте новый терминал и выполните:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
ros2 launch ar_nav_ros2 bringup_launch.py
|
||||
```
|
||||
|
||||
В этом модуле можно использовать все предыдущие конфиги Rviz2 под каждого робота:
|
||||
**Не забудьте выполнить сурсы (source), если они не добавлены в ваш ~/.bashrc**
|
||||
```bash
|
||||
# Для RMC1
|
||||
ros2 launch ar_webots_fms_ros2 rviz_rmc1.launch.py
|
||||
|
||||
# Для манипулятора ARM95
|
||||
ros2 launch ar_webots_fms_ros2 rviz_arm95.launch.py
|
||||
|
||||
# Для RMC2
|
||||
ros2 launch ar_webots_fms_ros2 rviz_rmc2.launch.py
|
||||
|
||||
# Для Nav2
|
||||
ros2 launch ar_nav_ros2 rviz.launch.py
|
||||
```
|
||||
|
||||
# Управление
|
||||
|
||||
## Робот RMC1
|
||||
### Топики ROS2
|
||||
Робот RMC1 использует имя `RMC1` в поле `namespace` топиков ROS2. Ниже приведен список доступных топиков для взаимодействия:
|
||||
* `/RMC1/odometry` [nav_msgs/msg/Odometry] - положение робота по колесной одометрии
|
||||
* `/RMC1/scan` [sensor_msgs/msg/LaserScan] - объединенный скан переднего и заднего лидара
|
||||
* `/RMC1/scan_back` [sensor_msgs/msg/LaserScan] - скан заднего лидара
|
||||
publisher
|
||||
* `/RMC1/scan_front` [sensor_msgs/msg/LaserScan] - скан переднего лидара
|
||||
* `/RMC1/cmd_vel` [geometry_msgs/msg/Twist] - целевая скорость платформы
|
||||
* `/tf_static` [tf2_msgs/msg/TFMessage] - дерево статических преобразований между деталями робота
|
||||
* `/tf` [tf2_msgs/msg/TFMessage] - дерево динамическиз преобразований между роботом и миром
|
||||
* `/RMC1/arm95/camera_gripper/image_color` [sensor_msgs/msg/Image] - изображение с камеры манипулятора
|
||||
|
||||
### Управление манипулятором
|
||||
Чтобы управлять манипулятором, используйте файл с примером из пакета `ar_webots_ros2/ar_webots_ros2/moveit_api_example.py`, его содержимое приведено ниже:
|
||||
``` python3
|
||||
import time
|
||||
import rclpy
|
||||
from rclpy.logging import get_logger
|
||||
from geometry_msgs.msg import PoseStamped
|
||||
from tf_transformations import quaternion_from_euler
|
||||
|
||||
# moveit python library
|
||||
from moveit.planning import MoveItPy
|
||||
|
||||
def plan_and_execute(robot, planning_component, logger, sleep_time=0.0):
|
||||
plan_result = planning_component.plan()
|
||||
if plan_result:
|
||||
logger.info("Executing plan")
|
||||
robot_trajectory = plan_result.trajectory
|
||||
robot.execute(robot_trajectory, controllers=[])
|
||||
else:
|
||||
logger.error("Planning failed")
|
||||
time.sleep(sleep_time)
|
||||
|
||||
def main():
|
||||
rclpy.init()
|
||||
# Инициализация объектов MoveItPy
|
||||
arm95 = MoveItPy(node_name="moveit_py", name_space="/RMC1/arm95")
|
||||
arm95_arm = arm95.get_planning_component("arm95_group") # Объект - манипулятор
|
||||
gripper = arm95.get_planning_component("gripper") # Объект - захват
|
||||
|
||||
# Пример открытия захвата
|
||||
gripper.set_goal_state(configuration_name="open")
|
||||
plan_and_execute(arm95, gripper, logger, sleep_time=0.0)
|
||||
|
||||
# Пример закрытия захвата
|
||||
gripper.set_goal_state(configuration_name="closed")
|
||||
plan_and_execute(arm95, gripper, logger, sleep_time=0.0)
|
||||
|
||||
# Задать текущее положение манипулятора как начальное
|
||||
arm95_arm.set_start_state_to_current_state()
|
||||
|
||||
# Целевая ориентация схвата в углах Эйлера относительно основания "Base_link"
|
||||
# Задается в виде roll, pitch, yaw
|
||||
# Ориентация из углов Эцлера переводится в кватернион
|
||||
q = quaternion_from_euler(3.14, 0.0, 1.57)
|
||||
|
||||
# Задать целевую позицию в формате PoseStamped сообщения
|
||||
pose_goal = PoseStamped()
|
||||
pose_goal.header.frame_id = "Base_link" # Движение относительно основания манипулятора
|
||||
pose_goal.pose.orientation.x = q[0] # Ориентация робота задается через кватернион
|
||||
pose_goal.pose.orientation.y = q[1] # Ориентация робота задается через кватернион
|
||||
pose_goal.pose.orientation.z = q[2] # Ориентация робота задается через кватернион
|
||||
pose_goal.pose.orientation.w = q[3] # Ориентация робота задается через кватернион
|
||||
pose_goal.pose.position.x = -0.2 # Координата x захвата относительно основания "Base_link"
|
||||
pose_goal.pose.position.y = -0.5 # Координата y захвата относительно основания "Base_link"
|
||||
pose_goal.pose.position.z = 0.7 # Координата z захвата относительно основания "Base_link"
|
||||
arm95_arm.set_goal_state(pose_stamped_msg=pose_goal, pose_link="gripper_base") # Задается тип движения по заданной позиции
|
||||
plan_and_execute(arm95, arm95_arm, logger, sleep_time=0.0) # Запуск перемещения в заданную позицию
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
Запускать данный файл необходимо через `ar_webots_ros2/launch/moveit_api_example.launch.py` файл, в котором в moveit контроллер передаются параметры манипулятоар и захвата.
|
||||
|
||||
### Управление навигацией Nav2
|
||||
Чтобы использовать навигацию Nav2, необходимо написать скрипт с использованием пакета `nav2_simple_commander`. Используйте его при запущенной навигации. Пример управляющего скрипта представлен ниже:
|
||||
``` python3
|
||||
from nav2_simple_commander.robot_navigator import BasicNavigator, TaskResult
|
||||
import rclpy
|
||||
|
||||
rclpy.init()
|
||||
nav = BasicNavigator() # Создание экземпляра контроллера
|
||||
|
||||
# ...
|
||||
|
||||
nav.setInitialPose(init_pose) # Задание исходной позиции в формате PoseStamped
|
||||
|
||||
# ...
|
||||
|
||||
path = nav.getPath(init_pose, goal_pose) # Построить маршрут из исходной точки в целевую (PoseStamped), проверка что путь существует
|
||||
|
||||
# ...
|
||||
|
||||
nav.goToPose(goal_pose) # Задать роботу цлевую позицию в формате PoseStamped
|
||||
while not nav.isTaskComplete(): # Цикл выполнения целевой точки, пока она не будет достигнута
|
||||
feedback = nav.getFeedback() # Информация о выполнении задачи
|
||||
if feedback.navigation_duration > 600: # Сравнение времени выполнения задачи с заданным временем
|
||||
nav.cancelTask() # Остановить выполнение целевой точки
|
||||
|
||||
# ...
|
||||
|
||||
result = nav.getResult() # Получение результата о выполнении задачи
|
||||
if result == TaskResult.SUCCEEDED:
|
||||
print('Goal succeeded!')
|
||||
elif result == TaskResult.CANCELED:
|
||||
print('Goal was canceled!')
|
||||
elif result == TaskResult.FAILED:
|
||||
print('Goal failed!')
|
||||
```
|
||||
|
||||
Для запуска достаточно создать экземпляр контроллера, задать начальную и целевую точки. Робот начнет двиижение.
|
||||
|
||||
Подробнее о работе с `nav2_simple_commander` можете уздать в [официальной документации](https://docs.nav2.org/commander_api/index.html).
|
||||
|
||||
## Робот RMC2
|
||||
### Топики ROS2
|
||||
Робот RMC2 использует имя `RMC2` в поле `namespace` топиков ROS2. Ниже приведен список доступных топиков для взаимодействия:
|
||||
* `/RMC2/aruco_id` [std_msgs/msg/String] - ID найденного нижней камерой ArUco маркера
|
||||
* `/RMC2/camera_bottom/image_color` [sensor_msgs/msg/Image] - изображение с нижней камеры (геометрический центр робота)
|
||||
* `/RMC2/depth_camera/image` [sensor_msgs/msg/Image] - изображение с передней камеры
|
||||
* `/RMC2/depth_camera/point_cloud` [sensor_msgs/msg/PointCloud2] - облако точек с передней камеры глубины
|
||||
* `/RMC2/lift_status` [std_msgs/msg/String] - состояние лифта (moving / success)
|
||||
* `/RMC2/lift` [std_msgs/msg/Float64] - поднятие лифта на заданную высоту
|
||||
* `/RMC2/odometry` [nav_msgs/msg/Odometry] колесная одометрия робота
|
||||
* `/RMC2/scan` [sensor_msgs/msg/LaserScan] - объединенный скан переднего и заднего лидара
|
||||
* `/RMC2/scan_back` [sensor_msgs/msg/LaserScan] - скан заднего лидара
|
||||
publisher
|
||||
* `/RMC2/scan_front` [sensor_msgs/msg/LaserScan] - скан переднего лидара
|
||||
* `/RMC2/cmd_vel` [geometry_msgs/msg/Twist] - целевая скорость платформы
|
||||
* `/tf_static` [tf2_msgs/msg/TFMessage] - дерево статических преобразований между деталями робота
|
||||
* `/tf` [tf2_msgs/msg/TFMessage] - дерево динамическиз преобразований между роботом и миром
|
||||
|
||||
Чтобы робот начал перемещение, необходиом начать публиковать в топик `/RMC2/cmd_vel` целевую скорость. Кинематика робота РМК2 позволяет задачать линейную скорость по оси `x` и угловую по оси `z` робота.
|
||||
|
||||
Чтобы управлять положением подъемного лифта, необходимо отправить в топик `/RMC2/lift` число с плавающей точкой с высотой, на которую поднимется лифт. Значение `0.0` соответствует полностью опущенному положению лифта. Значения `0.1` соответстует поднятому положению. Этого достаточно, чтобы поднять стеллаж с объектами. Лифт имеет 2 фиксированных положения, промежуточного не существует.
|
||||
|
||||
# Дополнительная информация
|
||||
## Поле
|
||||
Соревновательное поле размечено ArUco маркерами в соответствии со следующим изображением:
|
||||

|
||||
|
||||
Маркеры ArUco имеют уникальные ID адреса от 0 до 35, верх маркера соответствует верху цифры на изображении выше. Инпче говоря, все маркеры ориентированы верхней гранью в одну сторону.
|
||||
|
||||
Начало координат поля в Webots совпадает с маркером ID = 0, направление векторов координат показано на картинке выше: ось X смотрит вправо, ось Y смотрит вверх.
|
||||
BIN
__pycache__/test_detect.cpython-313.pyc
Normal file
BIN
dataset/train.cache
Normal file
BIN
dataset/train/hammer/img_0000.jpg
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
dataset/train/hammer/img_0001.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
dataset/train/hammer/img_0002.jpg
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
dataset/train/hammer/img_0003.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
dataset/train/hammer/img_0004.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
dataset/train/hammer/img_0005.jpg
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
dataset/train/hammer/img_0006.jpg
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
dataset/train/hammer/img_0007.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
dataset/train/hammer/img_0008.jpg
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
dataset/train/hammer/img_0009.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
dataset/train/hammer/img_0010.jpg
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
dataset/train/hammer/img_0011.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
dataset/train/hammer/img_0012.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
dataset/train/hammer/img_0013.jpg
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
dataset/train/hammer/img_0014.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
dataset/train/hammer/img_0015.jpg
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
dataset/train/hammer/img_0016.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
dataset/train/hammer/img_0017.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
dataset/train/hammer/img_0018.jpg
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
dataset/train/hammer/img_0019.jpg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
dataset/train/hammer/img_0020.jpg
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
dataset/train/hammer/img_0021.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
dataset/train/hammer/img_0022.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
dataset/train/hammer/img_0023.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
dataset/train/hammer/img_0024.jpg
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
dataset/train/hammer/img_0025.jpg
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
dataset/train/hammer/img_0026.jpg
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
dataset/train/hammer/img_0027.jpg
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
dataset/train/hammer/img_0028.jpg
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
dataset/train/hammer/img_0029.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
dataset/train/hammer/img_0030.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
dataset/train/hammer/img_0031.jpg
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
dataset/train/hammer/img_0032.jpg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
dataset/train/hammer/img_0033.jpg
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
dataset/train/hammer/img_0034.jpg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
dataset/train/hammer/img_0035.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
dataset/train/hammer/img_0036.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
dataset/train/hammer/img_0037.jpg
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
dataset/train/hammer/img_0038.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
dataset/train/hammer/img_0039.jpg
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
dataset/train/hammer/img_0040.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
dataset/train/hammer/img_0041.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
dataset/train/hammer/img_0042.jpg
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
dataset/train/hammer/img_0043.jpg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
dataset/train/hammer/img_0044.jpg
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
dataset/train/hammer/img_0045.jpg
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
dataset/train/hammer/img_0046.jpg
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
dataset/train/hammer/img_0047.jpg
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
dataset/train/hammer/img_0048.jpg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
dataset/train/hammer/img_0049.jpg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
dataset/train/hammer/img_0050.jpg
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
dataset/train/hammer/img_0051.jpg
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
dataset/train/hammer/img_0052.jpg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
dataset/train/hammer/img_0053.jpg
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
dataset/train/hammer/img_0054.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
dataset/train/hammer/img_0055.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
dataset/train/hammer/img_0056.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
dataset/train/hammer/img_0057.jpg
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
dataset/train/hammer/img_0058.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
dataset/train/hammer/img_0059.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
dataset/train/hammer/img_0060.jpg
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
dataset/train/hammer/img_0061.jpg
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
dataset/train/hammer/img_0062.jpg
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
dataset/train/hammer/img_0063.jpg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
dataset/train/hammer/img_0064.jpg
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
dataset/train/hammer/img_0065.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
dataset/train/hammer/img_0066.jpg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
dataset/train/hammer/img_0067.jpg
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
dataset/train/hammer/img_0068.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
dataset/train/hammer/img_0069.jpg
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
dataset/train/hammer/img_0070.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
dataset/train/hammer/img_0071.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
dataset/train/hammer/img_0072.jpg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
dataset/train/hammer/img_0073.jpg
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
dataset/train/hammer/img_0074.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
dataset/train/hammer/img_0075.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
dataset/train/hammer/img_0076.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
dataset/train/hammer/img_0077.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
dataset/train/hammer/img_0078.jpg
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
dataset/train/hammer/img_0079.jpg
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
dataset/train/hammer/img_0080.jpg
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
dataset/train/hammer/img_0081.jpg
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
dataset/train/hammer/img_0082.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
dataset/train/hammer/img_0083.jpg
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
dataset/train/hammer/img_0084.jpg
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
dataset/train/hammer/img_0085.jpg
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
dataset/train/hammer/img_0086.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
dataset/train/hammer/img_0087.jpg
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
dataset/train/hammer/img_0088.jpg
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
dataset/train/hammer/img_0089.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
dataset/train/hammer/img_0090.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
dataset/train/hammer/img_0091.jpg
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
dataset/train/hammer/img_0092.jpg
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
dataset/train/hammer/img_0093.jpg
Normal file
|
After Width: | Height: | Size: 5.3 KiB |