乐于分享
好东西不私藏

无人机开发实战——开发控制插件实现复合翼、固定翼无人机控制

无人机开发实战——开发控制插件实现复合翼、固定翼无人机控制
    各位无人机开发爱好者在做无人机开发时,用到比较多的机型应该都是四旋翼无人机,其灵活好控,开发样例众多,比较受开发者们青睐。但随着低空经济的兴起,垂起复合翼(vtol)和固定翼飞机也越来越多了进入了开发爱好者的视野中。四旋翼在做外部控制时,通过offboard模式控制位置、速度、姿态、角速率的这种模式已经非常普遍了,但是网上关于复合翼和固定翼的开发教程比较少,开发群里也很多人想对此进行研究。因此本期对如何通过外部插件控制复合翼和固定翼无人机(以PX4)为例进行介绍。
一、开发功能
    本次主要通过开发控制插件,实现在外部模块(比如集群管理系统、机上设备)对复合翼等无人机进行控制。使用mavlink协议,脱离ROS2 DDS和MAVROS(因为dds和mavros虽然使用方便,但是很难满足所有需求,同时关于垂起和固定翼的太少)。
二、实现方法
1.修改px4源码的mavlink样例,增加组播和单播端口。(增加你的外部程序的控制来源,如组播,单播等)
# GCS linkmavlink start -x -u $udp_gcs_port_local -r 4000000 -fmavlink stream -r 50 -s POSITION_TARGET_LOCAL_NED -u $udp_gcs_port_localmavlink stream -r 50 -s LOCAL_POSITION_NED -u $udp_gcs_port_localmavlink stream -r 50 -s GLOBAL_POSITION_INT -u $udp_gcs_port_localmavlink stream -r 50 -s ATTITUDE -u $udp_gcs_port_localmavlink stream -r 50 -s ATTITUDE_QUATERNION -u $udp_gcs_port_localmavlink stream -r 50 -s ATTITUDE_TARGET -u $udp_gcs_port_localmavlink stream -r 50 -s SERVO_OUTPUT_RAW_0 -u $udp_gcs_port_localmavlink stream -r 20 -s RC_CHANNELS -u $udp_gcs_port_localmavlink stream -r 10 -s OPTICAL_FLOW_RAD -u $udp_gcs_port_local# API/Offboard linkmavlink start -x -u $udp_offboard_port_local -r 4000000 -f -m onboard -o $udp_offboard_port_remote# Onboard link to cameramavlink start -x -u $udp_onboard_payload_port_local -r 4000 -f -m onboard -o $udp_onboard_payload_port_remote# Onboard link to gimbalmavlink start -x -u $udp_onboard_gimbal_port_local -r 400000 -m gimbal -o $udp_onboard_gimbal_port_remote
2.开发外部程序
(1)首先依赖mavlink底层协议,官方网址在此

https://mavlink.io/zh/messages/common.html

可根据官网示例,生成mavlink依赖协议。如下

(2)开发外部程序插件

通过调用mavlink底层协议,开发控制函数,如下

