Sound Servo (PC Speaker) icon Sound Servo (PC Speaker) — Maps PC audio volume to servos in real time with scalar, min/max, invert & multi-servo options-ideal for syncing robot mouth to sound Try it →
 
ROS 2 Connector Robot Skill

ROS 2 Connector

by Synthiam Inc.

Bridge ARCx and ROS 2 via rosbridge: bind topics, publish Robot Bus data, and expose ARCx services without ROS installed.

Requires ARCx v6 (Updated 10/28/2026)
Tags: Communication
Compatible with: Compatible with Microsoft Windows 10 or 11 Windows Compatible with ARM Linux (Raspberry pi, etc) ARM Compatible with Linux Linux Compatible with MacOS MacOS

How to add the ROS 2 Connector robot skill

  1. Load the most recent release of ARCx on a compatible operating system (Get ARCx).
  2. Press the + Skills menu from the top menu bar in ARCx.
  3. Choose the Communication category tab.
  4. Press the ROS 2 Connector icon to add the robot skill to your project.

Don't have a robot yet?

Follow the Getting Started Guide to build a robot and use the ROS 2 Connector robot skill.


How to use the ROS 2 Connector robot skill

Bridges ARCx and ROS 2 over rosbridge, so ROS nodes can drive the robot and ARCx can consume what ROS publishes.

ARCx does not need ROS installed. Run rosbridge_server on the ROS machine and point this skill at it; everything travels as WebSocket JSON.

The skill is deliberately open-ended. Rather than a fixed set of features, it is a list of bindings - each one wires a part of ARCx to a ROS topic, in one direction or the other - plus services ARCx advertises for nodes to call, plus script commands for anything not covered.

ROS 2 Connector  <a href='/Support/Skills/Skills-Overview' target='_top'>robot skill</a> window

Requirements

  • A ROS 2 machine running rosbridge_server (from rosbridge_suite), typically on port 9090:

    ros2 launch rosbridge_server rosbridge_websocket_launch.xml
    
  • Network reachability between that machine and ARCx.

  • For ListTopics, ListServices and ListNodes, the rosapi node that rosbridge_suite runs alongside the server.

Adding it to a project

  1. Start rosbridge_server on the ROS machine.
  2. Add the skill (Communication category).
  3. On the Connection tab set the host and port, and press Connect in the skill's window.
  4. On the Bindings tab add the wiring you need - see below.
  5. Turn on Auto connect once it works, so the robot comes up on its own.

Bindings

Bindings configuration tab

A binding has a name, a direction, a topic and a kind. Direction is either:

  • RosToArc - subscribe to a topic and apply what arrives to ARCx;
  • ArcToRos - watch something in ARCx and publish it.
Kind What it wires Notes
Movement The movement panel, as geometry_msgs/Twist. Subscribing to /cmd_vel is what lets a ROS 2 navigation stack drive the robot. Publishing reports what ARCx is commanding. Default /cmd_vel, RosToArc.
Servo Servo positions, either one value per topic or a whole sensor_msgs/JointState. Default /joint_states, RosToArc, JointState mode.
Digital A digital IO port. Default /arc/digital/d0, RosToArc.
ADC An analog to digital converter port. Default /arc/adc/adc0, ArcToRos, 200 ms.
PWM A PWM port duty cycle. Default /arc/pwm/d0, RosToArc.
Sonar An ultrasonic distance sensor as sensor_msgs/Range. Publish only - a distance sensor is read, not told. Default /arc/range, 200 ms.
Battery EZB battery voltage and CPU temperature as sensor_msgs/BatteryState. Publish only. Default /arc/battery, 5 s.
LaserScan Scan data through ARCx's navigation messaging, as sensor_msgs/LaserScan. Subscribing feeds a ROS lidar into ARCx's mapping skills; publishing hands ARCx's scan data to ROS. Default /scan, RosToArc, 360 field of view, throttled to 100 ms.
Odometry Robot pose through ARCx's navigation messaging, as nav_msgs/Odometry or a stamped pose. Default /odom, ArcToRos.
NavigationStatus Navigating, paused or stopped, as a string. Default /arc/navigation_status, ArcToRos.
Variable An ARCx global variable. The general purpose escape hatch: anything a script can compute can be published, and anything ROS publishes can land in a variable. Default /arc/variable, ArcToRos.
ControlCommand Runs a ControlCommand on another robot skill when a message arrives. Subscribe only. Default /arc/command.
Script Runs a script when a message arrives, with the message in ROSMessage and the topic in ROSSource. Subscribe only. Default /arc/script.
Camera A camera image as sensor_msgs/CompressedImage. Publish only. Default /arc/camera/compressed.
Custom A message built from a JSON template with ARCx variables substituted in, or an incoming message picked apart into ARCx variables. For message types this skill has never heard of, including your own. Default /arc/custom, ArcToRos.
RobotBus A topic on the ARCx Robot Bus, carried whole: any ROS message type, in either direction, with no ARCx variable in between. See The Robot Bus below. Default /scan, RosToArc, published on the bus as /ros/scan.

