Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
---
title: Build a ROS 2 and Zenoh simulation environment on an Arm server

draft: true
cascade:
draft: true

description: Set up ROS 2 Jazzy with rmw_zenoh in Docker, then run and evaluate a Neobotix ROX simulation on an Arm server.

minutes_to_complete: 60
Expand All @@ -17,7 +21,8 @@ prerequisites:
- An Arm server running Linux with at least 8 CPU cores, 16 GB of RAM, and 30 GB of free disk space
- Docker and Docker Compose installed
- Network access to ports 6080 and 6081 on the Arm server
- Basic familiarity with Linux terminal commands
- Familiarity with launching bash shells within a running Docker container
- Basic familiarity with Linux terminal commands within bash shells

author:
- Odin Shen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,40 @@ layout: "learningpathall"

Keep the installed templates unchanged. You copy them to `~/container_data/` so you can modify the working copies later. This directory is a Docker volume, so the files persist when the container restarts and are also accessible from the host.

## Open a bash shell in the `robot` container

First, get the container ID for the `robot` container. From an SSH session on the Arm server, run:

```bash
docker ps
```

The output is similar to:

```output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
471c961e54d8 odinlmshen/ros2-zenoh-arm:jazzy-desktop "/bin/bash -c /entry…" 4 days ago Up 4 days 0.0.0.0:7447->7447/tcp, 0.0.0.0:7447->7447/udp, [::]:7447->7447/tcp, [::]:7447->7447/udp, 0.0.0.0:6080->80/tcp, [::]:6080->80/tcp ros_zenoh-robot-1
4b574fe60afe odinlmshen/ros2-zenoh-arm:jazzy-desktop "/bin/bash -c /entry…" 4 days ago Up 4 days 0.0.0.0:6081->80/tcp, [::]:6081->80/tcp ros_zenoh-control-1

```

Copy the container ID for `ros_zenoh-robot-1`, such as `471c961e54d8`.

Next, open a bash shell in the running `robot` container:

```bash
docker exec -it 471c961e54d8 /bin/bash
```

{{% notice Important %}}
Whenever you need a new container shell, repeat `docker ps`, copy the appropriate container ID, and run the `docker exec` command.
{{% /notice %}}

Use this bash shell for the next steps.

## Copy the router and session configurations

Open a terminal in the `robot` container. Copy each installed template to the corresponding working file:
Using the open bash shell in the `robot` container, copy each installed template to the corresponding working file:

```bash
cp /opt/ros/jazzy/share/rmw_zenoh_cpp/config/DEFAULT_RMW_ZENOH_ROUTER_CONFIG.json5 \
Expand All @@ -39,17 +70,17 @@ Source the workshop environment so ROS 2 uses the new configuration files:
source ~/workshop_env.bash
```

The output should show both exported paths:
The expected output includes both exported paths:

```output
ZENOH_ROUTER_CONFIG_URI=/home/ubuntu/container_data/ROUTER_CONFIG.json5
ZENOH_SESSION_CONFIG_URI=/home/ubuntu/container_data/SESSION_CONFIG.json5
```

{{% notice Note %}}
From this point, run `source ~/workshop_env.bash` whenever you open a new terminal in the `robot` container.
From this point, run `source ~/workshop_env.bash` whenever you open a new bash shell in the `robot` container.
{{% /notice %}}

## What you've accomplished and what's next

You've created and verified separate router and session configurations, then loaded their paths into the ROS 2 environment. Next, you'll use three ROS 2 processes to observe the router's role in discovery.
You've created separate router and session configurations and confirmed both exported paths in the ROS 2 environment. Next, you'll use three ROS 2 processes to observe the router's role in discovery.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The ROX base subscribes to the `/cmd_vel` topic using the `geometry_msgs/Twist`

Any process that publishes to `/cmd_vel` can control the base. Navigation2 uses this same interface, so it is one publisher to the robot rather than a privileged control path.

Open a sourced terminal in the `robot` container:
Open a sourced bash shell in the `robot` container:

```bash
source ~/workshop_env.bash
Expand All @@ -28,7 +28,7 @@ just teleop

Use the key bindings displayed in the terminal to drive the robot while you observe its movement in RViz.

![Keyboard teleoperation terminal showing the movement key bindings for controlling the robot.](images/robot-teleoperation.png)
![Keyboard teleoperation terminal showing the movement key bindings for controlling the robot.#center](images/robot-teleoperation.png)

## Publish a velocity command

Expand All @@ -54,13 +54,13 @@ Read one odometry message and display the robot position:
ros2 topic echo /odom --once | grep -A2 position
```

The `x` position should advance when the robot moves. On the supplied reference system, a 3-second command at `0.2 m/s` moved the robot from approximately `x = 0` to `x = 0.39 m`:
The `x` position should advance when the robot moves. The output is similar to:

```output
x: 0.3899999883542309
```

This value is an example, not an exact target. Acceleration behaviour and the robot's starting position affect the result.
On the supplied reference system, a 3-second command at `0.2 m/s` moved the robot from approximately `x = 0` to `x = 0.39 m`. This value is an example, not an exact target. Acceleration behaviour and the robot's starting position affect the result.

