Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Groovy rosjava project setup
Description: This explains how to use the Groovy language to interact with ROS via rosjavaTutorial Level:
WARNING: This documentation refers to an outdated version of rosjava and is probably incorrect. Use at your own risk. Follow updates on site: https://github.com/rosjava/rosjava_core and https://github.com/tkruse/rosjava_wiki_tutorials
Contents
Introduction
Groovy is a script language that is based on the Java Virtual Machine. As such we can use the rosjava libraries to interact with ROS.
Setup
Create a project just like in rosjava_tutorial_pubsub
Copy the build.gradle file from there, but make these modifications:
apply plugin: 'groovy' dependencies { compile 'ros.rosjava_core:rosjava:0.0.0-SNAPSHOT' compile 'ros.rosjava_core:rosjava_messages:0.0.0-SNAPSHOT' compile 'ros.rosjava_core:rosjava_bootstrap:0.0.0-SNAPSHOT' // Libraries required for groovy groovy group: 'org.codehaus.groovy', name: 'groovy', version: '2.0.0' }
The groovy version may be outdated by the time you read this tutorial.
Creating a Listener
We will create a simple Listener as in the Publisher / Subscriber rosjava Tutorial:
Copy / Create the file src/main/java/org/ros/rosjava_tutorial_pubsub/Talker.java, we will reuse the same Talker. You can also use the tutorial talker from c++ or python tutorials, of course.
Create this file as src/main/groovy/org/ros/rosgroovy_tutorial_pubsub/Listener.groovy:
package org.ros.rosgroovy_tutorial_pubsub import org.apache.commons.logging.Log; import org.ros.message.MessageListener; import org.ros.namespace.GraphName; import org.ros.node.AbstractNodeMain; import org.ros.node.ConnectedNode; import org.ros.node.NodeMain; import org.ros.node.topic.Subscriber; class Listener extends AbstractNodeMain { GraphName getDefaultNodeName() { new GraphName("rosjava_tutorial_pubsub/listener"); } void onStart(ConnectedNode connectedNode) { final log = connectedNode.getLog(); Subscriber<std_msgs.String> subscriber = connectedNode.newSubscriber("chatter", std_msgs.String._TYPE); subscriber.addMessageListener(new MessageListener<std_msgs.String>() { @Override void onNewMessage(std_msgs.String message) { log.info("I heard: \"${message.getData()}\""); } }); } }
The file must go there because that's where gradle picks up groovy files.
Note I am not an experienced Groovy programmer, so the code above might be ugly and too verbose for Groovy, it is a rather literal translation from the rosjava tutorial with just a bit of groovy syntax added.
build and run
To build, use gradle:
$ gradle installApp
To run, we use the same procedure as for rosjava:
$ roscore $ ./build/install/rosjava_wiki_tutorial_pubsub/bin/rosjava_wiki_tutorial_pubsub org.ros.rosjava_tutorial_pubsub.Talker $ ./build/install/rosjava_wiki_tutorial_pubsub/bin/rosjava_wiki_tutorial_pubsub org.ros.rosgroovy_tutorial_pubsub.Listener
Interactive usage
This section is for advanced users.
Groovy has two tools to code interactively, GroovyConsole and groovysh. The general problem is to set up the classpath for either.
GroovyConsole
GroovyConsole is relatively easy to start with gradle. In my case, what was required was this change to build.gradle:
dependencies { ... compile 'org.codehaus.groovy:groovy-all:2.0.0' } task(console, dependsOn: 'classes', type: JavaExec) { main = 'groovy.ui.Console' classpath = sourceSets.main.runtimeClasspath }
Then the following should work:
$ gradle console
groovysh
To run groovysh, I found it a bit more difficult to get the classpath right. First I extended the dependencies in build.gradle to:
dependencies { ... compile 'xerces:xercesImpl:2.9.1' compile 'org.apache.commons:commons-cli:1.3-SNAPSHOT' }
However I had to remove org.codehaus.groovy:groovy-all:2.0.0, due to some later conflicts.
Then, I ran
$ gradle installApp
This generates a shell script, in ./build/install/<project>/bin/<project>. The idea now is to copy the classpath section into a file. I created startgroovysh.sh
APP_HOME="`pwd -P`/build/install/rosgroovy_tutorials" CLASSPATH=$APP_HOME/lib/rosgroovy_tutorials-0.0.0-SNAPSHOT.jar:\ $APP_HOME/lib/xercesImpl-2.9.1.jar:\ $APP_HOME/lib/rosjava-0.0.0-SNAPSHOT.jar:\ $APP_HOME/lib/rosjava_messages-0.0.0-SNAPSHOT.jar:\ $APP_HOME/lib/rosjava_bootstrap-0.0.0-SNAPSHOT.jar:\ $APP_HOME/lib/commons-pool-1.6.jar:\ $APP_HOME/lib/jsr305-1.3.9.jar:\ $APP_HOME/lib/guava-12.0.jar:\ $APP_HOME/lib/com.springsource.org.apache.commons.lang-2.4.0.jar:\ $APP_HOME/lib/com.springsource.org.apache.commons.codec-1.3.0.jar:\ $APP_HOME/lib/com.springsource.org.apache.commons.io-1.4.0.jar:\ $APP_HOME/lib/netty-3.5.1.Final.jar:\ $APP_HOME/lib/com.springsource.org.apache.commons.logging-1.1.1.jar:\ $APP_HOME/lib/junit-3.8.2.jar:\ $APP_HOME/lib/xml-apis-1.0.b2.jar:\ $APP_HOME/lib/ws-commons-util-1.0.1.jar:\ $APP_HOME/lib/com.springsource.org.apache.commons.httpclient-3.1.0.jar:\ $APP_HOME/lib/apache_xmlrpc_common-0.0.0-SNAPSHOT.jar:\ $APP_HOME/lib/apache_xmlrpc_server-0.0.0-SNAPSHOT.jar:\ $APP_HOME/lib/apache_xmlrpc_client-0.0.0-SNAPSHOT.jar:\ $APP_HOME/lib/com.springsource.org.apache.commons.net-2.0.0.jar:\ $APP_HOME/lib/dnsjava-2.1.1.jar:\ $APP_HOME/lib/antlr-2.7.7.jar:\ $APP_HOME/lib/asm-4.0.jar:\ $APP_HOME/lib/asm-tree-4.0.jar:\ $APP_HOME/lib/asm-commons-4.0.jar:\ $APP_HOME/lib/asm-util-4.0.jar:\ $APP_HOME/lib/asm-analysis-4.0.jar:\ $APP_HOME/lib/commons-cli-1.3-SNAPSHOT.jar groovysh -cp $CLASSPATH
An alternative approach is to use the jar's for xercesImpl and commons-cli that gradle or maven download into your M2_REPO.
If you install the program mop, you can locate automate jar location like this:
$ mop classpath commons-cli:commons-cli:1.2
Either way, whenever you have run gradle installApp, the following session should work:
$ sh startgroovysh.sh groovy:000> import org.ros.rosgroovy_tutorial_pubsub.Listener groovy:000> import org.ros.node.DefaultNodeMainExecutor; groovy:000> import org.ros.node.NodeConfiguration; groovy:000> import org.ros.node.NodeMainExecutor; groovy:000> l = new Listener() groovy:000> nodeConfiguration = NodeConfiguration.newPrivate() groovy:000> nodeMainExecutor = DefaultNodeMainExecutor.newDefault() groovy:000> nodeMainExecutor.execute(l, nodeConfiguration)
This will spam the repl with the outputs of the listener, but you get the idea.