Per-binding options include the publish interval, a throttle for incoming messages, and publish on change only, which keeps a topic quiet while nothing is happening.

ARCx's navigation messaging uses ROS's frame and units: metres, x forward, y left, with yaw and scan angles in radians growing counter-clockwise from -pi to pi. The LaserScan and Odometry bindings therefore pass poses and scans straight across in both directions with no conversion.

Services ARCx advertises

Services configuration tab

A topic is fire-and-forget. A service lets a ROS node ask ARCx to do something and wait for the answer - a behaviour tree node calling /arc/say and waiting for the robot to finish speaking needs a service, not a topic.

Each service export has a name (default /arc/trigger), a type (default std_srvs/srv/Trigger, which takes no request fields and answers with success and message), and an action:

Action What the node's call does
ControlCommand Runs a ControlCommand on a chosen robot skill and returns what it gave back. Request fields are mapped to the command's parameters with JSON paths - a comma separated path per parameter, in order; a path of . means the whole request as JSON text.
Script Runs a script and returns its result.
SetVariable Sets an ARCx global variable from the request.
GetVariable Returns the current value of an ARCx global variable.

The response is a JSON template. $Result is replaced by whatever the action returned, and any other $VariableName by that ARCx variable - so $Distance in a template is the value of the variable Distance. The default matches std_srvs/srv/Trigger.

Any service type works, as long as the response template names the fields that type declares.

The Robot Bus

The Robot Bus is where the parts of an ARCx robot share what they know: robot skills and scripts publish topics, offer services and place frames, and with Options, Preferences, Robot Bus turned on, programs outside ARCx (Python, JavaScript, anything that speaks HTTP or WebSocket) join in. This robot skill puts your ROS graph on it, so every robot skill, script, recording and external program can use ROS without knowing that ROS is there. Views, Robot Bus shows it all live.

RobotBus bindings

A RobotBus binding joins one ROS topic to one Robot Bus topic.

A RobotBus binding putting the ROS topic /chatter on the bus as /ros/chatter

  • RosToArc subscribes to the ROS topic and publishes every message, whole and in its own shape, on the bus topic. The bus message's type is the ROS message type. Leave Robot Bus topic blank to use /ros followed by the ROS topic, so /scan lands on /ros/scan and /odom on /ros/odom. Read from carries a single field instead of the whole message.
  • ArcToRos subscribes to the bus topic and publishes what arrives on the ROS topic with the binding's message type. The bus topic may be a pattern: * matches one level and ** any number. An object is sent as the ROS message, so its fields must match the type; text, a number or a flag is sent as {"data": value}, which is what the std_msgs types expect. Send picks one field, and Throttle keeps only the newest message when the bus is faster than you want ROS to be. A message this robot skill put on the bus itself is never sent back, so one bus topic can be bridged in both directions.

A RobotBus binding sending the text field of the bus topic /my_robot/status to the ROS topic /arcx_status

Because the whole message travels, a recording made with the Robot Bus recorder captures ROS data exactly, and playing it back publishes it on the bus again for the bindings and skills that listen.

Services on the bus

While connected, this robot skill offers open ended services on the bus, named after its window title (/ros_connector/... for a skill titled ROS Connector). A script calls them with Bus.call(), an external program through the Robot Bus API, an AI through the MCP bus_call_service tool.

  • /ros_connector/call_service calls any ROS service: service, type (optional when rosbridge can look it up), args and timeoutMs. It returns the response values, or fails with ROS's reason.
  • /ros_connector/publish publishes one message: topic, type (needed the first time a topic is published) and msg.
  • /ros_connector/subscribe mirrors a ROS topic onto the bus until /ros_connector/unsubscribe: topic, type, busTopic (default /ros followed by the topic) and throttleMs. This is how a program puts a ROS topic on the bus without anyone editing this robot skill's bindings.
  • /ros_connector/topics, /ros_connector/services and /ros_connector/nodes list the ROS graph through rosapi.
  • /ros_connector/status reports the connection, the running bindings and the mirrored topics.

For example, from JavaScript:

Bus.call("/ros_connector/subscribe", { topic: "/odom" });
var odom = Bus.waitForMessage("/ros/odom", 2000);
print(odom.pose.pose.position.x);

Bus.call("/ros_connector/call_service", { service: "/reset_odometry", type: "std_srvs/srv/Trigger" });

The services are removed when the connection drops and offered again when it returns.

Connection settings

Connection configuration tab