{{% notice Note %}}
The UR10 arm on the ROX uses a `JointTrajectory` action rather than `Twist`. Publishing `Twist` to the base and `JointTrajectory` to the arm follows the standard ROS interface for each mechanism.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@ You first measure the default TCP-loopback latency. You then enable shared memor

## Measure the TCP-loopback baseline

Stop Navigation2 in Terminal 3. The latency measurement needs wall-clock timestamps, and Navigation2 doesn't operate in this mode.
Stop Navigation2 in bash shell #3 in the `robot` container. The latency measurement needs wall-clock timestamps, and Navigation2 doesn't operate in this mode.

Stop the current simulation. Restart it in Terminal 2 with wall-clock time and without the Gazebo viewer:
Stop the current simulation. Restart it in bash shell #2 with wall-clock time and without the Gazebo viewer:

```bash
just rox_simu use_wall_time:=True no_gui
```

Open a new terminal, source the environment, and measure the point-cloud latency:
Open a new bash shell in the `robot` container and measure the point-cloud latency:

```bash
source ~/workshop_env.bash
just cam_latency
```

Expand All @@ -39,7 +38,7 @@ Record the mean for comparison.

## Enable shared memory in both configurations

Open both of these working files:
Open both of these working files using your choice of editor in one of the `robot` bash shells:

- `~/container_data/ROUTER_CONFIG.json5`
- `~/container_data/SESSION_CONFIG.json5`
Expand All @@ -57,16 +56,16 @@ Both files contain multiple `enabled` fields. In both `ROUTER_CONFIG.json5` and
The router and ROS 2 sessions read these files when their processes start. Stop the router and simulation processes with `Ctrl+C`, then restart them so they load the updated setting:

```bash
# Router terminal
# Router bash shell
just router
```

```bash
# Simulation terminal
# Simulation bash shell
just rox_simu use_wall_time:=True no_gui
```

Run the latency measurement again from a sourced terminal:
Run the latency measurement again from another bash shell in the `robot` container:

```bash
just cam_latency
Expand Down Expand Up @@ -95,23 +94,23 @@ just iftop_lo

## Restore the environment for the next Learning Path

Keep the shared-memory configuration enabled. In Terminal 2, press `Ctrl+C` to stop the temporary wall-time simulation if it is still running.
Keep the shared-memory configuration enabled. In bash shell #2, press `Ctrl+C` to stop the temporary wall-time simulation if it is still running.

Keep the Zenoh router running in Terminal 1. If it has stopped, restart it from a sourced terminal:
Keep the Zenoh router running in bash shell #1. If it has stopped, restart it after re-sourcing the environment:

```bash
source ~/workshop_env.bash
just router
```

In Terminal 2, source the environment if needed and start the normal headless simulation:
In bash shell #2, source the environment if needed and start the normal headless simulation:

```bash
source ~/workshop_env.bash
just rox_simu no_gui
```

In Terminal 3, source the environment if needed and restart Navigation2:
In bash shell #3, source the environment if needed and restart Navigation2:

```bash
source ~/workshop_env.bash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The navigation view contains several layers:

## Start RViz

Open a new terminal in the `robot` container, source the environment, and start the Navigation2 RViz configuration:
Open a new bash shell in the `robot` container, source the environment, and start the Navigation2 RViz configuration:

```bash
source ~/workshop_env.bash
Expand All @@ -30,23 +30,21 @@ Wait for the map and costmaps to render. The light blue area represents free spa

## Send a navigation goal

1. Click Nav2 Goal in the top toolbar.
2. Move your mouse onto the mapped area in the centre.
- Click and hold somewhere in the free/light-blue area.
- While holding the mouse button, drag a short distance. You'll see an arrow appear.
3. Where you first clicked = where you want the robot to go.
4. Direction of the arrow = direction you want the robot facing when it arrives.
1. Select **Nav2 Goal** in the toolbar.
2. Move your pointer onto the mapped area in the centre.
3. Select and hold a position in the free, light-blue area where you want the robot to go.
4. While holding the mouse button, drag a short distance in the direction you want the robot to face. An arrow appears.
5. Release the mouse button.

Nav2 should then calculate a path and the robot should begin moving.

Goals outside the mapped costmap don't have a valid planned path, so the robot won't move toward them.

![RViz showing the Neobotix ROX robot, navigation map, costmaps, and Navigation2 panel.](images/rviz-navigation-goal.png)
![RViz showing the Neobotix ROX robot with the map, local and global costmaps, and active Navigation2 panel. The light-blue free space identifies where you can set a valid navigation goal.#center](images/rviz-navigation-goal.png)

## Verify the navigation result

The robot should plan a path, drive to the goal, and report `Feedback: reached`. A successful reference result is:
The robot should plan a path, drive to the goal, and report `Feedback: reached`. On the supplied reference system, the output is similar to:

```output
Navigation: active
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ These measurements establish a baseline before you enable shared-memory transpor

