C++ 远程读写结构

C++ 远程读写结构,c++,struct,embedded,arm,protocol-buffers,C++,Struct,Embedded,Arm,Protocol Buffers,我目前正在建造一个机器人,上面有一些传感器。机器人上的控制单元是一个手臂Cortex-M3,所有传感器都连接到它,并通过以太网连接到“地面站” 现在我想通过地面站读写机器人的设置。因此,我考虑在机器人上实现一个可以由地面站操作的“虚拟寄存器” 它可以由结构组成,如下所示: // accelerometer register struct accel_reg { // accelerations int32_t accelX; int32_t accelY; int32_t acc

我目前正在建造一个机器人,上面有一些传感器。机器人上的控制单元是一个手臂Cortex-M3,所有传感器都连接到它,并通过以太网连接到“地面站”

现在我想通过地面站读写机器人的设置。因此,我考虑在机器人上实现一个可以由地面站操作的“虚拟寄存器”

它可以由结构组成,如下所示:

// accelerometer register
struct accel_reg {
  // accelerations
  int32_t accelX;
  int32_t accelY;
  int32_t accelZ;
};

// infrared distance sensor register 
struct ir_reg {
  uint16_t  dist; // distance
};

// robot's register table
struct {
  uint8_t     status;         // current state
  uint32_t    faultFlags;     // some fault flags
  accel_reg   accelerometer;  // accelerometer register
  ir_reg      ir_sensors[4];  // 4 IR sensors connected
} robot;

// usage example:

robot.accelerometer.accelX = -981;
robot.ir_sensors[1].dist = 1024;
message RobotState { optional int32_t status = 1; optional int32_t distance = 2; optional int32_t accelX = 3; ... } 在机器人上,寄存器将不断填充新值,配置设置由地面站设置并由机器人应用

地面站和机器人将用C++编写,所以它们都可以使用相同的结构数据类型。 我现在的问题是如何在不写入大量元数据的情况下将读/写操作封装在协议中

假设我想读取寄存器robot.ir\u sensors[2].dist。我将如何在协议中对该寄存器进行寻址

我已经考虑过以字节为单位传输相对偏移量(即结构中内存中的相对位置),但我认为内存对齐和填充可能会导致问题,特别是因为地面站运行在x86_64体系结构上,而机器人运行在32位ARM处理器上

谢谢你的提示!:)

我认为是一个非常好的会话/表示层工具。实际上,Google协议缓冲区不支持我所想的语法。因此,我将把我的答案的这一部分改为“通过代码合成推荐”。尽管它主要与XML一起使用,但它支持不同的表示层,例如,并且可能比具有大量可选数据的协议缓冲区更有效。生成代码也非常好用XSD可以自由地与开源软件一起使用,甚至可以在有限的消息结构下用于商业用途

我认为您不希望随机读取/写入寄存器集。您可以使用表示消息的
enum
作为消息前缀,例如,
IR update
distance
accel
等。这些是寄存器组。然后,机器人用寄存器集进行响应。到目前为止,您提供的所有寄存器都是传感器。
写入
必须是电机控制

您需要考虑您想要执行的控制以及您想要接收的遥测类型。然后提出一个消息结构并将信息捆绑在一起。您可以使用
序列图
,以及远程过程API等。我不是直接指这些RPC框架,而是指诸如
请求/响应
之类的概念,以及可能只是定期发送(遥测)而无需特定请求的消息。因此,地面站会以一定的间隔发出遥测请求,然后机器人会周期性地响应未经请求的数据。您总是需要一个消息id(
enum
),除非您的协议将是有状态的,出于健壮性原因,我不鼓励这样做


您还没有描述控制系统如何工作,或者您是否希望远程执行此操作。描述这一点可能会引出更多关于协议的想法。我相信我们谈论的是第5层、第6层、第7层。玩得开心。

我还将推荐谷歌协议缓冲区

在最简单的情况下,您可以实现一条消息
RobotState
,如下所示:

// accelerometer register
struct accel_reg {
  // accelerations
  int32_t accelX;
  int32_t accelY;
  int32_t accelZ;
};

// infrared distance sensor register 
struct ir_reg {
  uint16_t  dist; // distance
};

// robot's register table
struct {
  uint8_t     status;         // current state
  uint32_t    faultFlags;     // some fault flags
  accel_reg   accelerometer;  // accelerometer register
  ir_reg      ir_sensors[4];  // 4 IR sensors connected
} robot;

// usage example:

robot.accelerometer.accelX = -981;
robot.ir_sensors[1].dist = 1024;
message RobotState { optional int32_t status = 1; optional int32_t distance = 2; optional int32_t accelX = 3; ... } 消息机器人状态{ 可选int32_t状态=1; 可选int32_t距离=2; 可选int32_t accelX=3; ... } 然后,当机器人接收到消息时,它将从存在的任何可选字段中获取新值。然后,它将回复一条包含所有字段当前值的消息

通过这种方式,使用大多数protobuf实现的“合并消息”功能实现字段更新非常容易。另外,您可以在开始时使其非常简单,因为您只有一种消息类型,但如果以后需要展开,则可以添加子消息


protobuf确实不支持
int8\u t
int16\u t
。只需使用
int32\t
即可。

我本来打算建议,但您已经用这些标记了问题。不使用它们有什么原因吗?嗨,乍一看它看起来不像是在手臂上运行的,但我刚刚发现它有一个嵌入式版本!我已经成功地在各种嵌入式设备上运行了GPB,包括ARM。这就是我要做的,除非有什么问题。除非地面站也是一个手臂,否则你需要担心对齐和端点问题。您是想以一个单元读取和写入所有数据,还是选择单个值?我想读取/写入单个值,寄存器(如红外传感器数据、加速计数据)可以分组到定期传输的数据流中。+1尽管在某些情况下,
可选
开销将达到(可能超过)消息id的使用。基本上八个选项应该与一个字节宽的消息id相同,如果我已经猜到了如何使用google协议缓冲区正确地实现选项。@artlessnoise如果要将选项分组为消息类型,请将其作为子消息。那么可选子消息的开销与messa相同ge id应该是。是的,我认为无论哪种方式,您都可以以某种方式构造消息,以减少开销。重要的一点是,消息结构将减少开销。OP想要低开销,但似乎想要随机读/写;我认为这些目标冲突,这是我答案的一部分。我想我有协议缓冲区不支持我的想法。这是事实。我对它们了解得不够。我认为可能有子消息,但我找不到关于如何可选或子消息的文档