Difference between revisions of "Calico ROS"

From IPRE Wiki
Jump to: navigation, search
(RosCS)
(Calico)
 
(16 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
= ROS =
 
= ROS =
  
[http://www.ros.org/wiki/ ROS] is the Robot Operating System. Here we assume a standard ROS install.
+
[http://www.ros.org/wiki/ ROS] is the Robot Operating System. Here we assume a standard ROS install. Also, we assume that Mono has been installed. The example below uses Ubuntu.
 
+
= RosCS =
+
 
+
RosCS is a ROS package which creates a connection between Mono and ROS. It takes a C# file and dynamically builds all of the needed links into a set of dynamic link libraries (DLL).
+
  
 
First, we need a local copy of ROS. We are using the current version of ROS (called "fuerte"):
 
First, we need a local copy of ROS. We are using the current version of ROS (called "fuerte"):
Line 16: Line 12:
 
# source ~/ros/setup.bash
 
# source ~/ros/setup.bash
 
# roscd
 
# roscd
 +
 +
= RosCS =
 +
 +
[http://www.ros.org/wiki/roscs RosCS] is a ROS package which creates a connection between Mono and ROS. It takes a C# file and dynamically builds all of the needed links into a set of dynamic link libraries (DLL). It wraps ROS C++ calls (from roscpp) in the C# code through DllImports.
  
 
Next, we need to install the package RosCS:
 
Next, we need to install the package RosCS:
Line 22: Line 22:
 
# source ~/ros/setup.sh
 
# source ~/ros/setup.sh
 
# rosws update cn-roscs-ros-pkg
 
# rosws update cn-roscs-ros-pkg
# [remove depend "mono" from  ~/ros/cn-roscs-ros-pkg/roscs/manifest.xml]
+
# [remove <rosdep name="mono"> from  ~/ros/cn-roscs-ros-pkg/roscs/manifest.xml]
 
# rosdep install roscs
 
# rosdep install roscs
  
 
Finally, we create a C# file and build the DLLs:
 
Finally, we create a C# file and build the DLLs:
  
 +
# mkdir sandbox
 
# rosws set ~/ros/sandbox
 
# rosws set ~/ros/sandbox
 
# source ~/ros/setup.sh
 
# source ~/ros/setup.sh
# roscd sandbox
+
# cd sandbox
 
# roscreate-pkg ROS std_msgs rospy roscpp roscs
 
# roscreate-pkg ROS std_msgs rospy roscpp roscs
# Create a C# file in ROS/src/hello.cs
+
# Create a C# file in ROS/src/hello.cs (see below)
# Edit ROS/CMakeLists.txt
+
# Edit ROS/CMakeLists.txt to add text (see below)
#  
+
# roscd ROS
 +
# rosmake
 +
 
 +
If it compiles without errors, then you can copy the .dll and .so files from lib to Calico/modules/
 +
 
 +
# cd lib
 +
# cp *.dll *.so ~/Calico/trunk/modules/
 +
 
 +
The next section explores using these libraries.
  
 
hello.cs:
 
hello.cs:
Line 85: Line 94:
 
CSHARP_ADD_EXE(hello src/hello.cs)
 
CSHARP_ADD_EXE(hello src/hello.cs)
 
</pre>
 
</pre>
 +
 +
== Explanation ==
 +
 +
By doing the above, you built the ~/ros/sandbox/ROS/bin/hello.exe Mono executable, and all of the required shared libraries (.dll and .so files) to run it. However, we are more interested in the shared libraries found in ~/ros/sandbox/ROS/lib/. We could also make the code in hello.exe be a DLL, or we could add code to the RosCS or RosSharp C# code to make it accessible to Calico.
 +
 +
= Calico =
 +
 +
In this example, we use the raw RosCS.dll from Calico Python. In reality, we would probably write a nicer wrapper in C# so that it will be available to all Calico languages. For example, there are a couple of places in this example where we have to jump through some hoops to get the right types. We can make this more generic.
 +
 +
# In a terminal, run roscore:
 +
## source ~/ros/setup.bash
 +
## roscore
 +
# In another terminal, start Calico:
 +
## StartCalico
 +
## Run sample Python code (below)
 +
# In another terminal, run rostopic
 +
## rostopic echo DummyTopic
 +
 +
<pre>
 +
import System
 +
import RosCS
 +
 +
# First we initialize the root (NodeName) and get the node:
 +
RosCS.RosSharp.Init("NodeName", System.Array[str]([]))
 +
node = RosCS.Node.MainNode
 +
 +
# Next, we create a publisher to post on a topic, here DummyTopic:
 +
publisher = RosCS.Publisher(node, "DummyTopic", RosCS.std_msgs.String.TypeId, 1)
 +
# It is setup to receive string messages
 +
 +
# Next, we setup a String Message receiver callback:
 +
def OnMessage(msg):
 +
    ## msg is RosCS.std_msgs.String
 +
    print("Got message: " + msg.Data);
 +
 +
# Directly calling the Subscribe doesn't work because signature is based on type:
 +
# node.Subscribe("DummyTopic", OnMessage, 6)
 +
# So, we get the overload by type:
 +
Subscribe = node.Subscribe.Overloads[str, RosCS.OnString, int]
 +
# and call it:
 +
Subscribe("DummyTopic", OnMessage, 6)
 +
 +
# And now we start sending and receiving messages:
 +
i = 0
 +
while RosCS.RosSharp.Ok() and i < 10:
 +
    # Create a string message:
 +
    msg = RosCS.std_msgs.String()
 +
    msg.Data = "Hello " + str(i)
 +
    # Send it:
 +
    publisher.Send(msg)
 +
    # Wait for a second, and continue:
 +
    i += 1
 +
    System.Threading.Thread.Sleep(1000)
 +
 +
# and unsubscribe:
 +
UnSubscribe = node.UnSubscribe.Overloads[str, RosCS.OnString]
 +
UnSubscribe("DummyTopic", OnMessage)
 +
</pre>
 +
 +
= Issues =
 +
 +
# Does it shutdown correctly? I think so, as long as you call UnSubscribe. How to do that automatically?
 +
# If you run the code twice, how to unsubscribe from the first, if there is an error?
 +
## finally?
 +
## with...?
 +
# Can we package this up so that it callable from other languages?
 +
## Add functions to C# code.

Latest revision as of 10:37, 18 October 2012

This page describes creating a ROS/Calico connection.

ROS

ROS is the Robot Operating System. Here we assume a standard ROS install. Also, we assume that Mono has been installed. The example below uses Ubuntu.

First, we need a local copy of ROS. We are using the current version of ROS (called "fuerte"):

  1. source /opt/ros/fuerte/setup.bash
  2. mkdir ~/ros
  3. rosws init ~/ros /opt/ros/fuerte
  4. source ~/ros/setup.bash
  5. roscd

RosCS

RosCS is a ROS package which creates a connection between Mono and ROS. It takes a C# file and dynamically builds all of the needed links into a set of dynamic link libraries (DLL). It wraps ROS C++ calls (from roscpp) in the C# code through DllImports.

Next, we need to install the package RosCS:

  1. rosws set cn-roscs-ros-pkg --git https://code.google.com/p/cn-roscs-ros-pkg/
  2. source ~/ros/setup.sh
  3. rosws update cn-roscs-ros-pkg
  4. [remove <rosdep name="mono"> from ~/ros/cn-roscs-ros-pkg/roscs/manifest.xml]
  5. rosdep install roscs

Finally, we create a C# file and build the DLLs:

  1. mkdir sandbox
  2. rosws set ~/ros/sandbox
  3. source ~/ros/setup.sh
  4. cd sandbox
  5. roscreate-pkg ROS std_msgs rospy roscpp roscs
  6. Create a C# file in ROS/src/hello.cs (see below)
  7. Edit ROS/CMakeLists.txt to add text (see below)
  8. roscd ROS
  9. rosmake

If it compiles without errors, then you can copy the .dll and .so files from lib to Calico/modules/

  1. cd lib
  2. cp *.dll *.so ~/Calico/trunk/modules/

The next section explores using these libraries.

hello.cs:

using System;
using System.Threading;
using RosCS;

public class RosCsExample
{
    Node node;
    Publisher pub;

    public RosCsExample()
    {
	this.node = Node.MainNode;
	this.pub = new Publisher(this.node,"DummyTopic",RosCS.std_msgs.String.TypeId,1);
	this.node.Subscribe("DummyTopic",OnMessage,6);
        
    }

    public void OnMessage(RosCS.std_msgs.String msg) {
	Console.WriteLine("Got message: "+msg.Data);
    }

    public void Run() {
	int i = 0;
	while(RosSharp.Ok()) {
	    RosCS.std_msgs.String msg = new RosCS.std_msgs.String();
	    msg.Data ="Hello "+i;
	    this.pub.Send(msg);
	    i++;
	    Thread.Sleep(1000);
	}                       
    }               

    public static void Main(string[] args) {                        
	RosSharp.Init("NodeName",args);                 
	RosCsExample rce = new RosCsExample();
	rce.Run();
    }
}

Add to bottom of CMakeLists.txt:

rosbuild_include(roscs cncs)
rosbuild_gen_cs_msg()
rosbuild_gensrv()
CSHARP_ADD_TARGET_DEPENDENCY(hello Mono.C5) 
CSHARP_ADD_EXE(hello src/hello.cs)

Explanation

By doing the above, you built the ~/ros/sandbox/ROS/bin/hello.exe Mono executable, and all of the required shared libraries (.dll and .so files) to run it. However, we are more interested in the shared libraries found in ~/ros/sandbox/ROS/lib/. We could also make the code in hello.exe be a DLL, or we could add code to the RosCS or RosSharp C# code to make it accessible to Calico.

Calico

In this example, we use the raw RosCS.dll from Calico Python. In reality, we would probably write a nicer wrapper in C# so that it will be available to all Calico languages. For example, there are a couple of places in this example where we have to jump through some hoops to get the right types. We can make this more generic.

  1. In a terminal, run roscore:
    1. source ~/ros/setup.bash
    2. roscore
  2. In another terminal, start Calico:
    1. StartCalico
    2. Run sample Python code (below)
  3. In another terminal, run rostopic
    1. rostopic echo DummyTopic
import System
import RosCS

# First we initialize the root (NodeName) and get the node:
RosCS.RosSharp.Init("NodeName", System.Array[str]([]))
node = RosCS.Node.MainNode

# Next, we create a publisher to post on a topic, here DummyTopic:
publisher = RosCS.Publisher(node, "DummyTopic", RosCS.std_msgs.String.TypeId, 1)
# It is setup to receive string messages

# Next, we setup a String Message receiver callback:
def OnMessage(msg):
    ## msg is RosCS.std_msgs.String
    print("Got message: " + msg.Data);

# Directly calling the Subscribe doesn't work because signature is based on type:
# node.Subscribe("DummyTopic", OnMessage, 6)
# So, we get the overload by type:
Subscribe = node.Subscribe.Overloads[str, RosCS.OnString, int]
# and call it:
Subscribe("DummyTopic", OnMessage, 6)

# And now we start sending and receiving messages:
i = 0
while RosCS.RosSharp.Ok() and i < 10:
    # Create a string message:
    msg = RosCS.std_msgs.String()
    msg.Data = "Hello " + str(i)
    # Send it:
    publisher.Send(msg)
    # Wait for a second, and continue:
    i += 1
    System.Threading.Thread.Sleep(1000)

# and unsubscribe:
UnSubscribe = node.UnSubscribe.Overloads[str, RosCS.OnString]
UnSubscribe("DummyTopic", OnMessage)

Issues

  1. Does it shutdown correctly? I think so, as long as you call UnSubscribe. How to do that automatically?
  2. If you run the code twice, how to unsubscribe from the first, if there is an error?
    1. finally?
    2. with...?
  3. Can we package this up so that it callable from other languages?
    1. Add functions to C# code.