Communication with MAVProxy
Using multiple GCS with MAVProxy
When the Beaglebone black boots, MAVProxy starts as a start-up service and communicates with APM over UDP. APM (and the connection to it) is referred to as the 'master' for MAVProxy. In addition to this UDP 'connection', MAVProxy can communicate (over UDP) to multiple Ground Control Stations (referred to as slaves). Multiple ground stations are specified by using a command line option '--out':
mavproxy.py --master=/dev/ttyACM0 --out=10.1.1.1:14550 --out=127.0.0.1:12345 --out=10.1.1.1:24550
All telemetry data sent by APM is sent to each of the GCS's. Similarly, command sent by any GCS is forwarded to APM for execution. The protocol used for both telemetry data (sent by APM) and commands (sent by GCS/MAVProxy) is MAVLink. More information about MAVLink can be found here: http://qgroundcontrol.org/mavlink/start
Introduction to pymavlink
Python bindings for MAVLink are provided by 'pymavlink'. The relevant python module has an interface that works in both cases:
- for communication with APM via MAVProxy (i.e. acting as a slave for MAVProxy)
- direct communication with the APM (MAVProxy is not involved).
There are other interfaces to work with MAVLink. We focus on python (and hence pymavlink).
Working with pymavlink
- Download mavlink source:
git clone git://github.com/mavlink/mavlink.git
- Using the following command, a python module (mavlink10.py) will be generated which can read and write messages in MAVLink.
mavgen.py -o mavlinkv10.py mavlink/message_definitions/v1.0/common.xml
- APM has an additional set of messages (specified in ardupilotmega.xml). This is used for generating 'mavlink_apm.py' which is the module used in the sample program. This is is generated using the following command:
mavgen.py -o mavlinkv_apm.py mavlink/message_definitions/v1.0/ardupilotmega.xml
- This module is included in the sample program using 'import':
import mavlink_apm
- mavlink_apm.py depends on other modules in the same source tree. So, to make sure that the dependencies are resolved, the 'generator' directory and all of its sub-directories are present in same directory where the sample program resides and the following is added in the sample program:
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
- To read or write MAVLink messages, a MAVLink object needs to be created. The constructor of this class requires a file descriptor as an argument. In the sample program, a UDP socket is created and passed an argument during object creation:
mavproxy_sock = socket.socket (socket.AF_INET,socket.SOCK_DGRAM) mavproxy_sock.bind((HOST,mavproxy_port)) mav_obj = mavlink_apm.MAVLink (mavproxy_sock)
- To decode messages from the APM, the 'decode()' method of 'mav_obj' object created is used. The decoded message can be used to extract other fields (message ID, component ID, system ID etc.):
data_from_mavproxy,address_of_mavproxy = mavproxy_sock.recvfrom (1024) #Function call to receive data over UDP socket decoded_message = mav_obj.decode(data_from_mavproxy) print("Got a message with id %u, fields: %s, component: %d, System ID: %d" % (decoded_message.get_msgId(), decoded_message.get_fieldnames(), decoded_message.get_srcComponent(), decoded_message.get_srcSystem())) # prints individual fields print (decoded_message) # Prints the entire decode message
- For the sample program, two message types are of interest - one is GPS_RAW_INT, the raw sensor reading and the other is heartbeat (containing the mode). The corresponding message IDs are 24 and 1 respectively. The message IDs of interest can be found in mavlink/message_definitions/v1.0/common.xml and mavlink/message_definitions/v1.0/ardupilotmega.xml (NOTE that ardupilotmega.xml 'includes' common.xml and has some additional messages).
- To send commands to the APM, the messages have to be encoded using 'XXX_encode()' methods. There is no single encode method that works for everything - separate methods exist for each functionality and they need to be looked up in mavlink_apm.py. Once the function is figured out, common.xml and ardupilotmega.xml have to be referenced for figuring out the arguments to be passed. For example, to set the UAV in AUTO mode, the following API is used:
msg = mav_obj.set_mode_encode(1, 1, 3) mavproxy_sock.sendto(msg.get_msgbuf(),(address_of_mavproxy))