## Run the monitoring commands

Run the following commands in a sourced `robot` container terminal:
Run each command in turn. Press **Ctrl+C** to stop the current command before starting the next one.

```bash
just top
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ The Zenoh router helps ROS 2 nodes discover each other. When nodes start, they c

You can examine this behaviour by stopping the router after a talker and listener have connected. If their established communication continues, the router isn't carrying the messages between these two processes.

Open three terminals in the `robot` container. Source the environment in each terminal:
Open three bash shells in the `robot` container. Source the environment in each shell:

```bash
source ~/workshop_env.bash
```

## Start the router

In Terminal 1, start the Zenoh router:
In shell #1, start the Zenoh router:

```bash
just router
Expand All @@ -36,13 +36,13 @@ The router ID can differ on your system.

## Start the ROS 2 nodes

In Terminal 2, start the talker:
In shell #2, start the talker:

```bash
ros2 run demo_nodes_cpp talker
```

In Terminal 3, start the listener:
In shell #3, start the listener:

```bash
ros2 run demo_nodes_cpp listener
Expand All @@ -57,13 +57,13 @@ The listener should receive every message published by the talker:

## Stop the router and observe the result

Press `Ctrl+C` in Terminal 1 to stop the router. Keep watching the talker and listener.
Press `Ctrl+C` in shell #1 to stop the router. Keep watching the talker and listener.

The message exchange should continue without interruption. The two nodes already established a direct peer-to-peer connection, so the router isn't in this data path. This result demonstrates the router's discovery role for this established local connection; it doesn't imply that every Zenoh topology can operate without a router.

Nodes can also start before the router because each node periodically retries the router connection.

Restart the router in Terminal 1 before continuing:
Restart the router in shell #1 before continuing:

```bash
just router
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ layout: "learningpathall"

## Understand the container environment

You use two Docker containers built from the same image:
You create and use two Docker containers built from the same image:

- The `robot` container runs the ROS 2 simulation, Zenoh router, and Gazebo environment used in this Learning Path
- The `control` container acts as a remote operator station for later Learning Paths
Expand All @@ -19,7 +19,7 @@ This setup is more than a container exercise. Gazebo, simulated camera and LiDAR

The environment uses official `arm64` binaries without architecture-specific modifications.

Run the host commands on your Arm server. After you open the browser desktop, run commands with an `ubuntu@robot` prompt in the `robot` container.
Run the provided commands on your selected Arm server. After the browser-based VNC desktop opens, run commands with an `ubuntu@robot` prompt in the `robot` container.

## Get the Docker Compose configuration

Expand Down Expand Up @@ -75,7 +75,7 @@ Open the browser desktops and sign in with the password `ubuntu`:
- Control container: `http://<server_ip>:6081/`

{{% notice Important %}}
Do not expose ports `6080`, `6081`, or `7447` directly to the public internet. Use a private network, VPN, SSH tunnel, or restrictive firewall or security-group rules so that only trusted clients can reach these services.
Do not expose ports `6080`, `6081`, or `7447` directly to the public internet from your Arm server. Use a private network, VPN, SSH tunnel, or restrictive firewall or security-group rules so that only trusted clients can reach these services.
{{% /notice %}}

![Browser showing the Ubuntu desktop running inside the robot container through noVNC.](images/robot-desktop.webp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ The simulation and navigation stack run as separate processes so you can start,

Stop the talker and listener from the router experiment. Keep the router running.

Open two new terminals in the `robot` container and source the environment in each one:
Open two new bash shells in the `robot` container and source the environment in each one:

```bash
source ~/workshop_env.bash
```

## Start the headless simulation

In one of the new Terminals, start the simulation:
In the first shell, start the simulation:

```bash
just rox_simu no_gui
Expand All @@ -35,29 +35,29 @@ The `no_gui` argument disables the Gazebo 3D viewer, not the simulation. Gazebo

## Start Navigation2

In the other Terminal, start the navigation stack:
In the second shell, start the navigation stack:

```bash
just rox_nav2
```

Wait for Navigation2 to activate its managed nodes.

It is normal for output to stop after its active. Navigation2 remains idle until it receives a navigation goal.
It is normal for output to stop after it's active. Navigation2 remains idle until it receives a navigation goal.

![Navigation2 terminal output showing managed nodes active while the navigation stack starts in the robot container.](images/nav2-successfully-running.webp)

## Verify the simulated sensors

In another sourced terminal, check the laser scan frequency:
In a third sourced bash shell, check the laser scan frequency:

```bash
ros2 topic hz /scan
```

The `/scan` topic should arrive at approximately 8 Hz. This rate is an expected operating observation, so small variations are normal.
The `/scan` topic should arrive at approximately 8 Hz. This rate is an expected operating observation, so small variations are normal. Press `Ctrl+C` in this shell to stop the scan.

List the camera topics using a new terminal:
Next, list the camera topics to confirm that they are present:

```bash
ros2 topic list | grep camera
Expand Down
Loading