目录
摘要
本节主要记录自己学习ardupilot的地面站MP代码Mavlink协议的官网Demo过程。
1.代码路径
代码路径参考:
F:\mp\MissionPlanner-MissionPlanner1.3.62\ExtLibs\SimpleExample
我的是在F盘,mp文件夹下,其他的可以直接看后续路径
2.打开代码
开发环境:visual studio 2017
找到SimpleExample.sln,双击打开即可。
打开后的工程代码如下所示:
3.运行代码
快捷键F5或者下面位置
运行后界面如下:
4.代码分析
1.应用程序入口
2.程序simpleexample
simpleexample的程序主要从两个角度看,设计器和代码。
C#中的WinForm知识点这里就不记录,可以参考下面知识点学习:
C#知识点
对于代码部分我们可以通过设计器去看代码:
1. 第一个下拉框
这里是选择我们飞控连接到电脑端的对于的端口
2. 第二个下拉框
第二个下拉框对应的是串口的波特率
具体支持的波特率如下,这里可以自己增加
3. connect button按钮
//点击连接按钮
private void but_connect_Click(object sender, EventArgs e)
{
//如果端口打开,请将其关闭
if (serialPort1.IsOpen)
{
serialPort1.Close();
return;
}
// 在 C# WinForm开发中组合框(ComboBox)控件也称下拉列表框,用于选择所需的选项,
//例如在注册学生信息时选择学历、专业等。
//通过下拉列表框获取数据
serialPort1.PortName = CMB_comport.Text;
serialPort1.BaudRate = int.Parse(cmb_baudrate.Text);
//打开部件
serialPort1.Open();
//将超时设置为2秒
serialPort1.ReadTimeout = 2000;
//创建bgw对象
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerAsync();
}
下面是执行的bgw_DoWork线程
/// <summary>
/// 后端工作线程
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
//当串口被打开后
while (serialPort1.IsOpen)
{
try
{
MAVLink.MAVLinkMessage packet;
lock (readlock)
{
//从端口读取任何有效数据包
packet = mavlink.ReadPacket(serialPort1.BaseStream);
//检查是否有效 check its valid
if (packet == null || packet.data == null)
continue;
}
//检查一下它是否是来自comport的心跳包
if (packet.data.GetType() == typeof(MAVLink.mavlink_heartbeat_t))
{
var hb = (MAVLink.mavlink_heartbeat_t)packet.data;
//保存seen MAV的sysid和compid
sysid = packet.sysid;
compid = packet.compid;
// request streams at 2 hz
var buffer = mavlink.GenerateMAVLinkPacket10(MAVLink.MAVLINK_MSG_ID.REQUEST_DATA_STREAM,
new MAVLink.mavlink_request_data_stream_t()
{
req_message_rate = 2,
req_stream_id = (byte)MAVLink.MAV_DATA_STREAM.ALL,
start_stop = 1,
target_component = compid,
target_system = sysid
});
serialPort1.Write(buffer, 0, buffer.Length);
buffer = mavlink.GenerateMAVLinkPacket10(MAVLink.MAVLINK_MSG_ID.HEARTBEAT, hb);
serialPort1.Write(buffer, 0, buffer.Length);
}
// from here we should check the the message is addressed to us
if (sysid != packet.sysid || compid != packet.compid)
continue;
Console.WriteLine(packet.msgtypename);
if (packet.msgid == (byte)MAVLink.MAVLINK_MSG_ID.ATTITUDE)
//or
//if (packet.data.GetType() == typeof(MAVLink.mavlink_attitude_t))
{
var att = (MAVLink.mavlink_attitude_t)packet.data;
//打印姿态横滚角和俯仰角
Console.WriteLine(att.pitch*57.2958 + " " + att.roll*57.2958);
}
}
catch
{
}
System.Threading.Thread.Sleep(1);
}
}
4. Send Mission button按钮
//任务按钮
private void but_mission_Click(object sender, EventArgs e)
{
MAVLink.mavlink_mission_count_t req = new MAVLink.mavlink_mission_count_t();
req.target_system = 1;
req.target_component = 1;
//设置wp计数
req.count = 1;
byte[] packet = mavlink.GenerateMAVLinkPacket10(MAVLink.MAVLINK_MSG_ID.MISSION_COUNT, req);
Console.WriteLine("MISSION_COUNT send");
serialPort1.Write(packet, 0, packet.Length);
var ack = readsomedata<MAVLink.mavlink_mission_request_t>(sysid, compid);
if (ack.seq == 0)
{
MAVLink.mavlink_mission_item_int_t req2 = new MAVLink.mavlink_mission_item_int_t();
req2.target_system = sysid;
req2.target_component = compid;
req2.command = (byte)MAVLink.MAV_CMD.WAYPOINT;
req2.current = 1;
req2.autocontinue = 0;
req2.frame = (byte)MAVLink.MAV_FRAME.GLOBAL_RELATIVE_ALT;
req2.y = (int) (115 * 1.0e7);
req2.x = (int) (-35 * 1.0e7);
req2.z = (float) (2.34);
req2.param1 = 0;
req2.param2 = 0;
req2.param3 = 0;
req2.param4 = 0;
req2.seq = 0;
packet = mavlink.GenerateMAVLinkPacket10(MAVLink.MAVLINK_MSG_ID.MISSION_ITEM_INT, req2);
Console.WriteLine("MISSION_ITEM_INT send");
lock (readlock)
{
serialPort1.Write(packet, 0, packet.Length);
var ack2 = readsomedata<MAVLink.mavlink_mission_ack_t>(sysid, compid);
if ((MAVLink.MAV_MISSION_RESULT) ack2.type != MAVLink.MAV_MISSION_RESULT.MAV_MISSION_ACCEPTED)
{
}
}
MAVLink.mavlink_mission_ack_t req3 = new MAVLink.mavlink_mission_ack_t();
req3.target_system = 1;
req3.target_component = 1;
req3.type = 0;
packet = mavlink.GenerateMAVLinkPacket10(MAVLink.MAVLINK_MSG_ID.MISSION_ACK, req3);
Console.WriteLine("MISSION_ACK send");
serialPort1.Write(packet, 0, packet.Length);
}
}
5. Arm/Disarm button按钮
//解锁或者不解锁
private void but_armdisarm_Click(object sender, EventArgs e)
{
//创建对象
MAVLink.mavlink_command_long_t req = new MAVLink.mavlink_command_long_t();
//系统
req.target_system = 1;
//组件
req.target_component = 1;
//命令
req.command = (ushort)MAVLink.MAV_CMD.COMPONENT_ARM_DISARM;
//参数1
req.param1 = armed ? 0 : 1;
armed = !armed;
/*
req.param2 = p2;
req.param3 = p3;
req.param4 = p4;
req.param5 = p5;
req.param6 = p6;
req.param7 = p7;
*/
//把数据组包
byte[] packet = mavlink.GenerateMAVLinkPacket10(MAVLink.MAVLINK_MSG_ID.COMMAND_LONG, req);
//组包完成后写入数据
serialPort1.Write(packet, 0, packet.Length);
try
{
var ack = readsomedata<MAVLink.mavlink_command_ack_t>(sysid, compid);
if (ack.result == (byte)MAVLink.MAV_RESULT.ACCEPTED)
{
}
}
catch
{
}
}
从以上代码可以看出Mavlink有两个重要函数组包和解包函数。
1. 组包函数
//组包数据
public byte[] GenerateMAVLinkPacket10(MAVLINK_MSG_ID messageType, object indata, byte sysid = 255, byte compid = (byte)MAV_COMPONENT.MAV_COMP_ID_MISSIONPLANNER, int sequence = -1)
{
byte[] data;
data = MavlinkUtil.StructureToByteArray(indata);
byte[] packet = new byte[data.Length + 6 + 2];
packet[0] = MAVLINK_STX_MAVLINK1;
packet[1] = (byte)data.Length;
packet[2] = (byte)packetcount;
if (sequence != -1)
packet[2] = (byte)sequence;
packetcount++;
packet[3] = sysid; // this is always 255 - MYGCS
packet[4] = compid;
packet[5] = (byte)messageType;
int i = 6;
foreach (byte b in data)
{
packet[i] = b;
i++;
}
ushort checksum = MavlinkCRC.crc_calculate(packet, packet[1] + 6);
checksum = MavlinkCRC.crc_accumulate(MAVLINK_MESSAGE_INFOS.GetMessageInfo((uint)messageType).crc, checksum);
byte ck_a = (byte)(checksum & 0xFF); ///< High byte
byte ck_b = (byte)(checksum >> 8); ///< Low byte
packet[i] = ck_a;
i += 1;
packet[i] = ck_b;
i += 1;
return packet;
}
2. 解包函数
packet = mavlink.ReadPacket(serialPort1.BaseStream);
public MAVLinkMessage ReadPacket(Stream BaseStream)
{
byte[] buffer = new byte[MAVLink.MAVLINK_MAX_PACKET_LEN];
DateTime packettime = DateTime.MinValue;
if (hasTimestamp)
{
byte[] datearray = new byte[8];
int tem = BaseStream.Read(datearray, 0, datearray.Length);
Array.Reverse(datearray);
DateTime date1 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
UInt64 dateint = BitConverter.ToUInt64(datearray, 0);
if ((dateint / 1000 / 1000 / 60 / 60) < 9999999)
{
date1 = date1.AddMilliseconds(dateint / 1000);
packettime = date1.ToLocalTime();
}
}
int readcount = 0;
while (readcount <= MAVLink.MAVLINK_MAX_PACKET_LEN)
{
// read STX byte
ReadWithTimeout(BaseStream, buffer, 0, 1);
if (buffer[0] == MAVLink.MAVLINK_STX || buffer[0] == MAVLINK_STX_MAVLINK1)
break;
readcount++;
}
if (readcount >= MAVLink.MAVLINK_MAX_PACKET_LEN)
{
throw new InvalidDataException("No header found in data");
}
var headerlength = buffer[0] == MAVLINK_STX ? MAVLINK_CORE_HEADER_LEN : MAVLINK_CORE_HEADER_MAVLINK1_LEN;
var headerlengthstx = headerlength + 1;
// read header
ReadWithTimeout(BaseStream, buffer, 1, headerlength);
// packet length
int lengthtoread = 0;
if (buffer[0] == MAVLINK_STX)
{
lengthtoread = buffer[1] + headerlengthstx + 2 - 2; // data + header + checksum - magic - length
if ((buffer[2] & MAVLINK_IFLAG_SIGNED) > 0)
{
lengthtoread += MAVLINK_SIGNATURE_BLOCK_LEN;
}
}
else
{
lengthtoread = buffer[1] + headerlengthstx + 2 - 2; // data + header + checksum - U - length
}
//read rest of packet
ReadWithTimeout(BaseStream, buffer, headerlengthstx, lengthtoread - (headerlengthstx-2));
// resize the packet to the correct length
Array.Resize<byte>(ref buffer, lengthtoread + 2);
MAVLinkMessage message = new MAVLinkMessage(buffer, packettime);
// calc crc
ushort crc = MavlinkCRC.crc_calculate(buffer, buffer.Length - 2);
// calc extra bit of crc for mavlink 1.0+
if (message.header == MAVLINK_STX || message.header == MAVLINK_STX_MAVLINK1)
{
crc = MavlinkCRC.crc_accumulate(MAVLINK_MESSAGE_INFOS.GetMessageInfo(message.msgid).crc, crc);
}
// check crc
if ((message.crc16 >> 8) != (crc >> 8) ||
(message.crc16 & 0xff) != (crc & 0xff))
{
badCRC++;
// crc fail
return null;
}
return message;
}