【笔记】Android上ROS开发——android_core创建一个android应用
前面已经讲了很多android_core,rosjava的介绍,如果你配置好了android_core,接下来就可以开发rosjava-android程序了。
首先在eclipse下创建一个android程序,然后使用RosActivity,下面给出官方范例详细介绍。
RosActivity是所有ROS Android应用的基本类,我们给出android_tutorial_pubsub来介绍如何写最基本ROS的Publisher和Subscriber。当学会Publisher和Subscriber也就相当于学会ROSjava一大半了,因为ROS机器人的所有行为都是建立在信息的发送与订阅的基础上。
原始地址来自:http://docs.rosjava.googlecode.com/hg/android_core/html/getting_started.html
package org.ros.android.android_tutorial_pubsub;import android.os.Bundle;import org.ros.android.MessageCallable;import org.ros.android.RosActivity;import org.ros.android.view.RosTextView;import org.ros.node.NodeConfiguration;import org.ros.node.NodeMainExecutor;import org.ros.rosjava_tutorial_pubsub.Talker;/** * @author damonkohler@google.com (Damon Kohler) */public class MainActivity extends RosActivity { private RosTextView<std_msgs.String> rosTextView; private Talker talker; public MainActivity() { // The RosActivity constructor configures the notification title and ticker // messages. super("Pubsub Tutorial", "Pubsub Tutorial"); } @SuppressWarnings("unchecked") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); rosTextView = (RosTextView<std_msgs.String>) findViewById(R.id.text); rosTextView.setTopicName("chatter"); rosTextView.setMessageType(std_msgs.String._TYPE); rosTextView.setMessageToStringCallable(new MessageCallable<String, std_msgs.String>() { @Override public String call(std_msgs.String message) { return message.getData(); } }); } @Override protected void init(NodeMainExecutor nodeMainExecutor) { talker = new Talker(); NodeConfiguration nodeConfiguration = NodeConfiguration.newPrivate(); // At this point, the user has already been prompted to either enter the URI // of a master to use or to start a master locally. nodeConfiguration.setMasterUri(getMasterUri()); nodeMainExecutor.execute(talker, nodeConfiguration); // The RosTextView is also a NodeMain that must be executed in order to // start displaying incoming messages. nodeMainExecutor.execute(rosTextView, nodeConfiguration); }}在第14行,我们需要extends RosActivity。这样当activity启动时:
1.在前台启动NodeMainExecutorService
2.开始一个MasterChooseractivity来提示用户填写master URI,并且显示正在进行的通告信息通知用户ROS节点正在后台运行。
第22行的超构造函数中,两个字符串是Android通告的标题和断续器信息。用户只需要关闭这个通告就可以关闭与该应用联系的所有ROS节点。
第28-30行,android开发者都熟悉。
第42行我们定义抽象函数RosActivity.init,这里我们开始了NodeMain。与用户填写的masterURI建立连接,执行talker发布信息,执行rosTextView显示输入信息。而且这里RosAcitivity操纵着其他应用的生命周期的管理,包括:
1.获取和释放WakeLocks和WifiLocks
2.捆绑或者松绑NodeMainExecutorService
3.当应用关闭时结束NodeMain
看完上面的代码,其实我们应该明白具体怎么发送信息关键在于Talker类,下面就来段代码解释下
package rosjava.wtf.pocketsphinx.version1;import org.ros.concurrent.CancellableLoop;import org.ros.namespace.GraphName;import org.ros.node.AbstractNodeMain;import org.ros.node.ConnectedNode;import org.ros.node.topic.Publisher;public class Talker extends AbstractNodeMain { @Override public GraphName getDefaultNodeName() { return GraphName.of("rosjava_tutorial_pubsub/talker"); } @Override public void onStart(final ConnectedNode connectedNode) { final Publisher<std_msgs.String> publisher = connectedNode.newPublisher("recognizer/output", std_msgs.String._TYPE); // This CancellableLoop will be canceled automatically when the node shuts // down. connectedNode.executeCancellableLoop(new CancellableLoop() { @Override protected void setup() { } @Override public void loop() throws InterruptedException { std_msgs.String str = publisher.newMessage(); str.setData( TalkParam.tmpstring ); publisher.publish(str); Thread.sleep(250); } }); }}第9行,需要extendsAbstractNodeMain。第19-20行,我们设置信息格式为std_msgs.String._TYPE,这个是发送字符串信息,发送给recognizer/output主题,这两点是publisher的关键。
后面就是进入loop()循环发送信息。补充下,控制电机的信息选用geometry_msgs/Twist格式,控制舵机的选用sensor_msgs/JointState格式,后续文章会详细提到。
接下来描述下subscribe。这个android_core堆提供了许多Android实现NodeMain的视图方法。例如,我们接下来要看的RosTextView的实现。这个视图的目的就是用文本表示发布的消息并显示。
package org.ros.android.view;import android.content.Context;import android.util.AttributeSet;import android.widget.TextView;import org.ros.android.MessageCallable;import org.ros.message.MessageListener;import org.ros.namespace.GraphName;import org.ros.node.ConnectedNode;import org.ros.node.Node;import org.ros.node.NodeMain;import org.ros.node.topic.Subscriber;/** * @author damonkohler@google.com (Damon Kohler) */public class RosTextView<T> extends TextView implements NodeMain { private String topicName; private String messageType; public void setTopicName(String topicName) { this.topicName = topicName; } public void setMessageType(String messageType) { this.messageType = messageType; } public void setMessageToStringCallable(MessageCallable<String, T> callable) { this.callable = callable; } @Override public GraphName getDefaultNodeName() { return new GraphName("android_gingerbread/ros_text_view"); } @Override public void onStart(ConnectedNode connectedNode) { Subscriber<T> subscriber = connectedNode.newSubscriber(topicName, messageType); subscriber.addMessageListener(new MessageListener<T>() { @Override public void onNewMessage(final T message) { if (callable != null) { post(new Runnable() { @Override public void run() { setText(callable.call(message)); } }); } else { post(new Runnable() { @Override public void run() { setText(message.toString()); } }); } postInvalidate(); } }); } @Override public void onShutdown(Node node) { } @Override public void onShutdownComplete(Node node) { } @Override public void onError(Node node, Throwable throwable) { }}这个视图已经配置了主 题topicName和信息格式messageType以及MessageCallable。 在40行的 NodeMain.onStart 类函数中,我们创建一个Subscriber来订阅已经配置的主题和信息格式。
在49行我们将新接收到的信息转变成一个字符串。如果没有收到信息,就像56行,我们就使用默认的toString(),然后发送文本到视图上来显示收到的信息。
就像其他NodeMain一样,RosTextView被NodeMainExecutor执行。在上述RosActivity示例中,我们在RosActivity.init中执行了它,并且使用它在Talker节点中显示传入的消息。
by:season
更多相关文章
- Android(安卓)打印日志封装库
- android 读取 AndroidManifest.xml 中的数据:版本号、应用名称、
- view的几种布局方式及实践
- [Android进阶]Android(安卓)开发最佳实践
- [SL4A]获取IMEI信息
- Android(安卓)Activity堆栈信息
- Android导入导出txt通讯录工具(源码共享)
- Android(安卓)开发笔记4-- 常用控件
- Android开发之Activity转场动画