I'm trying to set up a simple publisher using rosjava (pure java, I don't need Android). I've been following some tutorials and making lots of progress, but now I'm stuck. Here is the code I have so far:
import org.ros.concurrent.CancellableLoop;
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.Publisher;
import org.ros.node.NodeConfiguration;
import org.ros.node.Node;
import org.ros.internal.node.DefaultNode;
import org.ros.node.DefaultNodeFactory;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
public class Publisher_Test {
private DefaultNode node;
//private Publisher<std_msgs.String> publisher;
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public Publisher_Test() {
NodeConfiguration node_cfg = NodeConfiguration.newPrivate();
DefaultNodeFactory factory = new DefaultNodeFactory( scheduler );
node = (DefaultNode)factory.newNode( node_cfg );
System.out.println("In Constructor");
final Publisher<std_msgs.String> publisher = node.newPublisher("chatter", std_msgs.String._TYPE);
node.executeCancellableLoop( new CancellableLoop() {
private int seq;
@Override
protected void setup() {
seq=0;
System.out.println("Setting up loop");
}
@Override
protected void loop() throws InterruptedException {
System.out.println("Looping");
try {
while (true) {
org.ros.message.std_msgs.String();
std_msgs.String str = publisher.newMessage();
str.setData( "Hello world! " + seq++ );
publisher.publish(str);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
I've been basing this off of this question and this tutorial. Some of the syntax used is out of data, so I've been looking through the source code here to get things to compile.
I'm using ROS Hydro on an Ubuntu 13.04 machine. My goal is to get a publisher and subscriber implemented in pure java running in jython. I've compiled my class using javac, and can import it into jython fine, I get an error when I try to set up my node in the constructor for Publisher_Test:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
at org.ros.concurrent.ListenerGroup.addAll(ListenerGroup.java:85)
at org.ros.concurrent.ListenerGroup.addAll(ListenerGroup.java:101)
at org.ros.internal.node.DefaultNode.<init>(DefaultNode.java:132)
at org.ros.node.DefaultNodeFactory.newNode(DefaultNodeFactory.java:41)
at org.ros.node.DefaultNodeFactory.newNode(DefaultNodeFactory.java:46)
at Publisher_Test.<init>(Publisher_Test.java:31)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.python.core.PyReflectedConstructor.constructProxy(PyReflectedConstructor.java:210)
java.lang.NullPointerException: java.lang.NullPointerException
From what I understand so far, it looks like DefaultNodeFactory is setting up the DefaultNode with the Collection to be null (which looking at the source code seems to be a valid thing to do), and then the addAll() method which is called in the DefaultNode constructor throws this exception when it tries to iterate on null.
I'm thinking I need to give a Listener to the DefaultNodeFactory, but I am unsure how I would go about doing this. What is a Listener and what is it supposed to do/represent? Is there a way to create a default one to use?
I am new to java, so any help would be very appreciated
Thanks!
EDIT 1
I've tried the to get the rosjava_tutorial_pubsub working, by following the package creation steps here. I'm able to build it using ./gradlew install (installApp doesn't exist), but I can't seem to figure out how to run it (there is no .build directory created, which the tutorial uses)
Ideally I would like to not have to create any packages or workspaces or use gradle at all, as I find it much easier to work that way and integrate the code into other projects. I know for rospy you can just do something simple like this:
# my_program.py
import rospy
from std_msgs.msg import Int32
def int_callback( data ):
print( 'I saw the number %' % data.data )
def main():
rospy.init_node( 'name', anonymous=True )
sub = rospy.Subscriber( 'root/my_topic', Int32, int_callback )
pub = rospy.Publisher( 'root/my_other_topic', Int32 )
msg = Int32()
i = 0
while not rospy.is_shutdown():
msg.data = i
i += 1
pub.publish( msg )
and this will be able to work no matter what directory you place it in, by just running python my_program.py
and doesn't need to be part of a workspace or package.
What I'm really looking for is some equivalent of this for java. I want to compile a class that handles publishing and subscribing, and then just import that class into another program and use it there.
Does this make sense? Let me know if I am crazy and doing something dumb. I think the java code above is almost there, except for the part about the Listeners.
EDIT 2
I've made it a little further now, everything compiles, but when I run it, I don't see anything happen. I have roscore
running in another terminal, and when I do a rostopic list
all I get is /rosout
and /rosout_agg
.
The changes I made to get it to compile are as follows:
- made the class extend AbstractNodeMain
- added a getDefaultNodeName() function to the class
- set the default node name of the NodeConfiguration to "publisher_test"
- added the class itself as a listener to the new node that is created
Here is the relevant bits of the new code. I see the "In Constructor" print show up, but not any of the other ones
// Imports go here
public class Publisher_Test extends AbstractNodeMain {
private DefaultNode node;
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public Publisher_Test() {
NodeConfiguration node_cfg = NodeConfiguration.newPrivate();
node_cfg.setDefaultNodeName( "publisher_test" );
DefaultNodeFactory factory = new DefaultNodeFactory( scheduler );
//node = (DefaultNode)factory.newNode( node_cfg );
List<NodeListener> listener = new ArrayList<NodeListener>();
listener.add( this );
node = (DefaultNode)factory.newNode( node_cfg, listener );
final Publisher<std_msgs.String> publisher = node.newPublisher("chatter", std_msgs.String._TYPE);
System.out.println("In Constructor");
node.executeCancellableLoop( new CancellableLoop() {
private int seq;
@Override
protected void setup() {
seq=0;
System.out.println("Setting up loop");
}
@Override
protected void loop() throws InterruptedException {
System.out.println("Looping");
try {
while (true) {
std_msgs.String str = publisher.newMessage();
str.setData( "Hello world! " + seq++ );
publisher.publish(str);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
public GraphName getDefaultNodeName() {
return GraphName.of("publisher_test");
}
}
My guess is after the constructor is finished, this CancellableLoop thing just gets destroyed. I've tried inside an onStart()
method, but that didn't work either. I've also tried putting the loop directly into the contructor (in which case it just stays stuck in the loop, and nothing seems to get published). The last thing I tried is to put the loop in a separate method, to let the constructor finish first, and then I call it. Still no luck :(
Any idea what might be going on?
Originally posted by Albatross on ROS Answers with karma: 157 on 2013-11-14
Post score: 1