ROS-I simple_message 源码分析:SimpleMessage

概述

SimpleMessage类定义了ROS的驱动层(也就是我们写的client node)和机器人控制器之间的通信协议,说白了就是定义了交互消息的数据格式。这个协议满足了ROS-I定义的如下4个要求:

  • 格式要足够的简单,协议代码能够在ROS端和控制器端共享,当然这个是针对支持C/C++的控制器。对于不支持C/C++的控制器,则必须要保证能够使用机器人编程语言来处理消息。也就是说如果协议太复杂的话,有限的控制器资源会难以处理。
  • 要允许数据流,类似ROS topic
  • 要允许数据回复,类似ROS service
  • 协议不会封装版本信息,也就是说开发者要自己负责统一ROS端和控制器端之间的协议版本

协议格式

SimpleMessage协议定义了消息的前缀(PREFIX)、消息头(HEADER)和消息体(BODY)

  • PREFIX
    (长度1个字节)
    LENGTH域,int数据类型,代表(HEADER + DATA)的字节长度
  • HEADER
    (长度3个字节)
    MSG_TYPE域,int数据类型,代表了消息的类型,包括标准消息和厂商自定义的消息类型
    COMM_TYPE域,int数据类型,代表了通信的类型
    REPLY CODE域,int数据类型,代表回复代号,仅在服务回复时有效
  • BODY
    (变长)
    DATA域,ByteArray数据类型,代表由消息类型和服务类型决定的可变长度的数据

源代码

对着以上的定义,我们来看看源代码长的什么样:

namespace industrial
{

namespace simple_message
{

namespace StandardMsgTypes
{
  enum StandardMsgType
  {
   INVALID = 0,
   PING = 1,

   JOINT_POSITION = 10,
   JOINT = 10, 
   READ_INPUT = 20,
   WRITE_OUTPUT = 21,

   JOINT_TRAJ_PT = 11,  //Joint trajectory point message (typically for streaming)
   JOINT_TRAJ = 12,   //Joint trajectory message (typically for trajectory downloading)
   STATUS = 13,                //Robot status message (for reporting the robot state)
   JOINT_TRAJ_PT_FULL = 14,  // Joint trajectory point message (all message fields)
   JOINT_FEEDBACK = 15,      // Feedback of joint pos/vel/accel


   SWRI_MSG_BEGIN     = 1000,
   UR_MSG_BEGIN       = 1100,
   ADEPT_MSG_BEGIN    = 1200,
   ABB_MSG_BEGIN      = 1300,
   FANUC_MSG_BEGIN    = 1400,
   MOTOMAN_MSG_BEGIN  = 2000
  };
}
typedef StandardMsgTypes::StandardMsgType StandardMsgType;


namespace CommTypes
{
  enum CommType
  {
   INVALID = 0,
   TOPIC = 1,
   SERVICE_REQUEST = 2,
   SERVICE_REPLY = 3
  };
}
typedef CommTypes::CommType CommType;

namespace ReplyTypes
{
  enum ReplyType
  {
 INVALID = 0,
 SUCCESS = 1,
 FAILURE = 2
  };
}
typedef ReplyTypes::ReplyType ReplyType;


class SimpleMessage
{

public:
  SimpleMessage();
  ~SimpleMessage(void);
  bool init(int msgType, int commType, int replyCode);
  bool init(industrial::byte_array::ByteArray & msg);
  void toByteArray(industrial::byte_array::ByteArray & msg);
  static unsigned int getHeaderSize() { return SimpleMessage::HEADER_SIZE; };
  static unsigned int getLengthSize() { return SimpleMessage::LENGTH_SIZE; };
  int getMessageType() {return this->message_type_;};
  int getCommType() {return this->comm_type_;};
  int getReplyCode() {return this->reply_code_;};
  int getMsgLength() {return this->getHeaderSize() + this->data_.getBufferSize();};
  int getDataLength() {return this->data_.getBufferSize();};
  industrial::byte_array::ByteArray & getData() {return this->data_;};
  bool validateMessage();

private:
  industrial::shared_types::shared_int message_type_;
  industrial::shared_types::shared_int comm_type_;
  industrial::shared_types::shared_int reply_code_;
  industrial::byte_array::ByteArray data_;
  static const unsigned int HEADER_SIZE = sizeof(industrial::shared_types::shared_int) +
        sizeof(industrial::shared_types::shared_int) +
        sizeof(industrial::shared_types::shared_int);
  static const unsigned int LENGTH_SIZE = sizeof(industrial::shared_types::shared_int);
  void setMessageType(int msgType) {this->message_type_ = msgType;};
  void setCommType(int commType) {this->comm_type_ = commType;};
  void setReplyCode(int replyCode) {this->reply_code_ = replyCode;};
  void setData(industrial::byte_array::ByteArray & data);
};

}//namespace simple_message
}//namespace industrial

这个头文件在定义SimpleMessage类之前,定义了一些枚举类型,包括:

  • StandardMsgType
    代表了标准消息的ID号,所有的控制器应当支持这些消息类型,以及比如ABB,UR这些机器人厂商定义的消息类型,厂商可以定义多达100种消息类型。标准消息类型包括16种(不包括vendor specific的):
    INVALID,PING,JOINT_POSITION,JOINT,READ_INPUT,WRITE_OUTPUT,JOINT_TRAJ_PT,JOINT_TRAJ,STATUS,JOINT_TRAJ_PT_FULL,JOINT_FEEDBACK

  • CommType
    代表通信类型,包含INVALID,TOPIC,SERVICE_REQUEST,SERVICE_REPLY四种

  • ReplyType
    代表回复类型,包括INVALID,SUCCESS和FAILURE三种

有了前面的铺垫,我们开始分析SimpleMessage的实现。
首先看以下它的private数据,包括:message_type_,comm_type_,reply_code_,data_。显而易见,这些私有数据成员与协议格式中定义的HEADER和BODY部分是对应的。与之对应的提供了一些set方法,用于填充消息的各个段:

//设置消息类型ID号
void setMessageType(int msgType) {this->message_type_ = msgType;};
//设置通信类型
void setCommType(int commType) {this->comm_type_ = commType;};
//设置回复码
void setReplyCode(int replyCode) {this->reply_code_ = replyCode;};
//设置数据域
void setData(industrial::byte_array::ByteArray & data);

对应的,提供了get方法获取消息的各个段:

 int getMessageType() {return this->message_type_;};
 int getCommType() {return this->comm_type_;};
 int getReplyCode() {return this->reply_code_;};
 int getDataLength() {return this->data_.getBufferSize();};

下面看以下init初始化方法:

bool init(int msgType, int commType, int replyCode, industrial::byte_array::ByteArray &data );

init方法的参数就是消息的四个段,实现的功能就是用输入的四个参数填充内部数据,并验证消息格式是否有效,从而创建完整的消息。以下消息被认为是无效的,不可封装为消息:

  • commType是SERVICE_REPLY,而回复码是INVALID
  • commType不是SERVICE_REPLY,而回复码不是INVALID(即回复码竟然有效)
bool init(int msgType, int commType, int replyCode);

init重载版本,根据参数填充消息类型,通信类型,回复码,创建的消息数据域为空

bool init(industrial::byte_array::ByteArray & msg);

init重载版本,调用这个方法的前提是参数msg中包含了消息头或消息头+数据,在内部通过调用unload来卸载msg中的字节数据,填充到SimpleMessage的各个消息段中。

void toByteArray(industrial::byte_array::ByteArray & msg);

toByteArray方法用于向ByteArray类型的msg加载数据,注意的是在加载前,会首先清空ByteArray。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354