If you are not familiar with ROS across multiple machines, please refer to Running ROS across multiple machines tutorial.
Running ROS across multiple machines requires only ONE master, however, if you are trying to build an autonomous multi-robot system you will need to run all robots i.e. there will be more than one master. There is no solution till now for running ROS across multi-agent machines.
Lightweight Communications and Marshalling (LCM) is maybe one option to be used, it is "a set of libraries and tools for message passing and data marshalling, targeted at real-time systems where high-bandwidth and low latency are critical", for more info look here.
The idea is to use ROS to control and communicate between notebook and turtlebot base robot, and to use LCM to communicate over network. LCM supports C/C++, Java, Python, Lua, C#/.Net.
Installing LCM
o
$ unzip lcm-X.Y.Z.zip
o
$ cd lcm-X.Y.Z
o
$ ./configure
o
$ make
o
$ sudo make install
o
$ sudo ldconfig
- Getting started with LCM
What you need to start with LCM is to create a message type, here , you are going to pub/sub using lcm format, then use lcm-gen to generate the massage with the language you are using (C,C++, Python, etc), no more delay, start pub and sub.
There are some ready examples we can use for demonistration
o
Create a message type
§ Go to /lcm-1.3.0/examples/types
§
You will find example_t.lcm message
type
or simply create new file with the following content and name it example_t.lcm
package exlcm; struct example_t { int64_t timestamp; double position[3]; double orientation[4]; int32_t num_ranges; int16_t ranges[num_ranges]; string name; boolean enabled; }
o
Compile it based on the language you
use
§
for python lcm-gen -p example_t.lcm
o
Copy generated folder and past it
next to your publisher and subscriber code.
§ Copy exlcm generated folder and
past it into lcm-1.3.0/example/python, there is two simple examples for pub/sub listener.py and send-message.py, here is the content of them
# listener.py
import lcm from exlcm import example_t def my_handler(channel, data): msg = example_t.decode(data) print("Received message on channel \"%s\"" % channel) print(" timestamp = %s" % str(msg.timestamp)) print(" position = %s" % str(msg.position)) print(" orientation = %s" % str(msg.orientation)) print(" ranges: %s" % str(msg.ranges)) print(" name = '%s'" % msg.name) print(" enabled = %s" % str(msg.enabled)) print("") lc = lcm.LCM() subscription = lc.subscribe("EXAMPLE", my_handler) try: while True: lc.handle() except KeyboardInterrupt: pass lc.unsubscribe(subscription)
# send-message.py
import lcm import time from exlcm import example_t lc = lcm.LCM() msg = example_t() msg.timestamp = int(time.time() * 1000000) msg.position = (1, 2, 3) msg.orientation = (1, 0, 0, 0) msg.ranges = range(15) msg.num_ranges = len(msg.ranges) msg.name = "example string" msg.enabled = True lc.publish("turtlebot1", msg.encode())
o
On lcm-1.3.0/example/python change listener.py
and send-message.py to be executable file
§
chmod +x listener.py
§
chmod +x send-message.py
o
now you are ready to run
the listener and sender within the same pc.
§ python listener.py
§
python send-message.py
o However, to send and
receive within the network, you need to configure multicast address. It
usually enabled in ubuntu, you can check by this command
§
Netstat –g
§
Most probably you will get
default multicast ip 224.0.0.251
§
Then you need to change TTL
from 0 (default) into number of hops you want. Simply export this environment
variable on .bachrc file
export LCM_DEFAULT_URL=udpm:// 224.0.0.251:7667?ttl=3
§ Do the same for all nodes you want to communicate
§ Now run python listener.py on one node, and send-message.py on another node
Combine LCM with ROS
After installing and testing LCM, here is a sample for running running LCM over network and ROS within the robot.
#!/usr/bin/env python
# altered by M. Al-shaboti
import rospy
import lcm
from exlcm import example_t
from std_msgs.msg import String
def my_handler(channel, data):
from geometry_msgs.msg import Twist
is_moving = False;
print("Received message on channel \"%s\"" % channel)
msg = example_t.decode(data)
print(" timestamp = %s" % str(msg.timestamp))
print(" orientation = %s" % str(msg.orientation))
print(" position = %s" % str(msg.position))
print(" ranges: %s" % str(msg.ranges))
# let's go forward at 0.2 m/s
print(" name = '%s'" % msg.name)
print(" enabled = %s" % str(msg.enabled))
print("")
if msg.enabled:
move_cmd.linear.x = 0
move_cmd.linear.x = 0.2
# let's turn at 0 radians/s
move_cmd.angular.z = 0
else:
# let's go forward at 0.2 m/s
# let's turn at 0 radians/s
rospy.loginfo("To stop TurtleBot CTRL + C")
move_cmd.angular.z = 0
def main():
rospy.init_node('turtlebot_node', anonymous=True)
# tell user how to stop TurtleBot
cmd_vel = rospy.Publisher('cmd_vel_mux/input/navi', Twist, queue_size=10)
# Create a publisher which can "talk" to TurtleBot and tell it to move
# Tip: You may need to change cmd_vel_mux/input/navi to /cmd_vel if you're not using TurtleBot2
move_cmd = Twist()
#TurtleBot will stop if we don't keep telling it to move. How often should we tell it to move? 10 HZ
r = rospy.Rate(10);
# Twist is a datatype for velocity
global move_cmd
# let's go forward at 0.2 m/s
move_cmd.linear.x = 0.2
# let's turn at 0 radians/s
# wait for 0.1 seconds (10 HZ) and publish again
move_cmd.angular.z = 0
lc = lcm.LCM()
subscription = lc.subscribe("turtlebot1", my_handler)
try:
while not rospy.is_shutdown():
lc.handle()
# publish the velocity
cmd_vel.publish(move_cmd)
r.sleep()
except KeyboardInterrupt:
pass
main()
lc.unsubscribe(subscription)
# spin() simply keeps python from exiting until this node is stopped
#rospy.spin()
if __name__ == '__main__':
import lcmimport time from exlcm import example_t lc = lcm.LCM() msg = example_t() msg.timestamp = int(time.time() * 1000000) msg.position = (1, 2, 3) msg.orientation = (1, 0, 0, 0) msg.ranges = range(15) msg.num_ranges = len(msg.ranges) msg.name = "example string" msg.enabled = True lc.publish("turtlebot1", msg.encode())