Mavlink

From Rsewiki
Revision as of 08:14, 3 November 2018 by Jca (Talk | contribs)

Jump to: navigation, search

Back to Flexbot main page

Contents

Introduction

The MAVLink protocol have been implemented in the Flexbot project to secure a standardized communication protocol with as little overhead as possible. This allows for not only transferring data over the serial USB interface between the Teensy and Intel NUC, but also for wireless transfer of all data from the NUC to client(s) and vice versa.

For more information of the MAVLink protocol itself see http://qgroundcontrol.org/mavlink/start.

This page will give information on how MAVLink is utilized in this project as well as how to update the main flexbot.xml message container and generate the C-headers + Python files needed.

Prerequisites

Make sure to have downloaded the newest version of the Flexbot repository and head into code/MAVLink/ and make sure flexbot.xml, Bridge/ and Generator/ is present.

It is further needed to install "python future" to run the MAVgenerate python application.

$ (sudo) pip install future


Adding messages to Flexbot

MAV is used between the main processor (the base_node_ros node) and the 5 Teensy controllers.

file structure

code
  +-- base_node_ros           // ros node (accessed from catkin workspace)
  |     +-- include           // directory for generated MAV library
  |           +-- flexbot_2   // generated directory
  +-- MAVLink                 // MAV link definition directory
  |     +-- flexbot_2.xml     // definition of MAV link 
  |     +-- Generator         // MAV library generator (python code)
  |           +-- mavgenerate.py  // python code for MAV library generation
  +-- teensy_2                // code for teensy
        +-- src               // source code
        +-- Makefile          // normal makefile (not using arduino IDE)
        +-- teensy_2.hex      // generated code for teensy
        +-- teensy3           // link to teensyduino installation: arduino-1.x.y/hardware/teensy/avr/cores/teensy3
        +-- libteensy         // link to teensyduin0 installation: arduino-1.x.y/hardware/teensy/avr/libraries
        +-- tools             // link to teensyduino installation: arduino-1.x.y/hardware/tools

Mesaage definition

All messages/signals to/from Flexbot are defined in flexbot.xml. A message is defined by an ID, name and description. All signals related to this message is defined by a type (uint8_t, float, etc), name and signal description.

E.g. to add a new message to Flexbot identify the last listed message ID and append to it:

<message id="16" name="TestSignal">
  <description>Test signal for this example</description>
  <field type="float" name="value1">Floating point test value.</field>
  <field type="uint8_t" name="publish">Sets whether or not Teensy should publish this message.</field>
</message>

An important note which goes for all messages is that it must contain the publish signal. This signal allows clients to subscribe to different messages and will save bandwidth as the Teensy only will publish messages that has subscribers.

By updating flexbot.xml nothing magical will happen. In order to integrate the new version of the message definitions, C-headers must be generated and the source code on both Teensy and the GUI must be altered to support the new message definitions.

Generating C-headers & Python file

In order to generate the header files used by the Teensy and GUI, a MAVLink generator program is used. This translates the message definition file (flexbot.xml) into a bunch of files related to the chosen language. In order to run the generator, go to /code/MAVLink/Generator and type

cd code/MAVLink/Generator
python mavgenerate.py

This program should only depend on Python itself (inc future) and Tkinter. See https://github.com/mavlink/mavlink for references.

In the GUI, choose XML file

~/flexbot/code/MAVLink/flexbot_2.xml 

and set output path to

~/flexbot/code/base_node_ros/include

Set the protocol to version 1.0 and choose the desired language (C).

By pressing generate, the program should generate a set of files if C has been chosen and a single file for Python.

The generated MAV C files is generated into

~/flexbot/code/base_node_ros/include

Here it will make a subdirectory called flexbot_2 with the main file to include "mavlink.h"

Old code

The old code generated by Jesper and Servet need this:

The files generated for C will need to be put into two locations. First copy all the generated files into

/code/Teensy/src/mavlink 

and replace with the ones already existing. Repeat the process for the GUI - files are located at

/code/GUI/flexbot_visualizer/mavlink

Python

The Python code is used by the Jesper/Servet code only:

For Python, the generator produces an error. This is corrected by changing line 13 from

13: from ...generator.mavcrc import x25crc

to

