学习笔记之——ROS-Android

50 篇文章 13 订阅

之前博客《ROS学习笔记之——基于ROS的Android开发》和《ROS学习笔记之——ROSAndroid 与 rosjava》已经介绍过ROS-Android的一些学习资料,本博文再深入的学习一下

 

目录

rosjava

创建一个节点

NodeConfiguration

GraphName

ConnectedNode

发布者与订阅者

rosandroid

RosActivity

需要添加的权限

参考资料


 

rosjava

rosjava是ROS纯java的实现,它提供了一个客户端库,使Java程序员可以快速与ROS主题,服务和参数进行交互。甚至可以通过java实现roscore.

关于rosjava更多细节可以参考:http://rosjava.github.io/rosjava_core/latest/javadoc/index.html

由于ROS严重依赖于网络通信,因此rosjava是异步的。

 

一般而言,java包需要采用反向域名的形式,如下所示:

  • org.ros.rosjava
  • org.ros.rosjava_geometry

创建一个节点

通常,ROS节点与进程同步,然而,在rosjava中,节点更像nodelet,因为许多节点可以在单个进程Java VM中运行。

用户不会创建节点。 而是将程序定义为NodeMain的实现,由适当命名的NodeMainExecutor执行。如下所示

import org.ros.namespace.GraphName;
import org.ros.node.Node;
import org.ros.node.NodeMain;

public class MyNode implements NodeMain {

  @Override
  public GraphName getDefaultNodeName() {//返回节点的默认名字。该名字会一直被使用,除非在NodeConfiguration中被重新设置
    return new GraphName("my_node");//当rosjava指向node,topic或者parameters的时候,会采用GraphName
  }

  @Override
  public void onStart(ConnectedNode node) {//此处是输入代码的,就是开始节点了。参数ConnectedNode是用于构建发布者与订阅者
  }

  @Override
  public void onShutdown(Node node) {//离开代码,应该用于关闭所有的发布者订阅者
  }

  @Override
  public void onShutdownComplete(Node node) {//最后的退出程序的点
  }

  @Override
  public void onError(Node node, Throwable throwable) {//报错的时候调用
  }
}

NodeConfiguration

http://rosjava.github.io/rosjava_core/latest/javadoc/org/ros/node/NodeConfiguration.html#

Java NodeConfiguration.setNodeName方法代碼示例:https://vimsky.com/zh-tw/examples/detail/java-method-org.ros.node.NodeConfiguration.setNodeName.html

GraphName

http://rosjava.github.io/rosjava_core/latest/javadoc/org/ros/namespace/GraphName.html#

ConnectedNode

http://rosjava.github.io/rosjava_core/latest/javadoc/org/ros/node/ConnectedNode.html#

 

发布者与订阅者

关于ROS中,通过C++创建发布者与订阅者,可以参考博文《ROS复习笔记之——系统框架及其编程规范

下面例子中,创建一个发布者来发布chatter topic。发布者将消息std_msgs.String发布到/chatter话题上。部分理解写代码的注释中了~

package org.ros.rosjava_tutorial_pubsub;

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;

/**
 * A simple {@link Publisher} {@link NodeMain}.
 * 
 * @author damonkohler@google.com (Damon Kohler)
 */
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("chatter", std_msgs.String._TYPE);//定义发布的话题的名字以及其消息类型 

    // This CancellableLoop will be canceled automatically when the node shutsdown.
    // 这个Talker节点的目的是每秒发布一次hello world消息,因此是通过循环的发布与休眠来实现的
    //故此创建一个CancellableLoop来实现
    connectedNode.executeCancellableLoop(new CancellableLoop() {
      private int sequenceNumber;

      @Override
      protected void setup() {
        sequenceNumber = 0;
      }

      @Override
      protected void loop() throws InterruptedException {
        std_msgs.String str = publisher.newMessage();//创建消息
        str.setData("Hello world! " + sequenceNumber);//设置发布的消息的内容
        publisher.publish(str);//发布者发布消息
        sequenceNumber++;//记录第几次发布
        Thread.sleep(1000);//休眠1000ms
      }
    });
  }
}

接下来创建一个订阅者

package org.ros.rosjava_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;

/**
 * A simple {@link Subscriber} {@link NodeMain}.
 * 
 * @author damonkohler@google.com (Damon Kohler)
 */
public class Listener extends AbstractNodeMain {

  @Override
  public GraphName getDefaultNodeName() {
    return GraphName.of("rosjava_tutorial_pubsub/listener");//定义发布者节点的名字
  }

  @Override
  public void onStart(ConnectedNode connectedNode) {
    final Log log = connectedNode.getLog();
    Subscriber<std_msgs.String> subscriber = connectedNode.newSubscriber("chatter", std_msgs.String._TYPE);//创建一个订阅者,对应的要填入话题的名称以及消息的类型

    //对于订阅者节点,可以加多个MessageListener
    //当一个新的消息接收到后,所有的MessageListener将会被回调,以传入的消息作为参数调用 MessageListener.onNewMessage
    subscriber.addMessageListener(new MessageListener<std_msgs.String>() {
      @Override
      public void onNewMessage(std_msgs.String message) {
        log.info("I heard: \"" + message.getData() + "\"");
      }
    });
  }
}

而至于服务与参数,可以参考:http://rosjava.github.io/rosjava_core/latest/getting_started.html

 

rosandroid

android_core提供了安卓的库给编写ROS app。故此从某种程度上而已,rosandroid就说一个让ros可以使用一些Android应用的库

RosActivity

RosActivity是所以基于ROS的安卓应用的基类。

对于继承RosActivity的activity,在其开始时,其super class将会

  • 在前台开启NodeMainExecutorService服务
  • 登录MasterChooser活动,提示用户配置主URI
  • 显示正在进行的通知,通知用户ROS节点正在后台运行

如下所示

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;


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);//获取layout
    rosTextView = (RosTextView<std_msgs.String>) findViewById(R.id.text);//id
    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();
      }
    });
  }


//父类定义了RosActivity.init的抽象方法,故此需要重写
  @Override
  protected void init(NodeMainExecutor nodeMainExecutor) {//这是启动所编写的节点及其他逻辑的地方
    talker = new Talker();//前面定义过了talker

    // 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.

    // The user can easily use the selected ROS Hostname in the master chooser
    // activity.
    NodeConfiguration nodeConfiguration = NodeConfiguration.newPublic(getRosHostname());
    nodeConfiguration.setMasterUri(getMasterUri());
    nodeMainExecutor.execute(talker, nodeConfiguration);//执行talker节点
    // The RosTextView is also a NodeMain that must be executed in order to
    // start displaying incoming messages.
    nodeMainExecutor.execute(rosTextView, nodeConfiguration);
  }
}

 

需要添加的权限

在AndroidManifest.xml中添加

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

在<application>添加

<service android:name="org.ros.android.NodeMainExecutorService" >
    <intent-filter>
        <action android:name="org.ros.android.NodeMainExecutorService" />
    </intent-filter>
</service>

 

 

 

参考资料

https://github.com/rosjava/rosjava_core

http://rosjava.github.io/rosjava_core/latest/

http://rosjava.github.io/android_core/latest/

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值