staticvoidsend_mavlink_msg(constmavlink_message_t &msg)    {        uint8_t buffer[MAVLINK_MAX_PACKET_LEN];        uint16_t len = mavlink_msg_to_send_buffer(buffer, &msg);        // udp_multicast::send_multicast(buffer, len);        udp_unicast::send_unicast(buffer, len);    }    voidsend_heartbeat()    {        mavlink_message_t msg;        mavlink_msg_heartbeat_pack_chan(            GCS_SYS_ID, GCS_COMP_ID, MAVLINK_CHAN, &msg,            MAV_TYPE_ONBOARD_CONTROLLER, MAV_AUTOPILOT_GENERIC,            0, 0, MAV_STATE_ACTIVE);        send_mavlink_msg(msg);    }    voidset_mode(uint32_t mode)    {        mavlink_message_t msg;        mavlink_msg_command_long_pack_chan(            GCS_SYS_ID, GCS_COMP_ID, MAVLINK_CHAN, &msg,            TARGET_SYS_ID, TARGET_COMP_ID,            MAV_CMD_COMPONENT_ARM_DISARM, 0,            1, 0, 0, 0, 0, 0, 0 // param1=1 解锁        );        send_mavlink_msg(msg);        std::this_thread::sleep_for(500ms); // 等待解锁生效        mavlink_msg_command_long_pack_chan(            GCS_SYS_ID, GCS_COMP_ID, MAVLINK_CHAN, &msg,            TARGET_SYS_ID, TARGET_COMP_ID,            MAV_CMD_DO_SET_MODE, 0,            MAV_MODE_FLAG_CUSTOM_MODE_ENABLED, // param1:启用自定义模式            PX4_CUSTOM_MODE_GUIDED,            // param2:PX4 GUIDED 模式            0, 0, 0, 0, 0);        send_mavlink_msg(msg);    }    voidtakeoff(float altitude)    {        set_mode(0);        std::this_thread::sleep_for(1s);        mavlink_message_t msg;        mavlink_msg_command_long_pack_chan(            GCS_SYS_ID, GCS_COMP_ID, MAVLINK_CHAN, &msg,            TARGET_SYS_ID, TARGET_COMP_ID,            MAV_CMD_NAV_TAKEOFF, 0,            0, 0, 0, 0, 0, 0, altitude);        send_mavlink_msg(msg);    }    voidupload_mission(const Waypoint *waypoints, size_t count)    {        // 1. 发送航点数量        mavlink_message_t msg;        mavlink_msg_mission_count_pack_chan(            GCS_SYS_ID, GCS_COMP_ID, MAVLINK_CHAN, &msg,            TARGET_SYS_ID, TARGET_COMP_ID,            count, MAV_MISSION_TYPE_MISSION, 0);        send_mavlink_msg(msg);        // 2. 逐个发送航点        for (size_t i = 0; i < count; ++i)        {            const Waypoint &wp = waypoints[i];            mavlink_msg_mission_item_int_pack_chan(                GCS_SYS_ID, GCS_COMP_ID, MAVLINK_CHAN, &msg,                TARGET_SYS_ID, TARGET_COMP_ID,                wp.seq, wp.frame, wp.cmd, wp.current, wp.autocontinue,                wp.param1, wp.param2, wp.param3, wp.param4,                static_cast<int32_t>(wp.lat * 1e7), // 转换为INT32 1e7度                static_cast<int32_t>(wp.lon * 1e7),                wp.alt, MAV_MISSION_TYPE_MISSION);            send_mavlink_msg(msg);        }    }

(3)在你的外部程序启动通讯,然后把你在外部程序部署的软件,比如集群管理、避障、导航等智能软件的控制输出通过你写的mavlink函数输出到飞控上。

三、实践效果

 1.以PX4仿真为例,启动固定翼和复合翼模型,然后加载外部智能软件,通过网络通讯,把规划生成的控制指令通过此插件发送到px4飞控上。

   2. 比如我们测试航线装订,通过mavlink的航线装订函数,我们把规划的航线进行装订,装订注意航点数量和属性和地面站装订形式保持一致。在你的开发的插件上也要装订如下航点。

3.你的智能软件航线规划好,实现航线装订和飞行

垂起固定翼飞控在收到航线后,会通过飞控内部逻辑进行状态转换,进行旋翼和固定翼的切换,前提是你航点需要装订正确。
固定翼同理,相对复合翼简单,实现航线飞行。

4.最后实现的效果是你可以通过外部智能软件对集群飞机进行航线控制,效果等同于你通过单机地面站对每架飞机进行航线装订

四、总结
    本期主要通过开发控制插件实现对垂起复合翼、固定翼等无人机的控制,由于市面关于此类型飞机的外部控制开发经验较少,ROS2的dds和mavros也无法满足开发需求,因此分享一下经验,一起探讨交流。

    后续我们会继续分享 PX4 自定义模块开发、ROS2 与 PX4 通信、自主避障算法开发、多机集群控制等进阶内容,欢迎关注我的公众号,第一时间获取最新的无人机开发干货。

同时我们有无人机开发爱好者群聊,汇聚开发者们共同交流技术心得,欢迎加入~

相关学习资料