YAML on the ROS command line
Contents
Several ROS tools (rostopic, rosservice) use the YAML markup language on the command line. YAML was chosen as, in most cases, it offers a very simple, nearly markup-less solution to typing in typed parameters.
For a quick overview of YAML, please see YAML Overview.
Representing Messages in YAML
ROS Messages can be represented either as a YAML list or dictionary. If represented as a list, the arguments are filled in-order and must align 1-to-1 with the fields of the message. If represented as a dictionary, the dictionary keys are assumed to map onto fields of the same name in the message. Unassigned fields are given default values.
List vs. dictionary ambiguities: the command-line arguments that you type at the console, by default, are represented as a list. For example, if you type:
rosservice call /foo msg/Type 1 2
This will create the list [1, 2], which will then be used to populate a message.
The exception to this is if you type a single dictionary at the command line. for example, if you type:
rosservice call /foo msg/Type '{a: 1, b: 2}'
This will create the dictionary {a: 1, b: 2} with no list wrapper. This enables you to more easily populate the fields of the outer message.
Multiline representation
Assume you have a roscore running, and you listen to a topic e.g. with
rostopic echo /newTopic
You can then send to that topic using rostopic pub <msg-type>. For very simple example, you can try
rostopic pub /newTopic std_msgs/String "test"
std_msgs/String is a predefined type, many other types exist. You should see "test" appearing in the terminal where you launched rostopic echo.
If you want to create a message in the command line spanning several lines, the above will not work, you will have to complete your message with "---", and embed it in a list or dict yaml type, e.g.
rostopic pub /newTopic std_msgs/String ['test'] ---
Again, you should see "test" appearing in the terminal where you launched rostopic echo.
Headers/timestamps
There are two special keys you can use to assist with sending ROS Headers and time values:
auto: create a new Header with the timestamp set to the current time. Frame ID will be empty.
now: create a new time initialized to the current time
For example:
rostopic pub my_topic my_msgs/StampedMsg '{header: auto}'
or
rostopic pub my_topic my_msgs/StampedMsg '{header: {stamp: now}}'
YAML Syntax + the Command Line
While YAML is simple in most cases, there are some gotchas, especially with Bash. Single-quotes and double-quotes have their own meaning in Bash, so interleaving them with YAML can be difficult.
1. Type Overrides
YAML uses "tags" to override types, where the YAML syntax may be ambiguous. Common tags are: !!str, !!int, !!float, !!seq and !!map. Most likely you will just need to know about !!str. YAML tags are difficult because ! has its own meaning in Bash, so you have to use single-quotes.
2. Command-line and Strings
Using empty quotes (\'\' or \"\") will give you the empty string (this is actually null in YAML, but we map null to the empty string).
The !!str tag in YAML lets you override the type to be a string. You may need this when working with strings that look like boolean values (true, false, y, n, yes, no). YAML tags are difficult because ! has its own meaning in Bash, so you have to use single-quotes.
For example:
rosservice call /my_service '!!str true'
Will call /my_service with the string "true".
3. Command-line and messages (dictionaries)
Messages can be represented as YAML dictionaries on the command-line. YAML uses curly-braces to specify dictionaries.
Empty message:
rosservice call /my_service "{}"
Message within a message:
rosservice call /myservice "{position: {x: 1., y: 2.}}"
Bash multi-line syntax:
rosservice call /myservice "a: 1 b: 2"
For a more complicated example, lets look at geometry_msg/PointStamped, which is a message with two embedded messages:
Header header uint32 seq time stamp string frame_id Point point float64 x float64 y float64 z
These are all equivalent ways of publishing the same data:
rostopic pub pt geometry_msgs/PointStamped '{stamp: now, frame_id: base_link}' '[1.0, 2.0, 3.0]'
rostopic pub pt geometry_msgs/PointStamped '[0, now, base_link]' '[1.0, 2.0, 3.0]'
rostopic pub pt geometry_msgs/PointStamped '{header: {stamp: now, frame_id: base_link}, point: [1.0, 2.0, 3.0]}'
rostopic pub pt geometry_msgs/PointStamped '{header: {stamp: now, frame_id: base_link}, point: {x: 1.0, y: 2.0, z: 3.0}}'
4. Command-line and negative numbers
Negative numbers can confuse command-line option parsing, so you need to pass in an additional -- argument to indicate that command-line option parsing should terminate. For example:
rosservice call /add_two_ints -- -1 -2
will call with negative one as the argument.