Send and receive messages from a serial device with python¶
This tutorial explains how to send and receive messages to and from a serial device.
We will make a program that periodically sends PING messages to a serial device, while monitoring the device to print every paparazzi message received on it. When it receives a PING it will send back a PONG. This is ment to be tested with a loopback serial device (a FTDI cable with RX and TX linked).
The tutorial code will be written in the SerialTutorial
class so as to keep state information.
Creating the pprzlink.serial.SerialMessagesInterface
¶
First of all we need to create a pprzlink.serial.SerialMessagesInterface
object to handle sending and receiving data.
self.serial_interface = pprzlink.serial.SerialMessagesInterface(
callback = self.process_incoming_message, # callback function
device = args.dev, # serial device
baudrate = args.baud, # baudrate
interface_id = args.ac_id, # id of the aircraft
)
Here we create an interface that will bind to a serial device (args.dev
) at the specified baud rate (args.baud
). The id of the local system is set to args.id
and messages arriving on the serial device for this id will be passed along with the source id to the self.process_incoming_message()
callback function (see Receiving messages).
Note that the construction of pprzlink.serial.SerialMessagesInterface
can take additional parameters that we will ignore in this tutorial.
Receiving messages¶
When a message arrives on the serial device specified in the creation of the interface, the id of the destination of the message is checked. If the interface_id
specified in the interface creation is the same as the destination id of the message, then the callback function will be called.
# Callback function that process incoming messages
def process_incoming_message (self, source, pprz_message):
Here the callback function just prints the message and the id of the source.
Sending messages¶
To send a message, we just need to call the pprzlink.serial.SerialMessagesInterface.send()
function. We send the message from our id to ourselves.
# create a ping message
ping = message.PprzMessage('datalink', 'PING')
# send a ping message to ourselves
print("Sending ping")
self.serial_interface.send(ping, self.ac_id,self.ac_id)
Filtering messages on type¶
In order to filter the messages according to their type, we will use the pprzlink.message
API. It can be as simple as testing the name
attribute of the message.
Here we use this so as to answer with a PONG message to any PING message sent to us. We send it from our id to the id of the source of the PING message.
if pprz_message.name == "PING":
print ("Sending back PONG")
pong = message.PprzMessage('telemetry', 'PONG')
self.serial_interface.send(pong, self.ac_id,source)
Complete file¶
The complete file for this tutorial is here
.
#!/usr/bin/env python
import pprzlink.serial
import pprzlink.messages_xml_map as messages_xml_map
import pprzlink.message as message
import time
import argparse
class SerialTutorial:
"""
Class SerialTutorial that uses pprzlink.serial.SerialMessagesInterface to send
PING messages on a serial device and monitors incoming messages.
It respond to PING messages with PONG messages.
"""
# Construction of the SerialTutorial object
def __init__(self,args):
self.serial_interface = pprzlink.serial.SerialMessagesInterface(
callback = self.process_incoming_message, # callback function
device = args.dev, # serial device
baudrate = args.baud, # baudrate
interface_id = args.ac_id, # id of the aircraft
)
self.ac_id = args.ac_id
self.baudrate = args.baud
# Main loop of the tutorial
def run(self):
print("Starting serial interface on %s at %i baud" % (args.dev, self.baudrate))
try:
self.serial_interface.start()
# give the thread some time to properly start
time.sleep(0.1)
while self.serial_interface.isAlive():
self.serial_interface.join(1)
# create a ping message
ping = message.PprzMessage('datalink', 'PING')
# send a ping message to ourselves
print("Sending ping")
self.serial_interface.send(ping, self.ac_id,self.ac_id)
except (KeyboardInterrupt, SystemExit):
print('Shutting down...')
self.serial_interface.stop()
exit()
# Callback function that process incoming messages
def process_incoming_message (self, source, pprz_message):
print("Received message from %i: %s" % (source, pprz_message))
if pprz_message.name == "PING":
print ("Sending back PONG")
pong = message.PprzMessage('telemetry', 'PONG')
self.serial_interface.send(pong, self.ac_id,source)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--device", help="device name", dest='dev', default='/dev/ttyUSB0')
parser.add_argument("-b", "--baudrate", help="baudrate", dest='baud', default=115200, type=int)
parser.add_argument("-id", "--ac_id", help="aircraft id (receiver)", dest='ac_id', default=42, type=int)
args = parser.parse_args()
serialTutorial = SerialTutorial(args)
serialTutorial.run()