加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

UAVCAN——3.数据结构描述语言2

(2018-08-06 09:56:54)
标签:

pixhawk

ardupilot

can

uavcan

分类: Pixhawk

咨询

应用程序设计人员应考虑以下规则,但不应强制执行:

  • 消息名称应为名词或形容词; 服务名称应该是动词。
  • 带有命令的消息的名称应以“Command”结尾; 携带状态信息的消息的名称应以“状态”一词结尾。
  • 旨在获取或存储数据的服务名称应分别以“Get”或“Set”一词开头。

数据类型兼容性

数据类型兼容性的概念

交换某些特定数据结构的所有节点使用它的兼容DSDL定义至关重要。如果它们共享下面列出的方面,则认为不同的DSDL定义是兼容的。

二进制布局

编码二进制表示必须以相同方式由不同节点解释。这意味着兼容的数据结构必须具有相同顺序的相同字段类型。

第一个定义:

uint8 a uint8 b

第二个定义:

uint12 a uint4 b

即使上面数据结构的位长相同,二进制布局显然也不兼容。

字段名称和顺序

编码二进制表示必须以相同方式由不同节点解释。这意味着兼容的数据结构必须具有相同的字段类型和名称。

第一个定义:

uint8 a uint8 b

第二个定义:

uint8 b uint8 a

即使第一个和第二个定义共享相同的二进制布局(两个类型的字段uint8),它们也具有不同的字段名称,因此在语义上是不兼容的。

不变的定义

尽管不同的常量值可能使相同数据结构的不同表示在语义上不兼容,但UAVCAN并未考虑签名计算中的常量定义,因为固定常量定义会使数据类型不可扩展,即,常量的任何修改都会向后突破兼容性。

签名

不兼容的数据类型可能会破坏数据交换并导致不可预测的系统行为。为了确保类型兼容性,引入数据类型签名的概念本节介绍数据类型签名和许多关联/辅助概念。

签名用法在主题中讨论:CAN总线传输层

签名哈希函数

数据类型签名基于CRC-64-WE:

  • 名称:CRC-64-WE
  • 说明:http://reveng.sourceforge.net/crc-catalogue/17plus.htm#crc.cat-bits.64
  • 初始值:0xFFFFFFFFFFFFFFFF
  • 保利:0x42F0E1EBA9EA3693
  • 反向:没有
  • 输出XOR:0xFFFFFFFFFFFFFFFF
  • 检查:0x62EC59E3F1A4F00A

Python中的源代码:

# License: CC0, no copyright reserved class Signature: MASK64 = 0xFFFFFFFFFFFFFFFF POLY =0x42F0E1EBA9EA3693 def __init__(self, extend_from=None): if extend_from is not None: self._crc =(int(extend_from) & Signature.MASK64) ^ Signature.MASK64 else: self._crc = Signature.MASK64 defadd(self, data_bytes): if isinstance(data_bytes, str): data_bytes = map(ord, data_bytes) for b indata_bytes: self._crc ^= (b << 56) & Signature.MASK64 for _ in range(8): if self._crc & (1 << 63):self._crc = ((self._crc << 1) & Signature.MASK64) ^ Signature.POLY else: self._crc <<= 1 defget_value(self): return (self._crc & Signature.MASK64) ^ Signature.MASK64

规范化数据类型定义

数据类型的某些特征对于确保兼容性很重要,有些则不是。规范化数据类型定义是没有这种不重要特征的定义。

