NGCTRL2
| Development / Protocol | /NGCTRL2 |
The NGCTRL2 UAV Communication Protocol
{i} This is work in progress! Please post in the forum when you find errors or mistakes!
General overview
The NGCTRL2 protocol is a simple asynchronous serial protocol used between NGOS and it’s client implementation in libng (available in the source code release). Essentially it’s a packet driven, eg. each message has a message type and messages may arrive asynchronously and out of order.
The client library libng implements everything needed to open a connection to NGOS, request data packets with arbitrary intervals and default parsers for all available packet types. A client application opens a NGCTRL2 connection, requests packet types and intervals and specifies the parser function to process received packets.
There are several parser functions implemented in libng allowing you to process the received data:
- The printf parser - Outputs receiced data packets in human readable form to the console
- The fprintf parser - Outputs receiced data packets in human readable form to a file descriptor
- The struct parser - Outputs received data packets into a pre-defined structure allowing easy access
{i} It’s also easily possible to implement your own parser function and use that.
Usage of the NGCTRL2 protocol in the NGOS shell
The NGOS shell has shell commands which allow you to inspect and manipulate the NGCTRL2 packet dumping.
Make sure to enable the API mode, so that the special API shell commands are available to you:
# mode api
Shell mode: apiYou can inspect the available packet types with the command api ngctrl-v2-list-types.
# api ngctrl-v2-list-types
NGCTRL V2 - Packet Dump valid Packet Types:
0 Gyroscopes
1 Accelerometer
2 Attitude
3 Motor 1-4
4 Motor 5-8
5 Motor 9-12
6 Motor 13-16
7 Height/Baro
8 GPS Position
9 Guessed Position
10 Debug
11 Debug Long
12 Battery
13 Position Hold
14 Flight StateYou can also inspect the NGCTRL2 packet dumping tables. In this case we are dumping 5 packet types in intervals of 500ms on UART0:
# api ngctrl-v2-list
NGCTRL V2 - Packet Dump Table:
Terminal Active
uart0 NGCTRL V2
uart1 No
usb No
Terminal Id Rate Cnt Description
uart0 0 500 318 Gyroscopes
uart0 1 500 361 Accelerometer
uart0 2 500 402 Attitude
uart0 3 500 444 Motor 1-4
uart0 4 0 0 Motor 5-8
uart0 5 0 0 Motor 9-12
uart0 6 0 0 Motor 13-16
uart0 7 500 484 Height/Baro
uart0 8 0 0 GPS Position
uart0 9 0 0 Guessed Position
uart0 10 0 0 Debug
uart0 11 0 0 Debug Long
uart0 12 0 0 Battery
uart0 13 0 0 Position Hold
uart0 14 0 0 FlightstateIt’s also possible to request packet dumping with a shell command. To start dumping packet type 4 (motors 5-8) in an interval of 500ms use the following commands:
# api ngctrl-v2-dump uart0 on
UART0: Started dump...
# api ngctrl-v2-request uart0 4 500
Activating packet type 'Motor 5-8' with intervall 500Now, NGCTRL2 is active on UART0 and sends packet type 4 all 500ms. To switch it off again, use the following shell commands:
# api ngctrl-v2-request uart0 4 0
Activating packet type 'Motor 5-8' with intervall 0
# api ngctrl-v2-dump uart0 off
UART0: Dump stopped.The command line tool NGCTRL2
ngctrl2, the command line tool, uses the parsers described on this page to implement simple command and data query access to NGOS.
It’s arguments are quite simple:
ngctrl2 - 0.63
Usage:
--verbose (-v)
--help (-h)
--device (-d)
--baud (-b)
--flowctrl (-F)
--request (-r)
--log (-l)
--log-to-file (-L)
--show-version (-V)
--execute (-e)In essence you tell it what communication port to use (–device, –baud, –flowctrl), then you tell it what to request (–request) and choose if you want to print it to your screen (–log) or to a file (–log-to-file).
A sample usage where we request packets of type 2 (attitude) with a 500ms interval:
$ ./ngctrl2 -l -r 2:500
ngctrl - 0.63
Requesting continuous data of packet type 02 in intervall 500.
Dumping NG data ...
... press any key to stop!
Current NG log data:
ATTITUDE +42 -19 +19
ATTITUDE +40 -19 +19
...As you can see the argument to –request is <packet-type>:<intervall>.
Besides requesting certain packet types, ngctrl2 will also display out-of-order packets received. An out-of-order packet is a packet, which you did not request but which gets sent to you automatically when an event happens.
A sample of an out-of-order packet can be seen here:
$ ./ngctrl2 -l -r 2:1000
ngctrl - 0.63
Requesting continuous data of packet type 02 in intervall 1000.
Dumping NG data ...
... press any key to stop!
Current NG log data:
ATTITUDE +42 -19 +19
ATTITUDE +40 -19 +19
ATTITUDE +45 -19 +19
FLIGHTSTATE landed
ATTITUDE +31 +0 +0
ATTITUDE +36 +0 +0
ATTITUDE +41 +0 +0
FLIGHTSTATE spinup
ATTITUDE +26 +0 +0
ATTITUDE +33 +0 +0
ATTITUDE +37 +0 +0
FLIGHTSTATE flying
ATTITUDE +38 +0 +0
ATTITUDE +40 +0 +0
...As you can see above, we receive a packet of type DUMP_PKG_FLIGHTSTATE, whenever NGOS changes it’s flight state.
Out-of-order packets can be ignored, or they can be handled by the client application.
Simple NGCTRL2 communications
Available NGCTRL2 packet types
The following are the available packet types in the NGCTRL2 protocol (defined in ngos/src/fc/ctrl/dump.h):
typedef enum
{
DUMP_PKG_GYROS = 0, // Gyros
DUMP_PKG_ACC = 1, // Acc
DUMP_PKG_ATTITUDE = 2, // Attitude
DUMP_PKG_MOTOR_Q1 = 3, // Motor 1-4
DUMP_PKG_MOTOR_Q2 = 4, // Motor 5-8
DUMP_PKG_MOTOR_Q3 = 5, // Motor 9-12
DUMP_PKG_MOTOR_Q4 = 6, // Motor 13-16
DUMP_PKG_HEIGHT = 7, // Height
DUMP_PKG_HOME = 8, // Home position
DUMP_PKG_GPS = 9, // GPS position
DUMP_PKG_POS = 10, // Guessed position
DUMP_PKG_TARGET = 11, // Target position
DUMP_PKG_COMPASS = 12, // Compass
DUMP_PKG_NAVIGATION = 13, // Navigation data
DUMP_PKG_DEBUG = 14, // Debug
DUMP_PKG_DEBUGLONG = 15, // Debug
DUMP_PKG_BATTERY = 16, // Battery Voltage
DUMP_PKG_FLIGHTSTATE = 17, // Flight State
DUMP_PKG_INT_SCALING = 18, // Integral Scaling
DUMP_PKG_WAYPOINTS = 19, // Waypoints
DUMP_PKG_NEXT_WAYPOINT = 20, // Next Waypoint
} dump_pkg_type_t;These are the packet types you may request together with an interval specifying how often you want to receive that data packet. Please note that packets may arrive out of order.
NGCTRL2 functions in library libng
The following functions are implemented in libng and are defined in ng.h:
- **int ng_open_uart(char dev, int baud, int flowctrl, bool bluetooth, ng_handle_t ng)
Open serial connection to NGOS using the given communication parameters and the given ng_handle_t which will be used in further libng calls.
- *int ng_close_uart(ng_handle_t ng)
Close the serial connection using the given ng_handle_t.
- *int ng_ngctrl2_initialize(ng_handle_t ng)
Initialize the NGCTRL2 protocol. The function needs a ng_handle_t as argument which can be aquired by calling ng_open_uart() earlier.
- *int ng_ngctrl2_request(ng_handle_t ng, int type, int interval)
Request to receive packet type type in interval interval.
- *int ng_ngctrl2_shutdown(ng_handle_t ng)
Shutdown the NGCTRL2 protocol on the given ng_handle_t. Don’t forget to close the connection to NGOS with ng_close_uart(ng) afterwards.
- *int ng_ngctrl2_packet_parser_printf(unsigned char pkg)
The printf parser implementation available for use with ng_ngctrl2_packet_poll().
- *int ng_ngctrl2_packet_parser_fprintf(unsigned char pkg)
The fprintf parser implementation available for use with ng_ngctrl2_packet_poll().
- *int ng_ngctrl2_packet_parser_struct_storage(unsigned char pkg)
The struct storage parser implementation available for use with ng_ngctrl2_packet_poll().
- *int ng_ngctrl2_packet_poll(ng_handle_t ng, ng_ngctrl2_packet_parser_t parser)
The dispatcher function. It registers a NGCTRL2 packet parser function which will be called for every and all NGCTRL2 packets received for a given ng_handler_t. Make sure to register only one parser per ng_handler_t. The library libng implements several parser functions for easy usage but the above function also allows you to specify your own parser function.
The NGCTRL2 protocol packet definition
NGCTRL2 dispatches NGCTRL2 packets between NGOS and PC (or better libng). Each packet may contain an arbitrary count of data-sets. All data-sets sent out within one cycle will be queued up inside a single NGCTRL2 packet and sent out together as one packet.
These packets are COBS (Constant Overhead Byte Stuffing) encoded, which makes sure that no zero byte will show up inside the packet. The NGCTRL2 packet is framed with a zero byte. Each packet contains a simple one byte checksum at the end of the packet.
{i} The COBS algorithm has a constant worst case overhead of 1 byte per 255 bytes - whereas normal byte stuffing algorithms have a non-constant worst case of up to 200% of packet size - making sure our packets will not grow madly with deformed packet data content.
A NGCTRL2 packet consists of a arbitrary length series of data-sets, a checksum and a framing bytes. Each data-set consists of a type byte, specifying the data-set data content and size, and the payload with the implicit size given by the data-set type. These arbitrary count of data-sets are followed by a one byte XOR checksum. The whole packet gets COBS encoded and framed with a zero byte.
Concluding one can specify a NGCTRL2 packet like this:
||<tablewidth=“70%” colspan=“7”>NGCTRL2 Packet|| ||<colspan=“6”>COBS Encoded||Framing|| ||<colspan=“2”>Data Set 1||<colspan=“2”>Data Set 2||…||<colspan=“2”> || ||Type 1||Data 1||Type 2||Data 2||…||checksum||0||
There are a lot of different data-set types available in NGOS.
Here is a non conclusive list of the available data-set types:
- DUMP_PKG_GYROS
- DUMP_PKG_ACC
- DUMP_PKG_ATTITUDE
- DUMP_PKG_MOTOR_Q1
- DUMP_PKG_MOTOR_Q2
- DUMP_PKG_MOTOR_Q3
- DUMP_PKG_MOTOR_Q4
- DUMP_PKG_HEIGHT
- DUMP_PKG_HOME
- DUMP_PKG_GPS
- DUMP_PKG_POS
- DUMP_PKG_TARGET
- DUMP_PKG_COMPASS
- DUMP_PKG_NAVIGATION
- DUMP_PKG_DEBUG
- DUMP_PKG_DEBUGLONG
- DUMP_PKG_BATTERY
- DUMP_PKG_FLIGHTSTATE
- DUMP_PKG_INT_SCALING
- DUMP_PKG_WAYPOINTS
- DUMP_PKG_NEXT_WAYPOINT
Each of the above data-set types can be requested by a client application, either continiously with a arbitrary interval time or just once, for a snapshot of the current state.
The NGCTRL2 packet parsers
The NGCTRL2 printf parser
Requesting data from your NG and output it using the printf parser is a simple thing consisting of a handful lines of code.
#include <ng.h>
int main()
{
ng_handle_t ngs; /* ng handle storage */
ng_handle_t *ng = &ngs; /* pointer to ng handle storage */
int type = DUMP_PKG_GYROS;
int interval = 100; // [ms]
char *device = "/dev/ttyS0"; /* open arguments */
int baud = BAUD115200;
int flowctrl = 0;
// open connection to NGOS
if ((int ret = ng_open_uart(device, baudrate, flowctrl, ng)) < 0)
{
// handle error
}
// initialize NGCTRL2 protocol
ng_ngctrl2_initialize(ng);
// request data packet
ng_ngctrl2_request(ng, type, interval);
// while user did not press a key
while (! ng_char_available(stdin))
{
int pkg_type[20];
int pkg_count;
// dispatch received packets to printf parser
pkg_count = ng_ngctrl2_packet_poll(ng, ng_ngctrl2_packet_parser_printf, pkg_type);
}
// shutdown NGCTRL2 protocol
ng_ngctrl2_shutdown(ng);
// close connection to NGOS
ng_close_uart(ng);
}{i} Make sure to link the resulting object file with the NG client library libng.so.
The NGCTRL2 fprintf parser
Requesting data from your NG and output it using the fprintf parser is very similar to using the printf parser. The only difference is that you have to open a file before hand using a special file descriptor exported by libng.
#include <ng.h>
int main()
{
ng_handle_t ngs; /* ng handle storage */
ng_handle_t *ng = &ngs; /* pointer to ng handle storage */
int type = DUMP_PKG_GYROS;
int interval = 100; // [ms]
// open connection to NGOS
if ((int ret = ng_open_uart(device, baudrate, flowctrl, ng)) < 0)
{
// handle error
}
// open file to dump into and store file descriptor in libng's parser variable
if ((ng_ngctrl2_packet_parser_fprintf_fd = fopen(file, "w")) == NULL)
{
// handle error
}
// initialize NGCTRL2 protocol
ng_ngctrl2_initialize(ng);
// request data packet
ng_ngctrl2_request(ng, type, intervall);
// while user did not press a key
while (! ng_char_available(stdin))
{
int pkg_type[20];
int pkg_count;
// dispatch received packets to printf parser
pkg_count = ng_ngctrl2_packet_poll(ng, ng_ngctrl2_packet_parser_fprintf, pkg_type);
}
// shutdown NGCTRL2 protocol
ng_ngctrl2_shutdown(ng);
// close file
fclose(ng_ngctrl2_packet_parser_fprintf_fd);
// close connection to NGOS
ng_close_uart(ng);
}{i} Make sure to link the resulting object file with the NG client library libng.so.
Your own NGCTRL2 packet parser
A NGCTRL2 packet parser is nothing more than a function with defined arguments and return value.
int myown_ngctrl2_packet_parser(unsigned char *pkg)
{
// fetch packet type
dump_pkg_type_t type = (dump_pkg_type_t)*pkg;
// fetch packet data
ctrl_ngctrl_dump_v2_t *ngdump = (ctrl_ngctrl_dump_v2_t *) (pkg + 1);
// return value should be number of bytes parsed or -1 for unknown packet
int ret = -1;
switch (type)
{
case DUMP_PKG_GYROS:
{
int wN = ngdump->d[0].i_l16; // wN.v16 = Gyro Nick
int wR = ngdump->d[0].i_h16; // wR.v16 = Gyro Roll
int wY = ngdump->d[1].i_l16; // wY.v16 = Gyro Yaw
ret = 6;
// process the gyro values
break;
}
// ... handle more packet types
}
return ret; // return number of bytes parsed
}Having defined a parser function like the one above, you can now specify it when you setup the packet dispatcher:
// dispatch received packets to parser
pkg_count = ng_ngctrl2_packet_poll(ng, myown_ngctrl2_packet_parser, pkg_type);{i} Make sure to link the resulting object file with the NG client library libng.so.