The Robot Operating System (ROS) is a middleware which allows subsystems to communicate with each other.

The ROS Wiki is found at http://wiki.ros.org/.

Roscore must be run before any node, and allows nodes to find each other by name, it acts similarly to how a DNS allows web clients to find web servers.

Only one roscore must be running in the system at any given time even across multiple machines. The machine that runs roscore is called the ROS master.

Through ROS, nodes can:

  • exchange information with other nodes through message passing / pubsub on named topics
  • be registered with the ROS master to communicate with other nodes on the system

The ROS filesystem is built out of metapackages, built out of packages, built out of a package manifest, messages, services, codes, and other miscellaneous things.

ROS Prerequisites

ROS Demo

Install prerequisites, then drop into the container and start roscore:

apptainer run ros-container.sif
roscore

Roscore should spit out information similar to:

auto-starting new master
process[master]: started with pid [38274]
ROS_MASTER_URI=http://furry:11311/

setting /run_id to b887ba54-3c17-11ed-91e2-309c231ba727
process[rosout-1]: started with pid [38295]
started core service [/rosout]

Roscore will use your hostname by default, so we have to point it in the right direction. Make sure /etc/hosts resolves your hostname!

Copy the ROS_MASTER_URI and then start new containers as such:

# start container with variable:
ROS_MASTER_URI=http://furry:11311/ apptainer run Applications/ros-container.sif
 
# or within a container:
export ROS_MASTER_URI=[..]

Run the turtle simulator:

rosrun turtlesim turtlesim_node

Launch the ROS graph by using:

rosrun rqt_graph rqt_graph

Manipulate the ROS pubsub:

# list all topics
rostopic list
 
# show information about a topic
rostopic info /turtle1/pose
 
# subscribe to a topic
rostopic echo /turtle1/pose

After subscribing to a ROS topic, you refresh the graph to see the new connection between turtle1 and you:

Manipulate the turtle:

# understand how we can move the turtle
rostopic info /turtle1/cmd_vel
 
# we receive the output:
# Type: geometry_msgs/Twist
 
# publish a message to the turtle
rostopic pub /turtle1/cmd_vel <double tap TAB>
# or copy and fill as below:
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 2.0"

Linux File Permissions

Create a sample executable script, i.e. my_script.sh, then:

# set all executable bits (user, group, others)
chmod +x my_script.sh
 
# set executable bit for the user
chmod u+x my_script.sh
 
# set executable bit for the group
chmod g+x my_script.sh
 
# set executable bit for others
chmod o+x my_script.sh
 
# remove executable bit from everyone
chmod -x my_script.sh
 
# set (rwx) read-write-execute for owner
# set (r-x) read-execute for group
# set (r--) read for others
chmod 754 my_script.sh

Interact from Python

Below is a sample script to create and publish to a new topic:

#!/usr/bin/env python3
 
import rospy
from std_msgs.msg import String
 
def run():
	pub = rospy.Publisher('abc', String, queue_size=10)
	rospy.init_node('pythonnode', anonymous=True)
	rate = rospy.Rate(10) # 10hz
	while not rospy.is_shutdown():
		msg = "hello!"
		pub.publish(msg)
		rate.sleep()
 
if __name__ == '__main__':
	try:
		run()
	except rospy.ROSInterruptException:
		pass

Run the script as follows:

/opt/ros/noetic/env.sh python my_script.py

You can listen to the topic as follows:

rostopic echo /abc

Interact from Node.js

You can use rosnodejs to interact with ROS:

const rosnodejs = require('rosnodejs');
 
rosnodejs
    .initNode('/rosnodejs')
    .then(() => {
        const pub = rosnodejs
            .nh
            .advertise('/abc', 'std_msgs/String');
 
		const data = "Hello from Node.js!";
        setInterval(() => {
            pub.publish({ data });
        }, 500);
    });

Run as follows: (URI has to be explicitly defined)

ROS_MASTER_URI=http://furry:11311/ /opt/ros/noetic/env.sh node test.js

And again, listen to the topic:

rostopic echo /abc

Interact from Rust

To get started with Rust, create a new project and add the following dependencies:

# ROS library
rosrust = "0.9"
 
# automatic message generation
rosrust_msg = "0.1"

Next, replace the src/main.rs file with:

fn main() {
    // Initialize node
    rosrust::init("rustnode");
 
    // Create publisher
    let publisher = rosrust::publish(
	    "abc", 100).unwrap();
 
    // Create object that maintains 10Hz
    // between sleep requests
    let rate = rosrust::rate(10.0);
 
    // Breaks when a shutdown signal is sent
    while rosrust::is_ok() {
        // Create string message
        let mut msg = rosrust_msg::std_msgs::String::default();
        msg.data = "Hello from Rust!".to_owned();
 
        // Send string message to topic via publisher
        publisher.send(msg).unwrap();
 
        // Sleep to maintain 10Hz rate
        rate.sleep();
    }
}

To build or run, you must provide the ROS environment:

# build
/opt/ros/noetic/env.sh cargo build
 
# run
/opt/ros/noetic/env.sh cargo run
 
# run w/o env (RLS may trigger recompile often)
target/debug/your-binary

As usual, listen to /abc.