diff --git a/src/rosjava_actionlib/launch/test.launch b/src/rosjava_actionlib/launch/test.launch new file mode 100644 index 0000000000000000000000000000000000000000..909715b71be0405eb87b473f9837ef15cf9f7685 --- /dev/null +++ b/src/rosjava_actionlib/launch/test.launch @@ -0,0 +1,4 @@ +<launch> +<node pkg="actionlib_tutorials" type="fibonacci_server" name="fibonacci_server"/> +<test pkg="rosjava_actionlib" type="execute" test-name="rosjava_actionlib" args="com.github.ekumen.rosjava_actionlib.TestClient"/> +</launch> diff --git a/src/rosjava_actionlib/rosjava_actionlib/build.gradle b/src/rosjava_actionlib/rosjava_actionlib/build.gradle index 89829f89c0419a500f24f5770f60afe1125eda7d..5fbba5269834d55988109f5bf781dcf5753da57e 100644 --- a/src/rosjava_actionlib/rosjava_actionlib/build.gradle +++ b/src/rosjava_actionlib/rosjava_actionlib/build.gradle @@ -37,3 +37,15 @@ dependencies { compile 'org.ros.rosjava_messages:actionlib_tutorials:[0.1,)' } + +task deployApp(dependsOn: 'installApp') << { + File binDir = new File(project.projectDir, '/bin') + if (! binDir.isDirectory()) { + println "Creating $binDir directory" + binDir.mkdirs() + } + File link = new File(binDir,"execute") + File target = new File(project.projectDir, "build/install/$project.name/bin/$project.name") + println "Creating symlink from $link.absolutePath to $target.absolutePath" + ant.symlink(link: link.absolutePath, resource: target.absolutePath) +} diff --git a/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClient.java b/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClient.java index e198ddfd37505a77ba5e42ac387abfa642c78831..c4f00974c6ebe0400768b77c3bf1a42929ea6267 100644 --- a/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClient.java +++ b/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClient.java @@ -7,37 +7,86 @@ import org.ros.node.ConnectedNode; import org.ros.node.topic.Subscriber; import org.ros.node.topic.Publisher; import org.ros.message.MessageListener; -import org.ros.message.Message; +import org.ros.internal.message.Message; +import java.util.concurrent.TimeUnit; + +public class ActionClient<T_ACTION_GOAL extends Message, + T_ACTION_FEEDBACK extends Message, + T_ACTION_RESULT extends Message> { + + T_ACTION_GOAL actionGoal; + String actionGoalType; + String actionResultType; + String actionFeedbackType; + Publisher<T_ACTION_GOAL> goalPublisher = null; + //Publisher<actionlib_msgs.cancel> clientCancel; + //Suscriber<actionlib_msgs.status> serverStatus; + Subscriber<T_ACTION_RESULT> serverResult = null; + Subscriber<T_ACTION_FEEDBACK> serverFeedback = null; + ConnectedNode node = null; + String actionName; + ActionClientListener callbackTarget = null; + + ActionClient (ConnectedNode node, String actionName, String actionGoalType, + String actionFeedbackType, String actionResultType) { + this.node = node; + this.actionName = actionName; + this.actionGoalType = actionGoalType; + this.actionFeedbackType = actionFeedbackType; + this.actionResultType = actionResultType; -public class ActionClient extends AbstractNodeMain { + connect(node); + } - private string actionName = "fibonacci"; + public void attachListener(ActionClientListener target) { + callbackTarget = target; + } - //actionlib_tutorials.FibonacciActionGoal actionGoal; - Publisher<actionlib_tutorials.FibonacciActionGoal> clientGoal; - //Publisher<actionlib_msgs.cancel> clientCancel; - //Suscriber<actionlib_msgs.status> serverStatus; - Subscriber<actionlib_tutorials.FibonacciActionResult> serverResult; - //Suscriber<actionlib_tutorials.FibonacciActionFeedback> serverFeedback; + public void sendGoal(T_ACTION_GOAL goal) { + goalPublisher.publish(goal); + } void ActionClient(string actionName) { this.actionName = actionName; } private void publishClient(ConnectedNode node) { - clientGoal = node.newPublisher(actionName + "/goal", - actionlib_tutorials.FibonacciActionGoal._TYPE); + goalPublisher = node.newPublisher(actionName + "/goal", actionGoalType); //clientCancel = connectedNode.newPublisher("fibonacci/cancel", // actionlib_msgs.cancel._TYPE); } - private void suscribeToServer(ConnectedNode node) { - serverResult = node.newSubscriber(actionName + "/result", - actionlib_tutorials.FibonacciActionResult._TYPE); + private void unpublishClient() { + if (goalPublisher != null) { + goalPublisher.shutdown(5, TimeUnit.SECONDS); + } + } + + public T_ACTION_GOAL newGoalMessage() { + return goalPublisher.newMessage(); + } - serverResult.addMessageListener(new MessageListener<actionlib_tutorials.FibonacciActionResult>() { + private void subscribeToServer(ConnectedNode node) { + serverResult = node.newSubscriber(actionName + "/result", actionResultType); + serverFeedback = node.newSubscriber(actionName + "/feedback", actionFeedbackType); + + serverFeedback.addMessageListener(new MessageListener<T_ACTION_FEEDBACK>() { @Override - public void onNewMessage(actionlib_tutorials.FibonacciActionResult message) { + public void onNewMessage(T_ACTION_FEEDBACK message) { + gotFeedback(message); + } + }); + + serverResult.addMessageListener(new MessageListener<T_ACTION_RESULT>() { + @Override + public void onNewMessage(T_ACTION_RESULT message) { + gotResult(message); + } + }); + + serverResult.addMessageListener(new MessageListener<T_ACTION_RESULT>() { + @Override + public void onNewMessage(T_ACTION_RESULT message) { gotResult(message); } }); @@ -48,51 +97,43 @@ public class ActionClient extends AbstractNodeMain { actionlib_tutorials.FibonacciActionFeedback._TYPE);*/ } - public void gotResult(actionlib_tutorials.FibonacciActionResult message) { - actionlib_tutorials.FibonacciResult result = message.getResult(); - int[] sequence = result.getSequence(); - int i; - - System.out.print("Got Fibonacci result sequence! "); - for (i=0; i<sequence.length; i++) - System.out.print(Integer.toString(sequence[i]) + " "); - System.out.print("\n"); + private void unsubscribeToServer() { + if (serverFeedback != null) { + serverFeedback.shutdown(5, TimeUnit.SECONDS); + } + if (serverResult != null) { + serverResult.shutdown(5, TimeUnit.SECONDS); + } } -/** - * Publishes the client's topics and suscribes to the server's topics. - */ - public void connect(ConnectedNode node) { - publishClient(node); - //suscribeServer(node); + public void gotResult(T_ACTION_RESULT message) { + // Propagate the callback + if (callbackTarget != null) { + callbackTarget.resultReceived(message); + } } - @Override - public GraphName getDefaultNodeName() { - return GraphName.of("fibonacci_client"); + public void gotFeedback(T_ACTION_FEEDBACK message) { + // Propagate the callback + if (callbackTarget != null) { + callbackTarget.feedbackReceived(message); } + } - @Override - public void onStart(ConnectedNode node) { - connect(node); - - suscribeServer(node); - - // publish a goal message - actionlib_tutorials.FibonacciActionGoal goalMessage = clientGoal.newMessage(); - actionlib_tutorials.FibonacciGoal fibonacciGoal = goalMessage.getGoal(); - // set Fibonacci parameter - fibonacciGoal.setOrder(6); - goalMessage.setGoal(fibonacciGoal); + /** + * Publishes the client's topics and suscribes to the server's topics. + */ + private void connect(ConnectedNode node) { + publishClient(node); + subscribeToServer(node); + } - while (true) { - clientGoal.publish(goalMessage); - try { - Thread.sleep(10000); - } - catch (InterruptedException ex) { - ; - } - } + /** + * Finish the action client. Unregister publishers and listeners. + */ + public void finish() { + callbackTarget = null; + unpublishClient(); + unsubscribeToServer(); } } diff --git a/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClientListener.java b/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClientListener.java index c3453a811896c4c90785b2f9326cd6aa1f34edb1..680c731ddcecaa5fbeff3963e632f7976a8d19ee 100644 --- a/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClientListener.java +++ b/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/ActionClientListener.java @@ -4,9 +4,11 @@ import org.ros.internal.message.Message; /** * Listener interface to receive the incoming messages from the ActionLib server. + * A client should implement this interface if it wants to receive the callbacks + * with information from the server. */ -public interface ActionClientListener { - void resultReceived(Message result); - void feedbackReceived(Message feedback); +public interface ActionClientListener<T_ACTION_FEEDBACK extends Message, T_ACTION_RESULT extends Message> { + void resultReceived(T_ACTION_RESULT result); + void feedbackReceived(T_ACTION_FEEDBACK feedback); void statusReceived(Message status); } diff --git a/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/TestClient.java b/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/TestClient.java new file mode 100644 index 0000000000000000000000000000000000000000..919ce66a9125bfebe08e402ba03935559ba3abf7 --- /dev/null +++ b/src/rosjava_actionlib/rosjava_actionlib/src/main/java/com/github/ekumen/rosjava_actionlib/TestClient.java @@ -0,0 +1,99 @@ +package com.github.ekumen.rosjava_actionlib; + +import org.ros.namespace.GraphName; +import org.ros.node.AbstractNodeMain; +import org.ros.node.ConnectedNode; +import org.ros.internal.message.Message; +import actionlib_tutorials.FibonacciActionGoal; +import actionlib_tutorials.FibonacciActionFeedback; +import actionlib_tutorials.FibonacciActionResult; +import actionlib_tutorials.FibonacciGoal; +import actionlib_tutorials.FibonacciFeedback; +import actionlib_tutorials.FibonacciResult; + +public class TestClient extends AbstractNodeMain implements ActionClientListener<FibonacciActionFeedback, FibonacciActionResult> { + ActionClient ac; + volatile private boolean responded = false; + + @Override + public GraphName getDefaultNodeName() { + return GraphName.of("fibonacci_test_client"); + } + + @Override + public void onStart(ConnectedNode node) { + ac = new ActionClient<FibonacciActionGoal, FibonacciActionFeedback, FibonacciActionResult>(node, "/fibonacci", FibonacciActionGoal._TYPE, FibonacciActionFeedback._TYPE, FibonacciActionResult._TYPE); + int repeat = 3; + + // Attach listener for the callbacks + ac.attachListener(this); + + // publish a goal message + FibonacciActionGoal goalMessage = (FibonacciActionGoal)ac.newGoalMessage(); + FibonacciGoal fibonacciGoal = goalMessage.getGoal(); + + // set Fibonacci parameter + fibonacciGoal.setOrder(6); + goalMessage.setGoal(fibonacciGoal); + + while(repeat > 0) { + sleep(1000); + System.out.println("Sending goal #" + repeat + "..."); + ac.sendGoal(goalMessage); + System.out.println("Goal sent."); + repeat--; + } + + while (repeat > 0) { + responded = false; + ac.sendGoal(goalMessage); + while (!responded) { + } + repeat--; + } + + System.out.println("Finishing node!!"); + sleep(30000); + ac.finish(); + node.shutdown(); + } + + @Override + public void resultReceived(FibonacciActionResult message) { + FibonacciResult result = message.getResult(); + int[] sequence = result.getSequence(); + int i; + + responded = true; + + System.out.print("Got Fibonacci result sequence! "); + for (i=0; i<sequence.length; i++) + System.out.print(Integer.toString(sequence[i]) + " "); + System.out.print("\n"); + } + + @Override + public void feedbackReceived(FibonacciActionFeedback message) { + FibonacciFeedback result = message.getFeedback(); + int[] sequence = result.getSequence(); + int i; + + System.out.print("Feedback from Fibonacci server: "); + for (i=0; i<sequence.length; i++) + System.out.print(Integer.toString(sequence[i]) + " "); + System.out.print("\n"); + } + + @Override + public void statusReceived(Message status) { + + } + + private void sleep(long msec) { + try { + Thread.sleep(msec); + } + catch (InterruptedException ex) { + } + } +}