13: from mavcrc import x25crc

Now move the newly generated file to /code/MAVLink/Bridge and replace it with the one already existing.

Update Teensy and bridge and visualizer source code to support new messages

NB! most of this is old code, this is replaced with a ROS interface (base_node_ros).

This is considered the most important part. This ensures that the newly introduced messages are supported by software in both the Teensy source code and in the Flexbot Visualizer. There is a bit manual labour here, but with the given MAVLink protocol there is no way around it.

Updating Teensy source code

A few steps needs to be taken here to ensure that the new message is supported. First locate and open

/code/Teensy/src/command.cpp

Starting from (about) line 320 is a function called

void MAVLink_msg_handler(mavlink_message_t _msg)

This is where the incomming MAVLink messages will be processed. In order to support new messages there needs to be a section that processes each message. Follow the syntax in the code to append to the function.

E.g. for a message with ID = 3 the processing will look similar to this

else if(ID == 3)
{
  // DCCmd
  mavlink_dcwheelcmd_t msg;
  mavlink_msg_dcwheelcmd_decode(&_msg,&msg);
  dc_wheel.set(msg.dutycycle,msg.direction);
  dc_wheel.publish = msg.publish;
}

I.e. a struct available from the MAVLink generated files needs to be initialised. This struct needs to be the one that matches the message. Next the message is decoded and put into the struct. From the struct all signals will be available as showed in the example and existing source code.

The general idea is that each message is associated with a class (or signal) that has an attribute called publish. This will become useful when printing data over the USB serial interface. This is seen by looking at

void printSensorStatus()

in command.cpp. This function call all classes' print_data()-function which could look similar to this

void Linear_Actuator::print_data()
{
  if (publish)
  {
    uint8_t buf[2041];
    mavlink_message_t msg;
    mavlink_msg_act1sts_pack(0,0,&msg,0,current, publish);
    uint16_t len = mavlink_msg_to_send_buffer(buf,&msg);
    usb_serial_write(buf,len);
  }
}

where the data is printed only if publish is set.


This is basically what needs to be done in the Teensy source code. It is important to make sure that each received signal is decoded and processed.

Updating Flexbot Visualizer source code

Two files needs to updated here. First locate and open

/code/GUI/flexbot_visualizer/receiver.cpp

and go to the function

QList<int> Receiver::process_MAVLink_msg(mavlink_message_t _msg)

As with the Teensy source code, the GUI also needs to process all incoming MAVLink messages. An example to this could be

else if(ID == 3)
{
  // DCCmd
  mavlink_dcwheelcmd_t msg;
  mavlink_msg_dcwheelcmd_decode(&_msg,&msg);
  flexbot->update(flexbot->MavIDtoID(ID),msg.speed);
  IDarray.push_back(flexbot->MavIDtoID(ID));
  flexbot->update(flexbot->MavIDtoID(ID)+1,msg.publish);
  IDarray.push_back(flexbot->MavIDtoID(ID)+1);
}

Again the message is decoded, and the signal values are used to update the local values held by the GUI. Follow the examples already existing in the source code.

Next locate and open

/code/GUI/flexbot_visualizer/sender.cpp

and go to the function

void Sender::process_mavlink_message(int ID)

Here each value for a given signal is retrieved from the GUI and packed as a MAVLink struct. An example of this is

else if(ID == 3)
{
 // DCCmd
 double speed = flexbot->getValue("DCWheelCmd","speed");
 int dc = flexbot->getValue("DCWheelCmd","dutycycle");
 int dir = flexbot->getValue("DCWheelCmd","direction");
 int publish = flexbot->getValue("DCWheelCmd","publish");
 mavlink_msg_dcwheelcmd_pack(0,0,&msg,speed,dc,dir,publish);
}

Follow the examples already existing in the source code.

Closing remarks

This is all that needs to be done to add new signals/messages to Flexbot.

Some manual labour goes into hardcoding these functions as they cannot exist dynamically. It is very important that this is completed every single time a message is added. Otherwise the MAVLink interface, GUI and general communication simply cannot work. So please make sure this is complied to at all times!

Questions about this can be referred to Jesper Christensen: jesper@haahrchristensen.dk



--Jca (talk) 13:02, 9 June 2018 (CEST)

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox