> For the complete documentation index, see [llms.txt](https://docs.veerobot.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.veerobot.com/ros-robots/beetle-bot-plus/for-developers/ros2.md).

# ROS 2

SSH, topics, teleop, mapping, bags, ROS 2 Jazzy on BeetleBot

The stack is already running. SSH in and use ordinary ROS 2 commands. You can also run ROS 2 Jazzy on an Ubuntu laptop on the same Wi-Fi and open **RViz**, [Laptop ROS and RViz](/ros-robots/beetle-bot-plus/for-developers/laptop-ros.md). Map without a tablet: [Map from the terminal](/ros-robots/beetle-bot-plus/for-developers/map-from-terminal.md).

## Environment

```bash
ssh veerobot@<robot-ip>
source /opt/ros/jazzy/setup.bash
source ~/VEEROS/ros2_ws/install/setup.bash
```

```bash
ros2 topic list
ros2 node list
ros2 service list
ros2 topic echo /scan
ros2 topic hz /scan
ros2 topic info /cmd_vel -v
```

Default `ROS_DOMAIN_ID` is **0**. Check with `echo $ROS_DOMAIN_ID` on the robot.

## Safety services

Call these before you expect motion. ARM is required even if you publish `/cmd_vel`.

```bash
ros2 service call /veeros/arm std_srvs/srv/Trigger {}
ros2 service call /veeros/disarm std_srvs/srv/Trigger {}
ros2 service call /veeros/estop std_srvs/srv/Trigger {}
ros2 service call /veeros/clear_estop std_srvs/srv/Trigger {}
```

A `/goal_pose` published while disarmed is **not** replayed after ARM. Publish again.

## Velocity, TwistStamped

`/cmd_vel`, `/cmd_vel_joy`, and `/cmd_vel_nav` use **`geometry_msgs/TwistStamped`**, not `Twist`.

Keyboard teleop (publishes `/cmd_vel`):

```bash
ros2 run veeros_teleop keyboard_teleop
```

| Key                   | Action                       |
| --------------------- | ---------------------------- |
| `w` / `s` / `a` / `d` | Forward / back / turn        |
| Space                 | Zero velocity                |
| `z` / `c`             | Arm / disarm                 |
| `x` / `v`             | E-stop / clear E-stop        |
| `q` / `e`             | Scale linear speed up / down |

Publish a short forward command yourself:

```bash
ros2 topic pub --once /cmd_vel geometry_msgs/msg/TwistStamped \
 "{header: {frame_id: 'base_link'}, twist: {linear: {x: 0.15}, angular: {z: 0.0}}}"
```

## Topics and services

| Name                                            | Type                                      | Use                                       |
| ----------------------------------------------- | ----------------------------------------- | ----------------------------------------- |
| `/cmd_vel`                                      | `geometry_msgs/TwistStamped`              | Your teleop / node                        |
| `/cmd_vel_joy`                                  | `geometry_msgs/TwistStamped`              | Gamepad (wins while the pad switch is on) |
| `/cmd_vel_nav`                                  | `geometry_msgs/TwistStamped`              | Navigation output                         |
| `/scan`                                         | `sensor_msgs/LaserScan`                   | Perception and Nav2                       |
| `/scan_filtered`                                | `sensor_msgs/LaserScan`                   | Display (Foxglove)                        |
| `/odom`                                         | `nav_msgs/Odometry`                       | Wheel odometry                            |
| `/odometry/filtered`                            | `nav_msgs/Odometry`                       | Fused odometry                            |
| `/map`                                          | `nav_msgs/OccupancyGrid`                  | Active map                                |
| `/goal_pose`                                    | `geometry_msgs/PoseStamped`               | One Nav2 goal                             |
| `/initialpose`                                  | `geometry_msgs/PoseWithCovarianceStamped` | Localization seed                         |
| `/battery_state`                                | `sensor_msgs/BatteryState`                | Pack voltage                              |
| `/tf` `/tf_static`                              | `tf2_msgs/TFMessage`                      | Frames                                    |
| `/veeros/arm` `/disarm` `/estop` `/clear_estop` | `std_srvs/srv/Trigger`                    | Safety                                    |

### Who wins

E-stop beats the gamepad. The gamepad beats dashboard teleop and `/cmd_vel`. Navigation is last among those. ARM is still required.

A gamepad with the **physical switch on** overrides `/cmd_vel`. Turn the switch off (or put the pad down) while you test your node.

## LiDAR and camera

```bash
ros2 topic hz /scan # typically ~7–10 Hz
ros2 topic echo /scan --once
```

RGB live view for operators is the dashboard stream on port 8080, not a required ROS subscription.

When the Foxglove bridge is on, a republisher also offers:

* `/camera/image_raw/compressed`
* `/camera/camera_info`

Depth camera (if purchased and enabled): `/oak/rgb/image_raw`, `/oak/depth/image_raw`.

## Navigation from ROS

Map from the dashboard ([Maps and missions](/ros-robots/beetle-bot-plus/maps-and-missions.md)) or from SSH with `veeros_map` ([Map from the terminal](/ros-robots/beetle-bot-plus/for-developers/map-from-terminal.md)). After a map of this space is active:

```bash
# Seed pose (same job as Set pose)
ros2 topic pub --once /initialpose geometry_msgs/msg/PoseWithCovarianceStamped \
 "{header: {frame_id: 'map'}, pose: {pose: {position: {x: 0.0, y: 0.0, z: 0.0}, orientation: {w: 1.0}}}}"

# One goal, ARM first
ros2 topic pub --once /goal_pose geometry_msgs/msg/PoseStamped \
 "{header: {frame_id: 'map'}, pose: {position: {x: 1.0, y: 0.0, z: 0.0}, orientation: {w: 1.0}}}"
```

Foxglove **2D pose** and RViz **2D Nav Goal** publish `/goal_pose`. Multi-point routes are dashboard missions.

## Bags

On the robot:

```bash
ros2 bag record /scan /odom /odometry/filtered /tf /tf_static -o ~/bags/drive1
```

Play later with `ros2 bag play ~/bags/drive1`, or open the bag in Foxglove Studio → **Open local file**.

## Laptop on the same Wi-Fi

Full install (Jazzy, meshes, `beetlebot.rviz`): [Laptop ROS and RViz](/ros-robots/beetle-bot-plus/for-developers/laptop-ros.md).

```bash
export ROS_DOMAIN_ID=0
source /opt/ros/jazzy/setup.bash
source ~/ros_ws/install/setup.bash # after you built the overlay
ros2 topic list
```

If the access point blocks multicast, `ros2 topic list` on the laptop stays empty. Run nodes **on the robot** (SSH) or use [Foxglove](/ros-robots/beetle-bot-plus/foxglove.md) / [HTTP](/ros-robots/beetle-bot-plus/for-developers/http-and-webhooks.md).

## Your own package

Create the overlay on a laptop as in [Laptop ROS and RViz](/ros-robots/beetle-bot-plus/for-developers/laptop-ros.md) (section 5). On the robot, use a **separate** overlay, do not rebuild `~/VEEROS/ros2_ws`.

Publish `/cmd_vel` as **TwistStamped**. Call `/veeros/arm` before motion. Copy-paste node: [Write a node](/veestack/research/writing-a-node.md).
