上篇笔记记录了如何使用RosBridge连接Ros机器人,这篇主要记录话题的订阅。本想地图数据订阅和绘制slam地图一起放上来,但绘制地图代码块有点多,就放在下一篇,仅放置绘制的slam地图。
话题订阅
关于Ros话题(Topic)的发布与订阅概述或者介绍不多描述。知道Ros机器人端发布话题,Android端通过订阅这个话题来获取数据,并且数据是以JSON格式进行传递就OK了。
/**
* 获取地图数据 的话题订阅
*/
public void subscribeGetMapDataTopic() {
MessageHandler<OccupancyGrid> handler =new MessageHandler<OccupancyGrid>() {
@Override
public void onMessage(OccupancyGrid message) {
if (message != null) {
occupancyGrid = message;
}
}
};
// "/map"代表话题名称,双方约定好。
Topic<OccupancyGrid> mapDateTopic = new Topic<>("/map", OccupancyGrid.class, client);
mapDateTopic.subscribe(handler);
}
OccupancyGrid 地图数据类,
public class OccupancyGrid extends Message {
/**
* 时间戳信息
*/
public Header header;
/**
*地图的一些基本信息,宽高、分辨率
*/
public MapMetaData info;
/**
* 地图数据
*/
public byte[] data;
}
Topic类封装了话题订阅、取消订阅及数据 回调方法
public class Topic<T extends Message> extends LinkedBlockingQueue<T> implements FullMessageHandler {
protected String topic;
private Class<? extends T> type;
private String messageType;
private ROSClient client;
private Thread handlerThread;
public Topic(String topic, Class<? extends T> type, ROSClient client) {
this.topic = topic;
this.client = client;
this.type = type;
messageType = Message.getMessageType(type);
handlerThread = null;
}
@Override
public void onMessage(String id, Message message) {
add((T) message);
}
// warning: there is a delay between the completion of this method and
// the completion of the subscription; it takes longer than
// publishing multiple other messages, for example.
public void subscribe(MessageHandler<T> handler) {
startRunner(handler);
subscribe();
}
public void subscribe() {
client.register(Publish.class, topic, type, this);
send(new Subscribe(topic, messageType));
}
public void unsubscribe() {
// need to handle race conditions in incoming message handler
// so that once unsubscribe has happened the handler gets no more
// messages
send(new Unsubscribe(topic));
client.unregister(Publish.class, topic);
stopRunner();
}
private void startRunner(MessageHandler<T> handler) {
stopRunner();
handlerThread = new Thread(new MessageRunner(handler));
handlerThread.setName("Message handler for " + topic);
handlerThread.start();
}
private void stopRunner() {
if (handlerThread != null) {
handlerThread.interrupt();
clear();
handlerThread = null;
}
}
public void advertise() {
send(new Advertise(topic, messageType));
}
public void publish(T message) {
advertise();
send(new Publish(topic, message));
unadvertise();
}
public void unadvertise() {
send(new Unadvertise(topic));
}
private void send(Operation operation) {
client.send(operation);
}
public void verify() throws InterruptedException {
boolean hasTopic = false;
for (String s : client.getTopics()) {
if (s.equals(topic)) {
hasTopic = true;
break;
}
}
if (!hasTopic)
throw new RuntimeException("Topic \'" + topic + "\' not available.");
client.typeMatch(client.getTopicMessageDetails(topic), type);
}
private class MessageRunner implements Runnable {
private MessageHandler<T> handler;
public MessageRunner(MessageHandler<T> handler) {
this.handler = handler;
}
@Override
public void run() {
while (!Thread.interrupted()) {
try {
handler.onMessage(take());
}
catch (InterruptedException ex) {
break;
}
}
}
}
}