Interacting with External Agents via ROS

From OpenCog
Jump to: navigation, search

NOTE! It is recommended that you know how to use ROS before you do this tutorial. ROS tutorials can be found here: http://wiki.ros.org

Theory

About Opencog ROS communication

OpenCog by itself has no dependency on ROS for compilation. The way Opencog interacts with ros agents is by a cogserver dynamic library or application. Cogserver opens up a raw string(scheme code) port (as configured in the configuration file) and ROS Agents (nodes) send scheme (guile) code strings to cogserver over the string port (like netcat) and the cogserver executes it in a thread. If we send a string like ..

   (ListLink
       (ConceptNode "face-count")
       (NumberNode 5)
   )

Cogserver will create that graph in atomspace.

Hence a ROS Agent may subscribe to ROS messages etc. in the usual way and then form atoms or execute scheme code in cogserver. In current state such implementation exists in ros-behavior-scripting git repository inside ros-bridge directory. Studying that code can show how ros agents communicate with cogserver.

However, on the other side for OpenCog to send messages to ROS Agents requires us to load scheme and python code and atomspace graphs in cogserver. Python code is important to load ROS modules to be able to publish ros messages. And scheme code or atomspace graphs which execute the python code for emitting ROS messages via GroundedPredicateNode or GroundedSchemaNode are required as well. Example implementation of this can be seen in ros-behavior-scripting git repository in "src" directory.

Hands On

Overview

This is an overview of logical steps taken once we have installed ROS, and created the files (see File Listings below)

  1. start roscore
  2. start cogserver
  3. telnet to cogserver in a shell and execute cog2ros.py
  4. netcat coggo.scm to cogserver
  5. start ros2cog.py
  6. monitor the ros output


In this hands on we will create a ros agent that counts in a infinite loop from 1 to 5. Each count step happens at 1 second interval, and the ros agent creates a statelink in atomspace with key as conceptnode "ticker" and value as the current count in numbernode. The cogserver provides access to agents via port(default = 17001) and raw text is sent over port terminated by carriage return. The ros agent netcats scheme code to the port and that executes to create the required graph, while another opencog graph described through scheme in file coggo.scm executes inside cogserver atomspace. Whenever the graph being executed in cogserver from coggo.scm matches the statelink value to be equal to one it calls a grounded predicate node with conceptnode "tick" as parameter. The python code loaded in cogserver then gets executed by grounded predicate node and sends the string in conceptnode "tick" i.e. "tick" out as a ros message on topic "alert".

Installing Ros

You must have ros installed and setup before proceeding. You must install the Jade version of ROS (other versions will not work potentially - at the time of writing currently OpenCog only supports ubuntu 14.04): http://wiki.ros.org/jade/Installation/Ubuntu

Create Source Files

For this hands on we first create a few source files: netcat.py (utility file for netcat from python), cog2ros.py (python code to emmit ros message), ros2cog.py (a ros agent sending a count signal at 1 Hz [counts 1 to 5]) and coggo.scm (atomspace code)

Note, at the time of writing, these files exist on Mandeep's Github repository.

Keep all these files in the same directory Create the directory: mkdir ~/cogros this creates the cogros directory as a child to your home directory
Enter the directory: cd ~/cogros

Now create each of the files below in the previously created cogros directory.
Click on the [expand] links next to the file names to see the code

netcat.py

utility file for netcat from python

netcat.py (code)  
#
# netcat.py - Quick-n-dirty network interface
# Copyright (C) 2015  Linas Vepstas
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License v3 as
# published by the Free Software Foundation and including the exceptions
# at http://opencog.org/wiki/Licenses
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to:
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


import socket

# This implements netcat in python.
#
# If you don't now what netcat is, then you should google it.
# Its important and not complicated.
#
def netcat(hostname, port, content) :
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

	# If the cogserver is down, the connection will fail.
	try:
		s.connect((hostname, port))
	except socket.error as msg:
		print "Connect failed: ", msg
		s.close()
		return 1  # non-zero means failure

	s.sendall(content)
	s.shutdown(socket.SHUT_WR)
	while True:
		data = s.recv(1024)
		if not data or data == "":
			break
		# print "Received:", repr(data)
	# print "Connection closed."
	s.close()
	return 0  # zero means success

cog2ros.py

python code to emmit ros message

cog2ros.py (code)  
#!/usr/bin/env python
import rospy
from std_msgs.msg import String
from opencog.atomspace import TruthValue

rospy.init_node("cog2ros")
pub = rospy.Publisher('alert', String, queue_size=10)

def send_msg(valstr):
	s = valstr.name
	pub.publish(s)
	return TruthValue(1, 1)

ros2cog.py

a ros agent sending a count signal at 1 Hz [counts 1 to 5]

ros2cog.py (code)  
#!/usr/bin/env python
import rospy
from netcat import netcat

