ArduPilot 样式指南¶
为了提高 ArduPilot 代码的可读性,帮助新用户更快地掌握代码,请使用以下样式。如果不遵守这些样式,提交的代码可能会被拒绝。
备注
由于历史原因,规范的某些部分可能不符合要求,但新增加的部分应该符合要求!
风格 是我们格式化代码的首选工具。虽然我们目前还不能自动格式化代码,但在 Tools/CodeStyle 目录下有一个 astylerc 文件,可用于根据以下指南自动格式化代码。
风格 --选项=工具/代码风格/天体运动 <;文件名>;
请记住,对文件格式的任何更改都应作为单独的提交进行。
案例¶
变量名和函数名均为小写,以下划线分隔。
对
输入节流阀
错了
节流阀输入
缩进¶
空间¶
所有地方均使用 4 个空格缩进。不要使用制表符。
对
int 动物()
{
返回 0;
}
错了
int 动物()
{
返回 0;
}
案例说明¶
大小写标签的缩进既可以与开关并列,也可以缩进一次。
对
开关 (条件) {
个案 foo_cond:
动物();
断裂;
个案 bar_cond:
酒吧();
断裂;
}
对
开关 (条件) {
个案 foo_cond:
动物();
断裂;
个案 bar_cond:
酒吧();
断裂;
}
错了
开关 (条件) {
个案 foo_cond:
动物();
断裂;
个案 bar_cond:
酒吧();
断裂;
}
间距¶
一元运算符¶
单运算符周围不要留空格。
对
i++;
错了
i ++ ;
控制声明¶
在控制语句及其括号之间留出空格。
对
如果 (条件) {
动物();
}
错了
如果(条件) {
动物();
}
如果 (条件){
动物();
}
功能调用¶
请勿在函数和括号之间或括号和内容之间放置空格。
对
动物(a, 10);
错了
动物 (a, 10);
动物(a, 10 );
尾部空格¶
不要在新代码中留下拖尾空白(好的编辑器可以帮你处理这个问题)。修复现有代码中的空白时,应单独提交(不要与其他更改一起提交)。
换行¶
单项发言¶
除了头文件中的方法实现可能(也可能不)在一行之外,每条语句都应独立成行。
对
x++;
y++;
如果 (条件) {
动物();
}
错了
x++; y++;
如果 (条件) 动物();
对
bool requires_GPS() 缢 否决 { 返回 错误; }
Else 语句¶
一个 不然
语句应与前面的封闭括号放在同一行。
对
如果 (条件) {
动物();
} 不然 {
酒吧();
}
错了
如果 (条件) {
动物();
}
不然 {
酒吧();
}
牙套¶
功能括号¶
函数定义:将每个括号放在单独一行。对于头文件中的方法,括号可以内联。
控制声明¶
控制语句 (如果
, 虽然
, 做
, 不然
) 应始终在语句周围使用大括号。
对
如果 (条件) {
动物();
} 不然 {
酒吧();
}
错了
如果 (条件)
动物();
不然
酒吧();
其他支架¶
将开口括号放在代码块的前一行;将闭口括号放在它自己的一行。
对
类 我的类 {
...
};
命名空间 AP_HAL {
...
}
对于 (int i = 0; i <; 10; i++) {
...
}
错了
类 我的类
{
...
};
名称¶
非官方成员¶
类中的私有成员前应加上下划线:
对
类 我的类 {
私人:
int 你的工作是什么?;
};
错了
类 我的类 {
私人:
int 领域;
};
班级名称¶
班级名称的每个单词都应大写,并用下划线分隔。
对
类 AP_Compass { };
错了
类 ap_compass { };
枚举¶
首选枚举类而不是原始枚举。枚举应使用 PascalCase,并且是单数。所有条目都应有逗号,即使是最后一条。
对
枚举 类 指南针类型 {
FOO,
酒吧,
};
错了
枚举 罗盘类型 {
FOO,
酒吧
};
函数和变量¶
返回单个物理值的函数或表示物理值的变量应以物理单位作为后缀。
对
uint16 get_angle_rad() { ... };
浮动 距离_m;
错了
uint16 获取角度() { ... };
浮动 距离;
表示相对于框架的值的函数或变量,应首先以框架为后缀,然后以物理单位(如有)为后缀。
对
uint16 获取标定的厘米距离() { ... };
uint16 获取距离菜单() { ... };
浮动 位置_neu_mm;
错了
uint16 获取距离() { ... };
浮动 位置;
评论¶
每个具有公共可见性的文件、函数和方法都应在顶部添加注释,说明其作用。
参数¶
用户可以从这些字段中收集关键信息。有了代码中详细记录的参数,维基和 GCS 就能自动更新参数。如果对参数进行了适当的记录,用户通常就可以对载具进行调校,而不需要成页成页的外部非链接文档。虽然这里的信息不能替代调校指南,但可以非常有效地指导用户更改正确的参数。
包含多个单词的参数应按重要性从左至右排列单词:
飞行模式、功能或传感器应是第一个词。例如,仅与 RTL 飞行模式相关的参数应以 "RTL "开头,如 "RTL_ALT"。
MIN"、"MAX "或单位(极少数情况下它们会出现在名称中)等限定符应放在最右边。例如,RTL_ALT_MIN 比 RTL_MIN_ALT 好。
尽可能重复使用其他参数中的词,而不是创建新词。例如,我们使用 "MIN"(最小值)和 "MAX"(最大值),因此应使用这两个词,而不是 "TOP"(上)和 "BOTTOM"(下)这样的对等词。
参数应以标准单位表示(距离以米为单位,角度以度为单位),但如果参数不是以标准单位表示,则可以(选择性地)在末尾添加单位。这绝对不是要求,而是由开发者决定的。
参数名称的总长度必须小于或等于 16 个字符。
显示名称¶
显示名称通常是一个 2-5 个字的短语,用来描述参数的变化。通常是参数名称的全称。不要以 "the "等非描述性词语开头。PTCH_LIM_MAX_DEG 的一个好的显示名称是 "最大螺距角"。
说明¶
描述是一个长文本字段,用于完整描述参数以及更改参数对载具行为的影响。描述应简明扼要,同时向用户提供最关键的信息。
对
// @描述: 收益 附加的 至 沥青 至 保持 飞机 从 降序 或 升序 于 匝数. 增加 于 增量 的 0.05 至 减小 高度 损失. 减少 对于 高度 收获.
错了
// @描述: 这 是 的 收获 学期 那 是 应用 至 的 沥青 费率 胶印 计算 作为 所需 至 保持 的 鼻子 夷为平地 期间 匝数. "这款" 默认 价值 是 1 其中 将 工作 对于 一应俱全 模型. 高级 用户 会 使用 它 至 正确的 对于 高度 变异 于 匝数. 如果 高度 是 失去的 当初 于 匝数 此 会 是 增加 于 小 增量 的 0.05 至 赔偿. 如果 高度 是 获得 当初 于 匝数 则 它 会 是 减少.
避免在描述中出现:
所有参数通用的帮助性词语和非描述性语言,如 "本参数可改变......、您等"。
引用其他参数,除非是关键参数
将 0 设置描述为 "禁用"
默认设置
在描述中鼓励:
现在时语言
更改参数的后果(这也为用户如何调整载具提供了指导)
使用或忽略参数时
当 0 设置使用另一个参数值时
值、单位、范围¶
数值、单位、范围和步骤对于调整参数也至关重要。尽可能将其包括在内。
用户¶
用户字段有助于对高级参数进行分类和隐藏,防止新用户对其进行调整。目前有 2 个用户字段:
标准 - 任何人都可使用
高级 - 供高级用户使用
浮点注释¶
ArduPilot 使用 -单精度常数
.
这意味着目前允许在常量中省略 float 指定符。同时,也允许有浮点符。
对
1.0f
1.0
乘法与除法¶
尽可能使用乘法而不是除法:
对
缢 浮动 foo_m = foo_cm * 0.01;
错误
缢 浮动 foo_m = foo_cm / 100;
乘法的计算周期通常比除法少。
ArduPilot 设计决策¶
为了适应 ArduPilot 的嵌入式特性,ArduPilot 代码库做出了几项设计决定,这可能会让一些程序员感到惊讶。
内存隐式清零¶
内存的隐式归零可以让我们的行为更加一致(即使是不好的行为),还可以节省闪存空间,因为代码中的大多数地方都不需要初始化它们已经分配的内存。唯一必须清零的内存是堆栈存储变量 - locals、asprintf 等。
new 和 malloc 都将内存清零
bss 存储的数据无需清零(因此单例对象中的成员无需清零
向量是特殊的,即使在堆栈中也是零
函数中的静态变量(我们通常不赞成)无需清零
比特字段通常不受欢迎¶
使用位字段可以减少 RAM 的使用量,但会大大增加闪存的使用量,因为从位字段中提取布尔真值需要更多的机器指令。如果变量被频繁访问,闪存的使用量就会很大。
非首选:
类 Foo() {
私人:
bool 应飞 : 1;
bool should_grow : 1;
};
首选:
类 Foo() {
私人:
bool 应飞;
bool should_grow;
};
在头文件中而不是在构造函数中初始化成员变量¶
如果成员不依赖于构造函数参数,我们更倾向于在类定义中进行初始化。
非首选:
Foo::Foo() :
酒吧(37),
baz(BAZ_DEFAULT)
{
...
}
首选:
类 Foo() {
公:
...
私人:
uint8_t 酒吧 = 37;
浮动 baz = BAZ_DEFAULT;
};
无标准图书馆¶
出于提高效率的考虑,ArduPilot 不使用 C 标准库 (std::
).我们还倾向于使用跨平台一致的函数,以简化支持(例如,在支持 64 位数学的平台上不使用 64 位数学就很有用)。
这意味着没有 std::vector
没有 std::string
没有 std::unordered_map
例如
我们尽量避免使用库调用来处理自己的分配,但如果你真的想这样做,仅仅包含获取这些分配的头文件是不够的,你还需要在构建系统中做手脚,以链接 标准
中。
替代品 std::vector
¶
大多数情况下使用固定长度的数组。
AP_ExpandingArray
这也许是您的一个选择--但在飞行中扩展可能是件坏事。
有些地方使用链接列表。
替代品 std::string
¶
asprintf
在某些地方使用。一般来说,只需使用 char*
就足够了。
替代品 std::unordered_map
¶
创建结构数组并迭代。例如,在将 mavlink id 转换为 ap_message id 时就需要这样做。
创建一个结构体有序数组,并对其进行二叉搜索。
创建一个具有完美哈希值的结构数组。
无死亡代码¶
我们不会在 ArduPilot 中保留无效代码。如果代码未被使用,则应将其删除,而不仅仅是注释掉。这是一般规则,并非普遍遵守。