Services#
Description#

Services are standalone processes dedicated to a specific Flight mission.
They produce outputs that are used by Flight supervisor states machine or Guidance modes. They have access to all data exchanges (Telemetry, Messages, Video) and all Linux interfaces (Storage, 4G, Wi-fi, USB).
The typical use cases are: computer vision, sensors acquisition, data streaming.
Important
A Service can be written either in C/C++
or in Python
.
Language must be chosen carefully depending on the Flight mission and
required processing. C/C++
has to be chosen when real time is a
priority.
A Service is generally implemented using a single event loop (single threaded program) that runs indefinitely. You can use a set of components already present in the drone (see Framework) and you can add your own custom libraries.
Services run as a non privileged linux user.

How to write a service#
C#
Here is a typical skeleton of C
service:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <libpomp.h> #define ULOG_TAG service #include <ulog.h> ULOG_DECLARE_TAG(ULOG_TAG); struct context { struct pomp_loop *loop; struct pomp_timer *timer; } static struct context s_ctx; static volatile int stop; static void sighandler(int signum) { ULOGI("signal %d (%s) received", signum, strsignal(signum)); // ask the event loop to exit stop = 1; pomp_loop_wakeup(s_ctx.loop); } static void timer_cb(struct pomp_timer *timer, void *userdata) { struct ctx *ctx = userdata; ULOGI("Hello world"); } int main(int argc, char *argv[]) { // create a new event loop and a timer s_ctx->loop = pomp_loop_new(); s_ctx->timer = pomp_timer_new(s_ctx->loop, timer_cb, s_ctx); // signal handler to exit properly on interrupt and termination signal(SIGINT, &sighandler); signal(SIGTERM, &sighandler); signal(SIGPIPE, SIG_IGN); // configure the timer every seconds pomp_timer_set_periodic(s_ctx->timer, 1000, 1000); // run indefinitely until stop while (!stop) pomp_loop_wait_and_process(s_ctx.loop, -1); // clean up signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGPIPE, SIG_DFL); pomp_timer_destroy(s_ctx->timer); pomp_loop_destroy(s_ctx->loop); return EXIT_SUCCESS; }
Python#
Here is a typical skeleton of Python service:
import logging import os import sys import ulog import libpomp def update(self): logger.info("Hello world") def main(): def sighandler(signum, stack): # ask the event loop to exit nonlocal run, loop logging.debug(f"signal {signum} received") run = False libpomp.pomp_loop_wakeup(loop) run = True logger = logging.getLogger(None) logger.addHandler(ulog.ULogHandler()) if os.getenv('ULOG_LEVEL') == 'D': logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) # signal handler to exit properly on interrupt and termination signal.signal(signal.SIGINT, sighandler) signal.signal(signal.SIGTERM, sighandler) # create a new event loop and a timer loop = libpomp.pomp_loop_new() timer_cb = libpomp.pomp_timer_cb_t(lambda *_: update()) timer = libpomp.pomp_timer_new(loop, timer_cb, None) # configure the timer every seconds libpomp.pomp_timer_set_periodic(timer, 1000, 1000) while run: # timeout here is needed for signal handler libpomp.pomp_loop_wait_and_process(loop, 500) # clean up libpomp.pomp_loop_destroy(loop) if __name__ == '__main__': main()
Example#
See Hello Service and the code is available here.
Running multiple services#
It is possible to run multiple services per mission. For this, it is necessary to add a new element in the list named “services” present at the end of the mission.yaml file:
services:
srv-example1:
lang: c
args: ["arg1", "arg2"]
srv-example2:
lang: c
args: ["arg1"]
Note
Reminder: The file mission.yaml is located in the root directory of your mission. The airsdk init is here to help you getting started with a new mission project and can generate your first service boilerplate for you.
Important
The maximum number of simultaneous running services is 8 per mission.