4. 发送指令基础:command_long_send函数详解、参数填充规则
好,咱们今天来聊聊地面站里最核心的一个操作——发送指令。
说白了,地面站跟飞控打交道,大部分时间就是在发指令。而MAVLink里最常用的指令发送方式,就是 command_long_send 这个函数。我做了这么多年地面站,可以说90%的指令都是通过它发出去的。今天我就把它的底裤扒干净,让你彻底搞懂。
4.1 command_long_send 函数长什么样?
先看原型。这个函数在 mavlink.h 或者你生成的对应头文件里。不同语言版本参数顺序可能略有不同,但核心逻辑一样。
// C语言版本(最常用)
void mavlink_msg_command_long_send(
mavlink_channel_t chan, // 通信通道
uint8_t target_system, // 目标系统ID
uint8_t target_component, // 目标组件ID
uint16_t command, // 指令编号
uint8_t confirmation, // 确认标志
float param1, float param2, float param3,
float param4, float param5, float param6, float param7
);
嗯,一共11个参数。看着多,其实分三组:
- 第一组:目标定位(chan, target_system, target_component)—— 发给谁?
- 第二组:指令本体(command, confirmation)—— 干什么?
- 第三组:参数载荷(param1~param7)—— 具体怎么干?
我个人习惯把param1~param7叫做「七龙珠」,集齐七个就能召唤神龙(执行指令)。
4.2 参数填充规则——这七个参数到底填什么?
这是新手最容易懵的地方。七个float参数,每个指令含义都不一样。我刚开始做的时候也查表查到眼花。
核心原则:每个MAVLink指令(command)都有一份官方定义,告诉你每个param对应什么。比如:
| 指令 | param1 | param2 | param3 | param4 | param5~7 |
|---|---|---|---|---|---|
| MAV_CMD_NAV_WAYPOINT (16) | 停留时间(秒) | 到达半径(米) | 通过半径(米) | 偏航角(度) | 纬度/经度/高度 |
| MAV_CMD_DO_SET_MODE (176) | 模式类型 | 自定义模式 | 子模式 | 保留 | 保留 |
| MAV_CMD_COMPONENT_ARM_DISARM (400) | 1=上锁, 0=解锁 | 强制标志 | 保留 | 保留 | 保留 |
重要:不用的参数填0或NaN。但有些飞控对NaN处理不一样,我建议统一填0,最安全。
4.3 实战:发送解锁指令
咱们写个实际例子。解锁(arm)是每个飞手最常用的操作。对应的指令是 MAV_CMD_COMPONENT_ARM_DISARM,编号400。
// 解锁无人机
void send_arm_command(mavlink_channel_t chan, uint8_t sysid, uint8_t compid) {
mavlink_msg_command_long_send(
chan,
sysid, // 目标飞控系统ID
compid, // 目标飞控组件ID(通常是1)
MAV_CMD_COMPONENT_ARM_DISARM, // 400
0, // 首次发送,不要求确认
1.0f, // param1: 1=解锁, 0=上锁
0.0f, // param2: 强制标志(0=不强制)
0.0f, 0.0f, 0.0f, 0.0f, 0.0f // param3~7: 保留填0
);
}
你看,就这么简单。param1填1.0f就是解锁,填0.0f就是上锁。
我的经验:param2的强制标志,在PX4上如果你填1,它会忽略一些安全检查(比如GPS信号不好也能解锁)。ArduPilot对这个参数处理不太一样。我曾经踩过坑,在PX4上填了1,结果飞控直接解锁,差点出事。所以除非你明确知道后果,否则强制标志填0。
4.4 避坑指南——我踩过的那些坑
做地面站这么多年,command_long_send这个函数我写过不下千次。但有些坑,真的是血泪教训。
我曾经犯过的错:
- 参数类型搞混:param1~param7是float,不是int。我见过有人直接传整数,结果飞控收到的是乱码。记住:1.0f 不是 1。
- confirmation字段乱填:这个字段0表示首次发送,1表示重发。如果你填了1但之前没发过0,飞控会忽略。我调试时卡了半小时才发现。
- target_component填错:飞控的组件ID通常是1,但相机可能是100,GPS可能是6。发错组件,指令石沉大海。
4.5 知识体系:指令发送的核心逻辑
为了让你更直观地理解,我画了一张流程图。这张图我每次带新人都会拿出来讲。
你看,整个流程其实就四步。但每一步都有细节。尤其是第三步「填充参数」,不同指令差异巨大。我的建议是:写代码前先查MAVLink官方定义表,别凭感觉填。
4.6 关于confirmation字段的补充
这个字段很多人不理解。我简单说:
- 0 = 首次发送。飞控收到后会执行,并回复ACK。
- 1~255 = 重发。如果你没收到ACK,可以重发,confirmation递增。
但实际项目中,我很少用confirmation>0。为什么?因为地面站一般自己维护超时重传逻辑,不需要依赖这个字段。而且有些飞控对confirmation>0的处理有bug。所以我统一填0,自己写重传。
一句话总结:command_long_send就是地面站发号施令的「传令兵」。七个参数是「锦囊妙计」,每个指令对应不同的妙计。填对了,飞控乖乖执行;填错了,轻则指令无效,重则炸机。
好了,这一节就到这里。记住我今天讲的这些,尤其是那个表格和流程图,你写代码时随时可以回来翻。