Setting Meaning Default
Host / Port Where rosbridge is. 127.0.0.1 / 9090
Use SSL wss:// rather than ws://. Only needed when rosbridge is behind a TLS proxy - rosbridge itself speaks plain WebSocket. off
Ignore certificate errors For a self-signed proxy certificate. off
URL override A complete URL that overrides host, port and SSL, for a rosbridge reached through a proxy on a path, such as wss://myrobot.example.com/rosbridge. empty
Auto connect Connect as soon as the project finishes loading. On for a robot meant to come up on its own. off
Reconnect seconds How long to wait before retrying a dropped link. 5
ROS 1 compatibility Name time fields secs/nsecs and default message types to the short package/Type form, for a rosbridge running on ROS 1. Off means ROS 2, which is what this skill is for. off
Queue size How many messages may be waiting in either direction before the oldest are dropped. A stalled link must cost bounded memory, and stale robot data is not worth keeping. 512
Service call timeout (ms) How long CallService waits. 5000

Frames

Advanced configuration tab

Setting Default
Base frame id base_link
Odom frame id odom
Laser frame id laser_frame
Camera frame id camera_link

Behaviour

Setting Meaning Default
Verbose logging Write every message to the skill's log. Useful while wiring a node up, far too noisy to leave on. off
Publish status variables Keep the ROS... variables up to date, so a script can react to the link dropping. on
Stop movement on disconnect Stop the Movement Panel when the connection is lost. For a robot driven from ROS, a dropped link must not leave it driving into a wall. on

The Window tab sets the robot skill's window title, its size on the workspace and notes about what it does in this project.

Window configuration tab

Variables published

Variable Contents
ROSConnected Whether the link is up.
ROSStatus The connection status text.
ROSUrl The URL in use.
ROSLastTopic The topic of the most recent message.
ROSLastMessage That message, as JSON.

Inside a Script binding, the arriving message is in ROSMessage and the topic in ROSSource - read them with getVar("ROSMessage").

Numbers on the wire

rosbridge carries JSON, and JSON has no way to write infinity or NaN. A binding that would produce one - a laser scan with no return, for example - has to use the range maximum instead. Keep that in mind when interpreting ARCx data on the ROS side.

Troubleshooting

Symptom Cause
Never connects rosbridge_server is not running, the port is wrong, or a firewall is in the way. Try ws://host:9090 from a browser console on the same machine as ARCx.
Connects, but nothing arrives The topic name is wrong, or the publisher is on a different ROS domain. Use ListTopics to see the graph.
ListTopics returns nothing The rosapi node is not running; it comes with rosbridge_suite.
Messages arrive but nothing happens in ARCx The binding is disabled, its direction is the wrong way round, or the message type does not match. Turn on verbose logging.
The robot keeps driving after ROS goes away Turn on Stop movement on disconnect.
The link saturates with lidar data Raise the throttle on the LaserScan binding.
Time fields are rejected ROS 1 uses secs/nsecs; turn on ROS 1 compatibility.
Messages are dropped under load Raise Queue size, or publish less often.

See also

  • Camera Source (usb) / Camera Source (ezb) - what a Camera binding publishes
  • Auto Position / Continuous Rotation Movement Panel - what a Movement binding drives

Control Commands for the ROS 2 Connector robot skill

There are Control Commands available for this robot skill which allows the skill to be controlled programmatically from scripts or other robot skills. These commands enable you to automate actions, respond to sensor inputs, and integrate the robot skill with other systems or custom interfaces. If you're new to the concept of Control Commands, we have a comprehensive manual available here that explains how to use them, provides examples to get you started and make the most of this powerful feature.

Control Command Manual

This robot skill has 19 control commands, listed below. Send them from a JavaScript or Python script, from Blockly, or from another robot skill.

The first value is always the window title, which is the name in the title bar of the robot skill on your workspace. It starts out as ROS 2 Connector, which is what every example below uses. If you rename the robot skill, or add a second copy of it to the project, use the title as it appears on that window instead.

ControlCommand() can be shortened to CC(), and both spellings work in JavaScript and in Python. The examples are JavaScript; Python is the same call, except that true and false are written True and False.

Advertise a topic so it appears in ROS before its first message. Publishing advertises for you, so this is only needed to make an empty topic visible.

Syntax

ControlCommand("ROS 2 Connector", "Advertise", (String)topic, (String)messageType)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes
2 messageType Text Your text, in quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Advertise", "topic", "messageType");

CallService

Call a ROS service and wait for it. Returns the response values as JSON. Arguments are a JSON object, or blank for a service that takes none.

Syntax

ControlCommand("ROS 2 Connector", "CallService", (String)service, (String)serviceType, (String)argumentsJson)

Parameters

# Name Type What to pass
1 service Text Your text, in quotes
2 serviceType Text Your text, in quotes
3 argumentsJson Text Your text, in quotes

Returns: String

Example

