Modifying MissionPlanner and using MAVLink

A project log for Small Autonomous Survey Vessel

An autonomous little boat that scans and maps lakes and rivers.

cees-meijerCees Meijer 07/07/2020 at 18:470 Comments

Since I was writing my own controller software for the Raspberry Pi I first considered taking the shortest path to transferring the the data from my boat to shore: send everything as ASCII text and use a simple text parser to decode values. Easy to write, easy to debug. But a lot of overhead, and since my radio only supports 9600 baud this would seriously limit the amount of data I could transfer. Just create my own binary structure then (maybe using Binary JSON) ? But there is also MAVLink, a standard protocol for transferring data between 'Groundstation' and a Rover (Drone, plane, boat).

MAVLink Logo

Unfortunately this is also a big project, and although it is not too complicated in the end, the whole documentation seems very intimidating at first. But after a little trial and error I got it going. It helps that the most commonly used groundstation software is MissionPlanner which is open source.

MissionPlanner Logo

MissionPlanner is also a big project, but as I'm used to C# projects it did not take me long to find my way around. Fortunately it just builds and runs directly if you checkout the whole project and compile it with Visual Studio.

Generating a custom message

For the Sonar I will need a custom message to transmit range, distance etc. This can be added to the 'common.xml' file, which can be found in the MissionPlanner folder:

C:\Users\ceesm\Documents\Autonomous Survey Vessel\MissionPlanner\ExtLibs\Mavlink\message_definitions\common.xml

<message id="1000" name="SCANNING_SONAR">
   <description>Scanning sonar.</description>
     <field type="uint32_t" name="time_boot_ms" units="ms">Timestamp (time since system boot).</field>
     <field type="uint16_t" name="range" units="mm">Measured range</field>
     <field type="uint16_t" name="angle" units="0.1 degrees">Angle</field>
     <field type="uint16_t" name="roll" units="0.1 deg">Roll</field>
     <field type="uint16_t" name="pitch" units="0.1 deg">Pitch.</field>
     <field type="uint16_t" name="yaw" units="0.1 deg">Heading.</field>

 And that is all there is to it. This simply defines a message with ID 1000 that contains the required filelds.

In the MAVLink folder there is a 'regenerate.bat' file that produces a new C# library from a modified .XML file, and regenerate.bat also contains a line for doing the same for the C library. Which almost works, except for the fact that the 'pymavlink' folder is not complete, and does not contain all the required headers. So I checked out a complete MAVlink set from After copying the pymavlink folder to MissionPlanner it works fine.

Processing custom MAVLink messages

Now I defined a new messagetype and named it SCANNING_SONAR, there must be a way to view it in MissionPlanner, but how ? I found the solution in the 'MAVLinkInspector.cs' module. When opened, this window shows the messages as they are received, and even has an option to create a live chart of the incoming data. Key to this interaction seems to be the SubscribeToPacketType function:

var subscribeToPacket =
                    message =>
                        line.AddPoint(new XDate(message.rxtime),
                        return true;

So I created a new form (SonarView) with a start button, a textbox, and just the following function:

namespace MissionPlanner.Controls
    public partial class SonarView : Form
        private MAVLinkInterface mav;
        public SonarView(MAVLinkInterface mav)
            this.mav = mav;

        private void but_start_Click(object sender, EventArgs e)
            var subscribeToPacket =
                  message =>

                      MAVLink.mavlink_scanning_sonar_t S = (MAVLink.mavlink_scanning_sonar_t);
                      string data_txt = $"Data:{S.time_boot_ms},{S.range},{S.angle},{S.roll}{S.pitch}";

                      data_txt += Environment.NewLine;
                      textBox1.Invoke(new Action(() => textBox1.Text += data_txt)); 

                       return true;

And this works. The messages are caught, and show up on the textbox . 

So after tweaking it a bit and adding a ZedGraph chart it looks like this:

(Of course there is more to it, so if you want to know the details check out my version of MissionPlanner, and find the 'SonarView' module.)