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 知识体系:指令发送的核心逻辑

为了让你更直观地理解,我画了一张流程图。这张图我每次带新人都会拿出来讲。

command_long_send 指令发送核心流程 1. 确定目标 target_system + target_component 2. 选择指令 command 编号(如400=解锁) 3. 填充参数 param1~param7(查表填充) 4. 发送并确认 confirmation + 等待ACK ⚠️ 常见错误 • 参数类型用错(int vs float) • 目标组件ID填错 • 保留参数填了非零值 • 忘记等待ACK确认 • 通道号chan未初始化 —— 我全踩过

你看,整个流程其实就四步。但每一步都有细节。尤其是第三步「填充参数」,不同指令差异巨大。我的建议是:写代码前先查MAVLink官方定义表,别凭感觉填。

4.6 关于confirmation字段的补充

这个字段很多人不理解。我简单说:

  • 0 = 首次发送。飞控收到后会执行,并回复ACK。
  • 1~255 = 重发。如果你没收到ACK,可以重发,confirmation递增。

但实际项目中,我很少用confirmation>0。为什么?因为地面站一般自己维护超时重传逻辑,不需要依赖这个字段。而且有些飞控对confirmation>0的处理有bug。所以我统一填0,自己写重传。

一句话总结:command_long_send就是地面站发号施令的「传令兵」。七个参数是「锦囊妙计」,每个指令对应不同的妙计。填对了,飞控乖乖执行;填错了,轻则指令无效,重则炸机。

好了,这一节就到这里。记住我今天讲的这些,尤其是那个表格和流程图,你写代码时随时可以回来翻。

专注资料整理