要获取给定数据类型的规范化定义,必须对其定义执行以下操作:

  1. 删除评论。
  2. 删除所有常量定义。
  3. 确保明确定义所有强制转换说明符; 如果没有,添加默认的强制转换说明符。
  4. 对于动态数组,将表单中的最大长度说明符替换[为表单[<=Y]
  5. 对于嵌套数据结构,请使用全名替换所有短名称。
  6. 删除不重要的空格(空行,前导空格,尾随空格,标记之间有多个空格)。
  7. 在单独的行上添加具有完整数据类型名称的DSDL定义。
  8. 用ASCII换行符替换换行符(代码:0x0A;转义序列:) \n

A命名空间中的消息类型示例root

# A header comment. # Note that the formatting is broken deliberately. @union float16 foo float16 BAR = 12.34 # This is BAR truncated uint8 bar int32 FOO = - 42

规范化定义:

root.A @union saturated float16 foo truncated uint8 bar

A命名空间中的服务类型示例root

# A header comment. # Note that the formatting is broken deliberately. B foobar float16 foo float16 BAR = 12.34 # This is BAR --- truncated uint8 foo int32 BAR = -42 root.ns1.B baz

规范化定义:

root.A root.B foobar saturated float16 foo --- truncated uint8 foo root.ns1.B baz

DSDL签名

DSDL签名是将签名散列函数 应用于规范化数据类型定义的产物

重要的是要理解DSDL签名与数据类型签名不同(因为数据类型可能引用存储在多个文件中的定义)。

数据类型签名

数据类型签名是64位整数值,对于兼容的数据类型保证相等

因此,据说如果数据类型的名称和签名相同,则它们是兼容的

以下是给定数据类型的数据类型签名计算算法,其中hash是前面描述的签名哈希函数:

  1. 使用给定类型的DSDL签名初始化哈希值。
  2. 从DSDL定义的顶部开始,对每个嵌套数据结构执行以下操作:
    1. 使用嵌套数据结构的数据类型签名扩展当前哈希值。
  3. 生成的哈希值将是数据类型签名。

散列扩展算法:

  1. 保存当前哈希值。
  2. 将散列需要扩展的值输入到散列函数,逐字节,LSB优先。
  3. 将保存的哈希值逐字节地输入哈希函数,LSB优先。

数据类型签名计算算法具有以下属性:

  • 如果数据类型不包含嵌套数据结构,则相同类型的数据类型签名和DSDL签名是相等的。
  • 仅当所有嵌套数据结构都兼容时,才能保证数据类型签名匹配。

上面解释的算法的实现可以在现有实现之一中找到。

聚合签名

聚合数据类型签名是为一组数据类型计算的签名。

聚合数据类型签名对于检查两组数据类型之间的兼容性很有用。

两组数据类型的Xÿ是兼容的,如果在每个数据类型X中具有正好一个兼容的数据类型ÿ和两组大小相等。

确保XY之间兼容性的一种可能方法是直接检查X中每个元素与Y中每个元素的兼容性然而,UAVCAN基于数据类型签名扩展(如上所定义)定义了计算上较便宜的算法。

计算数据类型集A的聚合签名的算法定义如下,其中hash是前面描述的签名散列函数:

  1. 字典顺序按降序排序A按完整数据类型名称(编码为ASCII,顺序为A到Z)。
  2. 使用A中第一个数据类型的数据类型签名初始化哈希值
  3. 对于每个数据类型一个,从第二开始,执行下列操作:
  4. 与延伸的数据类型签名的当前散列值一个

然后,如果它们的聚合签名相等,则认为两组数据类型是兼容的

数据类型ID

可能的数据类型ID值的集合是有限的,因此来自不同供应商的设备有时可能出于不同目的重用相同的数据类型ID。数据类型ID空间的一部分保留用于标准数据类型。由于所有UAVCAN节点应共享标准数据类型的相同配置,因此在该范围内不太可能发生冲突。数据类型ID空间的另一部分专用于特定于供应商(或特定于应用程序)的ID,并且此ID范围始终容易发生冲突。

为了允许来自不同供应商的节点在同一应用程序中使用, 最终用户必须能够更改每个节点上任何非标准数据类型的ID建议供应商为最终用户提供更改任何标准消息类型的ID的选项。

笔记:

  • 应用程序级别约定中列出的保留ID范围
  • 消息类型和服务类型不共享同一组可能的数据ID值(即,消息类型和服务类型可以共享相同的数据类型ID而不会发生冲突)。您可以在CAN总线传输层规范中了解更多相关信息
  • 更改ID不会影响数据类型兼容性。

数据序列化

序列化数据格式

序列化数据是有序的位域序列; 没有提供页眉或页脚,并且字段不是隐式对齐的。建议DSDL作者(但不要求)使用void数据类型手动对齐字节边界处的字段,以简化数据布局并提高序列化和反序列化例程的性能。

下面定义了不同数据类型的编码规则。

原始类型

类型 比特长度 二进制表示
int X. X 二进制补码有符号整数
uint X. X 普通的比特
布尔 1 单位
float16 16 IEEE754二进制16
FLOAT32 32 IEEE754 binary32
float64 64 IEEE754 binary64
无效的X. X X零位; 解码时忽略

嵌套数据结构

嵌套数据结构的编码方式与它们是独立的顶级数据结构的方式大致相同,尾部数组优化有一个例外,如下所述。

固定大小的数组

固定大小的数组被编码为一个简单的项目序列,每个项目都是独立编码的,没有对齐。没有添加额外的数据。

实质上,大小为X的固定大小的数组将以与行中相同类型X字段序列完全相同的方式进行编码 因此,以下数据类型:

AnyType[3] array

将具有相同的二进制布局:

AnyType array_0 AnyType array_1 AnyType array_2

唯一的区别是目标编程语言中的表示。

动态数组

动态数组编码规则很复杂; 因此,建议审查现有的实施,以便更深入地理解。

除了人类利益的文本表示之外,以下两个数组定义之间没有区别:

AnyType[<42] a # Max size 41 AnyType[<=41] b # Max size 41

两种形式在数据序列化方面都是等同的。

数组项可以是可变长度的(例如,如果项的类型是本身包含动态数组的数据结构)。因此,阵列最大和最小尺寸可能并不总是相同。

通常,动态数组将被编码为一系列编码项,前面加上一个无符号整数字段,表示所包含项的数量 - 长度字段长度字段的位宽度是数组中项目的最大数量的函数: ⌈log2(X + 1)⌉其中X是数组中项目的最大数量。例如,如果最大项数为251,则长度字段位宽必须为8位,或者如果最大项数为1,则长度字段位宽仅为一位。

传输层为每次接收的数据传输提供数据长度(具有8位分辨率); 因此,在某些情况下,阵列长度信息将是冗余的,因为它可以从传输层报告的总传输长度推断出来。消除动态数组长度字段称为尾部数组优化,如果满足以下所有条件,则可以执行此操作:

  1. 项类型的最小位长度不小于8位 - 因为传输层以8位分辨率报告传输长度。
  2. 数组是顶级数据结构中的最后一个字段 - 因为否则,需要更复杂的逻辑来获得长度。

第二个条件意味着只有在动态数组之后输出比特流中没有其他字段时才能进行尾部阵列优化。只有一个数组可以进行尾部优化。下面是一些示例,说明何时可以进行尾部阵列优化,何时不进行。

# Type root.A uint8 foo # Tail array optimization is possible here # It will be encoded just like a fixed-size array # The number of elements will be inferred from the transfer length uint8[<9] array # Type root.B float16 foo # Tail array optimization will not be possible because item length is less than 8 bits uint7[<=8] array # Type root.C # Tail array optimization will not be possible because the array is not the last field uint8[<=8] array float16 bar # Type root.D # Tail array optimization will not be possible because item length is less than 8 bits bool[<=42] array # Type root.E # Tail array optimization will not be possible because the minimum item length is zero root.D[<=42] array # Refer to root.D definition above

相同的规则适用于更复杂的情况,例如,当使用具有动态数组的多个嵌套类型时。这种结构可能会产生非常复杂的二进制布局,但相同的数组编码规则仍然适用。

# Type root.Z # Refer to root.A definition above # This array will be tail optimized # Arrays inside root.A will not be tail optimized root.A[<=2] array # Type root.Y # This array will NOT be tail optimized # Arrays inside root.A will NOT be tail optimized root.A[<=2] array # The last field here effectively disables any arrays from being tail optimized float16 baz # Type root.Q int4 fooz # Just an array that can be tail optimized, no nested types float64[<=64] array # Type root.X # This array will NOT be tail optimized # Because the minimum bit length of root.Q is 4 bits (less than 8 bits) # However, the last array in the last item will be tail optimized root.Q[<=12] array

建议应用程序设计人员在设计自定义数据类型时要记住尾部数组优化规则。

工会

联合编码为两个后续实体:

  1. 联合标签;
  2. 选定的字段。

union标记是无符号整数,其位长是union中字段数的函数: ⌈log2(N)⌉其中N是并集中的字段数。union标记中编码的值是所选字段的索引。字段索引根据它们的定义顺序分配,从零开始; 即第一个定义的字段获得索引0,第二个定义的字段获得索引1,依此类推。

请考虑以下示例:

# This is a union. @union # In this case, the union tag requires 2 bits uint16 FOO = 42 # A regular constant attribute uint16 a # Index 0 uint8 b # Index 1 float64 c # Index 2 uint32 BAR = 42 # Another regular constant

为了对值进行编码b,根据定义,该值具有数据类型uint8,应为union标记赋值1.以下结构将具有相同的布局:

uint2 tag uint8 b

举个例子,如果值b是7,那么得到的编码字节序列将是(二进制):

01000001 11000000

字节顺序和位顺序

字节顺序:首先是最低有效字节(LSB),也称为little-endian。

位顺序:从最高有效位到最低有效位填充位,即最高有效位具有索引0。

结果位序列必须对齐到1个字节; 填充位必须设置为零。

出于示例的目的,将根据定义的顺序对以下数据进行编码:

  1. 位长12的0xbeda
  2. 比特长度为3的-1
  3. -5位长度4
  4. 比特长度为2的-1
  5. 比特长度为4的0x88

生成的字节序列如下图所示:

https://uavcan.org/Specification/figures/bit_encoding.png

我们建议您查看现有的实现。

标准数据类型

DSDL存储库中提供了标准数据结构的DSDL定义,该存储库在此处链接,并在规范的后续部分中提供。

有关标准DSDL定义的开发和维护的信息,请参见 此处

供应商特定的数据类型

供应商必须在单独的命名空间中定义其特定的数据类型,通常应将其命名为与其公司名称相匹配。将供应商的定义分离到专用命名空间可确保在使用来自不同提供商的特定于供应商的数据类型的系统中不会发生名称冲突。请注意,根据命名要求,DSDL命名空间的名称必须以字母字符开头; 因此,名称以数字开头的公司将不得不求助于错位的名称,例如将数字移到名称的末尾,或者用英语拼写数字(例如42 - fortytwo)。

uavcan明确禁止在标准名称空间中定义特定于供应商的数据类型标准名称空间将始终仅用于标准定义。

一般而言,期望将“通用”数据类型包括在标准集中。供应商应努力将其数据类型设计为通用的,并尽可能独立于其特定用例。测量单位的SI系统应该是首选,因为不会与SI产生不必要的偏差的数据类型定义将不被接受到标准集中。

翻译自官网:https://uavcan.org

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有