18/06/2019 PhaROS, ROS, Pharo, tutorial

A first step guide to PhaROS

PhaROS is a collection of Pharo libraries that implements the ROS (Robot Operating System ) based client protocol. It allows developing robotic applications right in the Pharo environment by providing an abstract software layer between Pharo and ROS. This guide makes an assumption that readers already have some basic knowledge about ROS, if this is not the case, please check the following links before going any further on this page:

prerequisites

Before installing PhaROS, make sure you have everything set up:

  • A linux environment with ROS pre-installed and configured
  • A Pharo 6.1 environment for PhaROS

Please note that PhaROS and ROS are not necessarily in the same environment. Since ROS protocol is based on the XMLRPC protocol, which is a network protocol, one can have a distributed configuration where PhaROS runs on a machine (e.g. a desktop PC) and ROS is installed on another machine (e.g. Raspberry Pi). As long as the two machines connect to the same network, they can communicate to each other via the ROS protocol. In this case, the ROS machine plays the role of the Master while all other machines connected to it are clients.

NOTE: if you opt for a distributed environment, make sure the two machines can see each other properly. For example, if the hostname of the ROS machine is walle and the hostname of the PhaROS machine is jarvis, please verify if the two can ping each other:

# you need to add the hostname of each machine to the /etc/hosts file of another machine
#From wall-E
ping jarvis
# From jarvis
ping walle

Install

Installing Pharos is really simple by evaluating the following snippet (from pharo 6.1) on the PhaROS machine:

Gofer it
        smalltalkhubUser: 'CAR' project: 'PhaROS';
        configurationOf: 'PhaROS';
        loadStable.

Writing a simple subscriber/publisher

In this guide, we will re-implement this example in PhaROS.

We will develop a publisher that publishes string messages to a topic, and a subscriber that connects to that topic and retrieves the published messages.

In Pharo, start by creating a new package named PhaROS-tutorial, then add a class named PhaROSNodeHelper . This class, a subclass of PhaROSPackage, provides an abstract interface to all of our publishers/subscribers in this example:

PhaROSPackage subclass: #PhaROSNodeHelper
    instanceVariableNames: 'proc'
    classVariableNames: ''
    package: ''PhaROS-tutorial'

The class has an abstract method spin which should be implemented by its subclasses:

PhaROSNodeHelper >> spin
    ^ self subclassResponsibility 

and a terminate method to clean up and terminate all processes created by the node:

PhaROSNodeHelper >> terminate
    proc
        ifNotNil: [ 
            proc terminate.
            proc := nil
        ].
        self cleanupProcesses. 
        OSProcess accessor restartChildWatcherProcess.
        
PhaROSNodeHelper >> cleanupProcesses
    |pb |
    pb := ProcessBrowser new.
    "Terminate non-critic processes"	
    pb processList do: [ :p |
            (pb nameAndRulesFor: p) second  
                ifTrue: [ 
                    p priority = Processor userSchedulingPriority 
                        ifFalse:[
                            pb class terminateProcess: p
                ]].
         ].
    pb updateProcessList.
    self inform: 'PhaROS processes were terminated.'

The publisher

Create a new class named PhaROSTalker which is a subclass of PhaROSNodeHelper :

PhaROSNodeHelper subclass: #PhaROSTalker
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'PhaROS-tutorial'

Inside this class, re-implement the abstract method spin:

PhaROSTalker >> spin
    |pub|
    pub := self controller node topicPublisher: '/chatter' typedAs: 'std_msgs/String'.
    
    proc := [ 
        [ true ] whileTrue: [
            pub send: [ :msg| msg data: 'helloworld ', (DateAndTime new asString)  ].
            500 milliSeconds wait
        ]
    ] forkAt: 31

This method is simple, we create a new publisher (line 3) that publishes messages to a topic named /chatter of type: std_msgs/String, a ROS message type of string.
We then create a new process that periodically publishes a hello world message to that topic each 500 milliseconds.

That's all for the publisher. To run it, make sure that the master is on-line on the ROS machine:

# open a terminal on the ROS machine and run
roscore

we can now run the publisher in a playground on the PhaROS machine:

"Run the publisher on PhaROS machine"
"Change theses IPs with your own:"
"The IP address of the PhaROS machine"
phaROSMachineIp := '192.168.1.11'.
"The ip address of the ROS master "
rosMasterIp := '192.168.1.84'.
rosMasterUri := 'http://',rosMasterIp,':11311'.
"Setting the environment variables"
OSEnvironment default setEnv: 'ROS_HOSTNAME' value: phaROSMachineIp.
OSEnvironment default setEnv: 'ROS_MASTER_URI' value: rosMasterUri.

"Now run the publisher"
pub := PhaROSTalker new.
pub spin.

To verify if the publisher works properly, open a terminal on the ROS (master) machine, and run:

rostopic echo /chatter

You should see the messages published by our publisher :

data: "helloworld 1901-01-01T02:00:00+02:00"
---
data: "helloworld 1901-01-01T02:00:00+02:00"
---
data: "helloworld 1901-01-01T02:00:00+02:00"
---
data: "helloworld 1901-01-01T02:00:00+02:00"
---
data: "helloworld 1901-01-01T02:00:00+02:00"
---
data: "helloworld 1901-01-01T02:00:00+02:00"
---
data: "helloworld 1901-01-01T02:00:00+02:00"
---

The publisher can be terminated by evaluating :

"on the same playground"
pub terminate

The subscriber

We will create a simple subscriber that subscribes to our /chatter topic and prints the received messages on Transcript.
Create a new class named PhaROSListener which is a subclass of PhaROSNodeHelper:

PhaROSNodeHelper subclass: #PhaROSListener
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'PhaROS-tutorial'

Then re-implement the spin method:

PhaROSListener>>spin
    |sub|
    sub := (self controller node buildConnectionFor: '/chatter')
        typedAs: 'std_msgs/String';
        for: [ :msg | Transcript show: msg data; cr ];
        connect

This method explains it all. Now we can run the subscriber/publisher in a playground:

"Change theses IPs with your own:"
"The IP address of the PhaROS machine"
phaROSMachineIp := '192.168.1.11'.
"The ip address of the ROS master "
rosMasterIp := '192.168.1.84'.
rosMasterUri := 'http://',rosMasterIp,':11311'.
"Setting the environment variables"
OSEnvironment default setEnv: 'ROS_HOSTNAME' value: phaROSMachineIp.
OSEnvironment default setEnv: 'ROS_MASTER_URI' value: rosMasterUri.

"Now run the publisher"
pub  := PhaROSTalker new.
pub spin.

"Then the subscriber"
sub := PhaROSListener new.
sub spin.

Open the Transcript, you should see the messages printed out:

To close all:

pub terminate.
sub terminate.

That's all folks!!

Related posts

Comments

The comment editor supports Markdown syntax. Your email is necessary to notify you of further updates on the discussion. It will be hidden from the public.
Powered by antd server, (c) 2017 - 2024 Dany LE.This site does not use cookie, but some third-party contents (e.g. Youtube, Twitter) may do.