Add lider ROS node and move robot control into its own directory
This commit is contained in:
@@ -149,6 +149,44 @@ The sensor will activate automatically when this command runs and deactivate whe
|
||||
|
||||
---
|
||||
|
||||
### RPLIDAR A1
|
||||
|
||||
Runs in a separate container built from [lidar/Dockerfile](lidar/Dockerfile).
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
│ sllidar_ros2 (rplidar_node) │
|
||||
│ │
|
||||
│ serial 115200 baud │
|
||||
│ angle_compensate = true │
|
||||
│ scan_mode = Sensitivity │
|
||||
│ ▼ │
|
||||
│ /dev/ttyUSB0 ──────> RPLIDAR A1 │
|
||||
│ │
|
||||
/scan <───────│ LaserScan @ ~10 Hz │
|
||||
(sensor_msgs/ │ 360° scan, range 0.15–12 m │
|
||||
LaserScan) │ │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### Topics
|
||||
|
||||
| Topic | Direction | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `/scan` | Published | `sensor_msgs/LaserScan` | 360° laser scan in the `laser` frame |
|
||||
|
||||
#### Configuration
|
||||
|
||||
The LIDAR container is configured via environment variables in `.env` or `docker-compose.yml`. See the [Launching](#launching) section for details.
|
||||
|
||||
#### Verifying LIDAR data
|
||||
|
||||
```bash
|
||||
ros2 topic echo /scan
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setting up the robot
|
||||
|
||||
### 1. Flash Raspberry Pi OS
|
||||
@@ -183,29 +221,51 @@ The [ansible/](ansible/) directory contains a playbook that handles the remainin
|
||||
docker run --rm --privileged tonistiigi/binfmt --install arm64
|
||||
```
|
||||
|
||||
### Build the image
|
||||
### Build with Docker Compose (recommended)
|
||||
|
||||
The Raspberry Pi is `arm64`, so the image must be built for that platform. On an amd64 host use `docker buildx`:
|
||||
Both images are defined in `docker-compose.yml`. Build them together:
|
||||
|
||||
```bash
|
||||
docker build --platform linux/arm64 -t raspbot_v2:latest .
|
||||
docker compose build
|
||||
```
|
||||
|
||||
`--load` exports the built image into the local Docker image store so it can be deployed with `docker save`.
|
||||
Or build a single service:
|
||||
|
||||
The build is split into two stages:
|
||||
```bash
|
||||
docker compose build robot
|
||||
docker compose build lidar
|
||||
```
|
||||
|
||||
1. **builder** — installs the Raspbot hardware library, then compiles the ROS package with `colcon`
|
||||
2. **runtime** — copies only the colcon install overlay and hardware library into a clean `ros:kilted` base; no build tools are included in the final image
|
||||
The builds are split into two stages each:
|
||||
|
||||
1. **builder** — compiles the ROS package(s) with `colcon`; the lidar builder also clones `sllidar_ros2` from GitHub
|
||||
2. **runtime** — copies only the install overlay into a clean `ros:kilted-ros-core` base; no build tools in the final image
|
||||
|
||||
### Build images individually
|
||||
|
||||
```bash
|
||||
# Robot controller
|
||||
docker build --platform linux/arm64 -f robot/Dockerfile -t raspbot_v2:latest .
|
||||
|
||||
# LIDAR
|
||||
docker build --platform linux/arm64 -f lidar/Dockerfile -t raspbot_v2_lidar:latest .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deploying
|
||||
|
||||
Once the image is built, pipe it directly to the target over SSH — no intermediate file or registry needed:
|
||||
Pipe both images directly to the target over SSH — no intermediate file or registry needed:
|
||||
|
||||
```bash
|
||||
docker save raspbot_v2:latest | ssh matt@raspbot-v2.local docker load
|
||||
docker save raspbot_v2:latest raspbot_v2_lidar:latest \
|
||||
| ssh matt@raspbot-v2.local docker load
|
||||
```
|
||||
|
||||
Then copy the compose file to the target:
|
||||
|
||||
```bash
|
||||
scp docker-compose.yml matt@raspbot-v2.local:~/
|
||||
```
|
||||
|
||||
Replace `matt` with the username configured in [ansible/inventory.ini](ansible/inventory.ini).
|
||||
@@ -214,19 +274,55 @@ Replace `matt` with the username configured in [ansible/inventory.ini](ansible/i
|
||||
|
||||
## Launching
|
||||
|
||||
The default `CMD` starts both nodes together via the launch file. The container needs access to the I²C bus — pass only that device rather than running privileged:
|
||||
### Start everything with Docker Compose (recommended)
|
||||
|
||||
```bash
|
||||
docker compose up
|
||||
```
|
||||
|
||||
This starts both the robot controller and LIDAR containers. Logs from both are interleaved in the terminal, each line prefixed with the service name. To run in the background:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
docker compose logs -f # follow logs
|
||||
docker compose down # stop and remove containers
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
Create a `.env` file in the same directory as `docker-compose.yml` to override defaults:
|
||||
|
||||
```bash
|
||||
ROS_DOMAIN_ID=0
|
||||
LIDAR_PORT=/dev/ttyUSB0
|
||||
LIDAR_FRAME_ID=laser
|
||||
```
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `ROS_DOMAIN_ID` | `0` | ROS 2 domain — must match on all nodes |
|
||||
| `LIDAR_PORT` | `/dev/ttyUSB0` | Host device node for the RPLIDAR |
|
||||
| `LIDAR_FRAME_ID` | `laser` | `frame_id` in published `LaserScan` messages |
|
||||
|
||||
### Run containers individually
|
||||
|
||||
```bash
|
||||
# Robot controller
|
||||
docker run --rm \
|
||||
--network=host \
|
||||
--device /dev/i2c-1 \
|
||||
--env ROS_DOMAIN_ID=0 \
|
||||
raspbot_v2:latest
|
||||
|
||||
# LIDAR
|
||||
docker run --rm \
|
||||
--network=host \
|
||||
--device /dev/ttyUSB0 \
|
||||
--env ROS_DOMAIN_ID=0 \
|
||||
raspbot_v2_lidar:latest
|
||||
```
|
||||
|
||||
If your board exposes the controller on a different bus (check with `ls /dev/i2c-*` on the host), substitute the correct device node (e.g. `--device /dev/i2c-0`).
|
||||
|
||||
### Overriding parameters at launch
|
||||
### Overriding robot launch parameters
|
||||
|
||||
Launch arguments can be appended after the image name:
|
||||
|
||||
@@ -250,6 +346,14 @@ Available launch arguments:
|
||||
| `tilt_center_deg` | `60.0` | Tilt angle at startup and shutdown (degrees) |
|
||||
| `ultrasonic_rate_hz` | `10.0` | Ultrasonic sensor publish rate (Hz) |
|
||||
|
||||
### LIDAR device permissions
|
||||
|
||||
The RPLIDAR connects as a USB serial device. If the user running Docker is not in the `dialout` group, add them and log back in:
|
||||
|
||||
```bash
|
||||
sudo usermod -aG dialout $USER
|
||||
```
|
||||
|
||||
### Sending velocity commands from the host
|
||||
|
||||
With the container running, publish from another terminal (requires ROS 2 on the host or a second container on the same network):
|
||||
@@ -301,20 +405,24 @@ ros2 topic echo /joint_states
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile # Two-stage production image
|
||||
├── docker-entrypoint.sh # Sources ROS overlays before exec
|
||||
├── src/
|
||||
│ └── raspbot_v2/
|
||||
│ ├── package.xml # ROS package manifest
|
||||
│ ├── setup.py # ament_python build definition
|
||||
│ ├── launch/
|
||||
│ │ └── robot.launch.py # Starts both nodes together
|
||||
│ └── raspbot_v2/
|
||||
│ ├── __init__.py
|
||||
│ ├── motor_controller_node.py # Differential-drive motor control
|
||||
│ ├── camera_orientation_node.py # Pan/tilt servo control
|
||||
│ └── ultrasonic_node.py # HC-SR04 range sensor
|
||||
└── raspbot_v2_interface/ # Vendored Yahboom hardware library
|
||||
└── Raspbot_Lib/
|
||||
└── Raspbot_Lib.py # I²C driver (smbus, bus 1, addr 0x2B)
|
||||
├── docker-compose.yml # Launches robot and lidar containers together
|
||||
├── docker-entrypoint.sh # Sources ROS overlays before exec (shared by both images)
|
||||
├── robot/
|
||||
│ ├── Dockerfile # Robot controller image (two-stage)
|
||||
│ ├── src/
|
||||
│ │ └── raspbot_v2/
|
||||
│ │ ├── package.xml # ROS package manifest
|
||||
│ │ ├── setup.py # ament_python build definition
|
||||
│ │ ├── launch/
|
||||
│ │ │ └── robot.launch.py # Starts all robot nodes together
|
||||
│ │ └── raspbot_v2/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── motor_controller_node.py # Differential-drive motor control
|
||||
│ │ ├── camera_orientation_node.py # Pan/tilt servo control
|
||||
│ │ └── ultrasonic_node.py # HC-SR04 range sensor
|
||||
│ └── raspbot_v2_interface/ # Vendored Yahboom hardware library
|
||||
│ └── Raspbot_Lib/
|
||||
│ └── Raspbot_Lib.py # I²C driver (smbus, bus 1, addr 0x2B)
|
||||
└── lidar/
|
||||
└── Dockerfile # RPLIDAR A1 image (two-stage, clones sllidar_ros2)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user