var result = ControlCommand("ROS 2 Connector", "CallService", "service", "serviceType", "argumentsJson");

Connect

Connect to the rosbridge server and start every binding.

Syntax

ControlCommand("ROS 2 Connector", "Connect")

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Connect");

Disconnect

Disconnect from the rosbridge server and stop every binding.

Syntax

ControlCommand("ROS 2 Connector", "Disconnect")

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Disconnect");

GetLastMessage

The most recent message seen on a topic subscribed to with Subscribe, as JSON. Empty when none has arrived.

Syntax

ControlCommand("ROS 2 Connector", "GetLastMessage", (String)topic)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes

Returns: String

Example

var result = ControlCommand("ROS 2 Connector", "GetLastMessage", "topic");

GetStats

Connection counters (messages and bytes each way, drops, uptime) as JSON.

Syntax

ControlCommand("ROS 2 Connector", "GetStats")

Returns: String

Example

var result = ControlCommand("ROS 2 Connector", "GetStats");

IsConnected

Is the connection to the rosbridge server up right now?

Syntax

ControlCommand("ROS 2 Connector", "IsConnected")

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "IsConnected");

ListNodes

Every node on the ROS graph, as JSON. Needs the rosapi node.

Syntax

ControlCommand("ROS 2 Connector", "ListNodes")

Returns: String

Example

var result = ControlCommand("ROS 2 Connector", "ListNodes");

ListServices

Every service on the ROS graph, as JSON. Needs the rosapi node.

Syntax

ControlCommand("ROS 2 Connector", "ListServices")

Returns: String

Example

var result = ControlCommand("ROS 2 Connector", "ListServices");

ListTopics

Every topic on the ROS graph, as JSON. Asks the rosapi node that rosbridge_suite runs alongside rosbridge_server.

Syntax

ControlCommand("ROS 2 Connector", "ListTopics")

Returns: String

Example

var result = ControlCommand("ROS 2 Connector", "ListTopics");

Publish

Publish a message given as JSON. The message type is needed so rosbridge knows what the topic carries.

Syntax

ControlCommand("ROS 2 Connector", "Publish", (String)topic, (String)messageType, (String)messageJson)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes
2 messageType Text Your text, in quotes
3 messageJson Text Your text, in quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Publish", "topic", "messageType", "messageJson");

PublishBool

Publish true or false to a topic as a std_msgs/Bool.

Syntax

ControlCommand("ROS 2 Connector", "PublishBool", (String)topic, (Bool)value)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes
2 value True or false true or false, without quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "PublishBool", "topic", true);

PublishNumber

Publish a number to a topic as a std_msgs/Float64.

Syntax

ControlCommand("ROS 2 Connector", "PublishNumber", (String)topic, (Number)value)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes
2 value Number A number, without quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "PublishNumber", "topic", 0);

PublishString

Publish text to a topic as a std_msgs/String.

Syntax

ControlCommand("ROS 2 Connector", "PublishString", (String)topic, (String)text)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes
2 text Text Your text, in quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "PublishString", "topic", "text");

Restart

Reconnect and rebuild every binding from the current configuration.

Syntax

ControlCommand("ROS 2 Connector", "Restart")

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Restart");

SetBindingEnabled

Turn one configured binding on or off by its name, then rebuild the bridge.

Syntax

ControlCommand("ROS 2 Connector", "SetBindingEnabled", (String)bindingName, (Bool)enabled)

Parameters

# Name Type What to pass
1 bindingName Text Your text, in quotes
2 enabled True or false true or false, without quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "SetBindingEnabled", "bindingName", true);

Subscribe

Subscribe to a topic at runtime and store each message, as JSON, in the given ARC variable. The message type may be left blank for a topic that already exists in ROS.

Syntax

ControlCommand("ROS 2 Connector", "Subscribe", (String)topic, (String)messageType, (String)variableName)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes
2 messageType Text Your text, in quotes
3 variableName Text Your text, in quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Subscribe", "topic", "messageType", "variableName");

Unadvertise

Stop advertising a topic.

Syntax

ControlCommand("ROS 2 Connector", "Unadvertise", (String)topic)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Unadvertise", "topic");

Unsubscribe

Drop a runtime subscription created by Subscribe. A topic that a configured binding also uses stays subscribed.

Syntax

ControlCommand("ROS 2 Connector", "Unsubscribe", (String)topic)

Parameters

# Name Type What to pass
1 topic Text Your text, in quotes

Returns: Boolean [true or false]

Example

var result = ControlCommand("ROS 2 Connector", "Unsubscribe", "topic");

This list is read out of the robot skill itself each time its package is uploaded, so it matches the published version (v6).


ARC Pro

Upgrade to ARC Pro

Unlock the true power of automation and robotics by becoming a proud subscriber of Synthiam ARC Pro.