rospy.init_node("ros2cog")
rate = rospy.Rate(1) # 1hz
i=0
while not rospy.is_shutdown():
	i=i+1
	if i>5:
		i=1
	#create atoms
	ato = '(StateLink (ConceptNode "ticker") (NumberNode '+str(i)+'))\n'
	netcat("localhost",17001,ato)
	rate.sleep()

coggo.scm

atomspace code

coggo.scm (code)  
(use-modules (opencog exec))

(DefineLink
	(DefinedPredicate "main loop")
		(SatisfactionLink
			(SequentialOrLink
				(False (SequentialAndLink
					(EqualLink (SetLink (Number 1))
						(GetLink
							(StateLink (ConceptNode "ticker")(VariableNode "$x"))))
					(EvaluationLink (GroundedPredicateNode "py: send_msg")
						(ListLink (ConceptNode "tick")))
				))
						(DefinedPredicateNode "main loop")
		)))

(cog-evaluate! (DefinedPredicateNode "main loop"))

Interact with External Agents

Now that you have installed ROS, and created all the required files, you can start interacting with an external agent.
Notes: pay close attention to which terminal you are using to enter each command below (and of course press enter after each command to execute it)

  1. Open 2 Terminals (i.e. with putty)
  2. In terminal 1, start roscore (in the background) by typing: roscore & Note: you might need to press enter again to get the prompt back
  3. In terminal 1, goto your opencog build directory and run the cogserver (in the background): ./opencog/cogserver/server/cogserver & Note: depending on your install, your OpenCog build directory might be at ~/opencog/opencog/build
  4. In terminal 2, telnet to cogserver by typing: rlwrap telnet localhost 17001
  5. In terminal 2, on telnet opencog prompt type: py
  6. In Terminal 2, on opencog py prompt type: execfile("path-to-file/cog2ros.py") Note: replace path-to-file with the full path to your directory i.e. /home/adam/cogros/cog2ros.py
  7. In terminal 1, enter the 'cogros' directory (containing coggo.scm - i.e. cd ~/cogros) and type: cat coggo.scm | netcat localhost 17001 Note: This will send the scheme code in coggo.scm to the scheme shell of cogserver and exit the shell, bringing you back to the bash shell
  8. In terminal 1, while still in the cogros directory run ros2cog.py (in the background): python ros2cog.py &
  9. In terminal 1, type: rostopic echo /alert

You should see word "tick" being printed over and over again in terminal 1

---
data: tick
---
data: tick
---
data: tick
---
data: tick
---

Once you have seen this and am satisfied, please go ahead and kill the background processes. Find the process ids :

ps -ax | grep ros2cog
ps -ax | grep roscore

then kill -9 <PID> for ros2cog and roscore

What is happening

  1. on executing cog2ros.py in py shell of cogserver we load the python function that can publish ros messages. It takes concept node atom and prints its name string
  2. On netcat of guile code into cogserver, it starts an endless loop to monitor value of StateLink ConceptNode "ticker" NumberNode value. It matches the numbernode to be equal to 1 and starts calling send_msg python function to emit string "tick" by passing ConceptNode "tick" atom to grounded predicate node
  3. On starting ros2cog.py, the program starts a rosnode and netcat's statelink with timer value to cogserver to put in atomspace. When atomspace updates, the coggo.scm guile code emits messages on "/alert" topic and its printed by rostopic echo

Quiz

1. What is ROS?

Reduced Operational Status. A special 'feature' in OpenCog responsible for all the segmentation faults.. Every.. SINGLE.. one of them. ROS is licensed under an open source, BSD license.
Return Of Saturn. A modern astrological science predicting the return of a hyperdimensional seven headed dream-goat with 15 technicolor horns festooned by 123098 floating eyeballs who enjoys surfing the outer layers of mandelbrot multiverses in it's spare cycles.
Robot Operating System. It provides libraries and tools to help software developers create robot applications. It provides hardware abstraction, device drivers, libraries, visualizers, message-passing, package management, and more.
Review of Systems - often written in to Atomspace relating to MOSES (i.e. when applied to medical data), indicating that the data provider requires a lengthy series of queries during the data cleansing process.

2. What is an External Agent?

An agent not hired by the Kremlin
A special type of Atom
An agent outside of OpenCog
An external agent that communicates with OpenCog

3. Is OpenCog dependent on ROS for compilation?

Maybe
Not sure
No
Absolutely

4. For OpenCog to send messages to ROS Agents, this requires

having the right public keys of the ROS Agents
running fatcat.py beforehand
your mother's permission
loading scheme and python code and atomspace graphs in cogserver
None of the above
All, except for none, of the above
All of the options below

5. What version of ROS must you have installed?

Jewel
Jane
Jehovah
Jehosephat
Jolley
Jade
J-Pop
Jellybean

Your score is 0 / 0


Info

Project Owner: Mandeep

Priority: HIGH