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.
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.