LogoLogo
  • Welcome
  • Vehicle Operation
    • Getting started
    • Auterion Suite
      • Dashboard
      • Fleet Management
        • Vehicles
          • Cloud Features
          • Groups
        • Flights
        • Compliance
      • Manufacturer
        • Service Bulletins
      • Administration
      • User Management
      • Simulations
    • Auterion Mission Control
      • Installation
      • First steps
      • UI Breakdown
        • Navigating between the views
        • Fly View
          • Fly View UI Overview
          • Vehicle status indicator
          • Flight mode selector
          • Quick actions sidebar
          • Connection manager
          • Vehicle Dashboard
          • Flight Map
          • Camera View
          • Monitoring the Flight
          • Flying Manually (RC/Joystick)
          • Flying a Mission
        • Plan View
          • Plan UI Overview
          • Plan tools
            • Mission Menu
            • Waypoint Missions
            • Survey Patterns
              • Area Survey
              • Corridor Scan
          • Mission Summary
          • Mission Editor Tab
            • Start Section
            • Mission Section
            • End Section
            • Extras
          • Terrain visualization
          • GeoFence
          • Rally Points
        • Quick Vehicle Menu
          • Pre-Flight Checklist
          • Connectivity
        • Photo Gallery
        • Settings
        • Pilot Login
      • Useful resources
        • Mission Planning
          • Mission Cloud Sync
          • Terrain Following
          • Import Geo-Awareness data or KML overlays
        • Maps and Custom Overlays
          • Using Offline Maps
          • Importing GeoPDF overlays
        • Track GCS as Smart Asset in Suite
        • Live PX4 Log Streaming
        • Monitor Local Flights with ADS-B
        • GPS Denied Workflow
        • Windows Crash Logs Analysis
        • Screen Recordings
    • Remote Controllers
      • Skynav Remote Controller
        • Installing Mission Control
        • Joystick and Button Mapping
        • Using LTE for Online Maps in the Field
        • Advanced Radio Settings
        • Drop Guards and Chest Strap
        • Unit Serial Number
    • Settings & Maintenance
      • Vehicle Setup
      • WiFi Setup
      • Compass Calibration
      • Safety Setup
      • Joystick Setup
      • Vehicle Web UI
      • Software Update
      • Remote ID
        • How Remote ID works
        • Remote ID indicators in AMC
        • Frequently Asked Questions
    • Precise Flight
  • App development
    • Getting Started
      • Development environment Setup
      • Connecting to a device
      • Application Development
    • App Framework
      • Building your First App
      • Apps API
      • Sensor Data
      • Video Streams
      • Photos
      • Hardware Peripherals
      • Persistent Storage
      • MAVLink
      • Native Docker Compose
      • App Parameters
      • Log App Data to Auterion Suite
        • How to log Time Series Data
        • How to log basic Text Output
      • How to store an App's Binary Data on Skynode
      • User Web Interfaces
      • Build Arguments
      • Debugging apps with SSH
      • Debugging Apps with gdb
      • PX4 Messages in ROS 2
      • DDS / ROS2 Configuration
      • Structuring Applications with Multiple Services
    • Auterion SDK
      • Installation
      • Write Your First App
      • SDK API
      • Flight Mode API
        • Flight Mode API
        • Dynamics in Body Frame
        • Dynamics in Local Frame
        • Go-To in Local Frame
      • System State API
      • Peripheral Actuator Control API
      • Camera API
      • Navigation Input API
        • Global Navigation
        • Local Navigation
      • Visual Tracking API
    • Simulation
      • Virtual Skynode
        • Simulation-Gazebo Reference
        • Simulation-AirSim Reference
        • Connecting from other Computers
        • Resetting Virtual Skynode
        • Multiple Virtual Skynodes on single machine
      • Physical Skynode
    • Resources
      • Cross Compilation - Faster Builds
      • Auterion CLI Reference
      • Troubleshooting
      • App Tutorial
      • Skynode Vision Kit S
        • Set up the Vision Kit
        • Install and test a simple vision app
    • Legacy app workflow
      • App Development
      • MAVLink
      • Using the App Template
      • Example Applications
        • Autopilot Telemetry (C++)
        • Autopilot Telemetry (Python)
        • Photo Gallery
  • Hardware Integration
    • Getting started
      • Required Sensors
      • Wiring Skynode to the Vehicle
      • Actuators Setup
      • Sensors Setup
        • Set Orientations
        • Compass Calibration
        • Gyroscope calibration
        • Accelerometer calibration
        • Level horizon calibration
        • Airspeed calibration
      • Bench Test
      • Tuning
      • Creating Airframe Configurations for APX4
    • Skynode
      • Skynode X
      • Skynode ENT/GOV
      • Skynode X Integration and Development Kit
        • Get Skynode ready
        • Power Skynode
        • Register Skynode
        • Connect Skynode to AMC
        • Sensors and Peripherals
        • Next steps
      • Payloads
        • Generic USB Webcams (UVC)
        • Workswell Wiris Pro
        • Trillium HD40-LV
        • NextVision Gimbals (with TRIP2)
        • Sony Alpha a7R IV
        • Phase One iXM-100
        • Gremsy Gimbals
      • Connectivity
        • USB-C Network Connection
        • WiFi
        • LTE Setup
        • SIYI MK15
        • Microhard Data Link
        • Data Link Wiring
        • Silvus Data Link
        • Doodle Labs Data Link
        • Custom Data Link
        • Ethernet Interface Configuration
      • Skynode LED Meanings
      • Troubleshooting
      • Legacy DSM/DSMX Support
      • Peripherals
        • Power Module
        • 12S Power Module
        • Pixhawk Adapter Board
        • Pixhawk Payload Bus
        • Data Link Module
        • PX4 F9P GPS
        • Freefly RTK GPS
        • Airspeed Sensor
        • LIDAR
        • USB camera
        • See3CAM_24CUG
    • Skynode S
      • Datasheet
      • Interfaces
      • Basic Vehicle Integration
      • Add LTE to Skynode S
      • Skynode S LED status indicator
      • Skynode S flight logs
    • AI Node
      • Datasheet
      • Evaluation Kit
        • Power AI Node
        • Wiring AI Node to Skynode
        • Internet sharing with Skynode
        • Activate AI Node on Suite
      • Dimensions and CAD model
      • Interfaces
      • Connectivity
        • USB Network Connection
        • Serial Debug Connection
        • AI Node as Network Bridge
        • Standalone Internet Access
      • Updating AuterionOS
    • Advanced Airframe Integration
      • Custom power setup
      • Wiring without Breakout Boards
      • Gripper Integration
        • Setting up Payload Delivery with Gripper
      • ESC Calibration
      • Camera Calibration
        • Camera Calibration on a Computer
        • Camera Calibration on Skynode
      • Serial Port Configuration
    • Flight controller customization
      • AMC's Advanced Mode
      • Flight Controller Shell
      • Micro XRCE-DDS
    • AuterionOS Customization
      • OEM Tools Installation
      • Adding SSH keys
      • Changing the Root Password
      • Modifying Environment Variables
      • Pre-install Applications
      • Suite Manufacturer Tools
    • AuterionOS System Guide
      • Introduction
      • Flashing PX4 Binary and Vehicle Config
      • Building and Flashing PX4 Firmware
      • SSH Access
      • Filesystem and partitions
      • Environment Variables Reference
      • Types of AuterionOS Images
      • Mavlink Routing and Endpoints
      • Packaging AuterionOS Image
    • Additional Resources
      • Remote ID
        • How Remote ID works
        • Vehicle Serial Number
        • Communication Diagram
        • Remote ID configuration
        • How Auterion tested
      • Auto-Tuning
  • Release Notes
    • APX4
      • APX4 3.2
        • APX4 3.2.1
      • APX4 3.1
        • APX4 3.1.1
        • APX4 3.1.0
      • APX4 3.0
        • APX4 3.0.8
        • APX4 3.0.5
      • APX4 2.7
        • APX4 2.7.37
        • APX4 2.7.25
        • APX4 2.7.20
        • APX4 2.7.12
        • APX4 2.7.7
        • APX4 2.7.6
      • APX4 2.6
        • APX4 2.6.1
      • APX4 2.5
        • APX4 2.5.14
        • APX4 2.5.13
        • APX4 2.5.8
        • APX4 2.5.7
        • APX4 2.5.5
        • APX4 2.5.4
        • APX4 2.5.0
      • APX4 2.4
        • APX4 2.4.2
        • APX4 2.4.1
      • APX4 2.3
        • APX4 2.3.0
      • APX4 2.2
        • APX4 2.2.2
        • APX4 2.2.0
      • APX4 2.1
        • APX4 2.1.1
        • APX4 2.1.0
      • APX4 2.0
        • APX4 2.0.2
        • APX4 2.0.0
    • AuterionOS
      • AOS for AI Node
        • AI Node AOS 1.1.0
        • AI Node AOS 1.0.2
        • AI Node AOS 1.0.0
        • AI Node AOS 0.7.0
        • AI Node AOS 0.6.1
        • AI Node AOS 0.6.0
        • AI Node AOS 0.5.0
        • AI Node AOS 0.4.0
      • AOS for Skynode
        • AOS 3.7
          • AOS 3.7.14
          • AOS 3.7.9
        • AOS 3.6
          • AOS 3.6.14
        • AOS 3.5
          • AOS 3.5.13
        • AOS 3.3
          • AOS 3.3.9
        • AOS 3.2
          • AOS 3.2.9
        • AOS 2.19
          • AOS 2.19.14
        • AOS 2.15
          • AOS 2.15.10
          • AOS 2.15.7
        • AOS 2.12
          • AOS 2.12.8
        • AOS 2.10
          • AOS 2.10.2
        • AOS 2.8
          • AOS 2.8.1
        • AOS 2.7
          • AOS 2.7.15
        • AOS 2.6
          • AOS 2.6.1
        • AOS 2.5
          • AOS 2.5.14
          • AOS 2.5.13
          • AOS 2.5.8
          • AOS 2.5.7
          • AOS 2.5.5
          • AOS 2.5.4
          • AOS 2.5.0
        • AOS 2.4
          • AOS 2.4.1
        • AOS 2.3
          • AOS 2.3.0
        • AOS 2.2
          • AOS 2.2.2
          • AOS 2.2.0
        • AOS 2.1
          • AOS 2.1.1
          • AOS 2.1.0
        • AOS 2.0
          • AOS 2.0.2
          • AOS 2.0.0
    • Auterion Mission Control
      • AMC 1.34
        • AMC 1.34.19
        • AMC 1.34.14
      • AMC 1.33
        • AMC 1.33.13
      • AMC 1.32
        • AMC 1.32.7
      • AMC 1.30
        • AMC 1.30.17
      • AMC 1.29
        • AMC 1.29.7
      • AMC 1.26
        • AMC 1.26.8
      • AMC 1.22
        • AMC 1.22.3
      • AMC 1.19
        • AMC 1.19.5
      • AMC 1.18
        • AMC 1.18.3-1
        • AMC 1.18.3
      • AMC 1.17
        • AMC 1.17.10
        • AMC 1.17.9
      • AMC 1.15
        • AMC 1.15.0
      • AMC 1.14
        • AMC 1.14.6
        • AMC 1.14.0
      • AMC 1.13
      • AMC 1.12
      • AMC 1.11
      • AMC 1.10
        • AMC 1.10.1
        • AMC 1.10.0
      • AMC 1.9
        • AMC 1.9.1
        • AMC 1.9.0
      • AMC 1.8
    • Hardware
      • Skynode Rev 11 (Jan 2022)
Powered by GitBook
On this page
  • Getting started
  • Tutorial App functions Overview
  • Setting Up the Development Environment
  • Structure
  • Directory Structure of the App
  • Git submodules
  • auterion-app.yml
  • main.cpp
  • index.html
  • CMakeList.txt
  • Dockerfile
  • Installation on Skynode
  • Discover Skynode using Auterion CLI
  • Build and Install app on Skynode using Auterion CLI
  • Get status and logs from app running on Skynode using Auterion CLI
  1. App development
  2. Resources

App Tutorial

Tutorial for creating an AuterionOS App

PreviousTroubleshootingNextSkynode Vision Kit S

Last updated 1 year ago

Getting started

Tutorial App functions Overview

The Tutorial App allows the user to access the vehicles position data from a custom UI and even command position changes. Follow this guide to learn how to write an app that can read and influence the state of the vehicle and make it accessible from a custom UI.

These are the main functions this app provides which will be explained in this guide.

  • Telemetry reading

  • Command sending

  • Custom UI

Along with these functions there will also be general explanations on the structure and functions of AuterionOS apps and how to build, install and use those apps.

Setting Up the Development Environment

Install the Auterion CLI

The Auterion CLI can easily be installed using PIP (python’s package manager) with the following command:

pip3 install auterion-cli

To get more detailed Information on the Setup go to

Development environment Setup

Get the Tutorial App Code

Clone the app-tutorial-code Repository to use the example code, take a look at one of the example codes in Application Development or build up your own according to the structure outlined in the next section.

Structure

Every AuterionOS app should follow the same file structure in order to be built and deployed using the Auterion CLI. There are 3 things that make up an AuterionOS app and these will be explained in the following 3 subsections. More information about this topic can be found in the Application Development Section.

For this app mavlink and libmav are used so they need to be added as git submodules.

Directory Structure of the App

An AuterionOS app minimally requires an auterion-app.yml needs to be in the root directory, in this case app-tutorial-code. The rest of the structure is optional, but all the referencing in the example code is based on this structure so any changes to the structure need to be changed there as well. The Dockerfile, the submodules that will be added and the source code will be in services/web-navigation. Since this app will be in C++, the CMakeList.txt will be in this directory as well, main.cpp will be in the src folder and the index.html in the website folder.

app-tutorial-code/              # Root directory of the application
    auterion-app.yml            # Auterion app metadata file. Has to be in root dir
    services/                   # Folder to contain the individual services
        web-navigation/         # Folder for the "web-navigation" service
            Dockerfile          # Describes how "web-navigation" image is built
            CMakeLists.txt      # Describes how our C++ app is built
            src/                # Diretory for source code of our C++ app
                main.cpp        # Source code of our C++ app
            website/            # Directory for the HTML content of our web-UI
                index.html      # Source code of our web UI
            libmav[subm]/       # libmav C++ library as submodule
            mavlink[subm]/      # mavlink message definitions as submodule

Git submodules

After creating the directory the app will be created in, use git to add the necessary submodules. If git isn't already installed you can follow this Guide. To turn your created directory into a git repository use git init.

git init

Then add libmav and mavlink as submodules to your repository by going to the directory the submodules should be added to and using git submodule add.

cd services/web-navigation/
git submodule add https://github.com/Auterion/libmav.git
git submodule add https://github.com/mavlink/mavlink.git

auterion-app.yml

Contains all meta-information about the app, like name, version, author etc. This file needs to be in the project root directory. Each build entry points to the location of a Dockerfile that needs to be built and run. More detailed explanations can be found here.

auterion-api-version: 2               # Auterion API version this app is targeting
auterion-app-base: v2                 # Version of the auterion/app-base

app-name: tutorial-web-navigation     # The name of your app
app-version: 0.0.1                    # The version of your app
app-author: com.auterion              # The authoring entity (reverse-domain notation)
target-platform: [skynode, ainode]    # Supported platforms (skynode or ainode)

Like in docker-compose, your app can consist of multiple docker containers. In 'services' you list all the docker containers that make up your app. In most cases, this is just one service. The API configuration for the web interface is also added here.

services:
  web-navigation:                        # Name of the service
    build: services/web-navigation       # Location of the Dockerfile
    ssh: true                            # Enable SSH port forwarding

    http:
      /:                                 # The URI that should be mapped
        static-root: /data/webroot       # Static content points to a directory
        function: 
          type: ui                       # Assign function UI to the endpoint
          label: Tutorial Web Navigation # Make site reachable from vehicle webpage
      
      /api:                              # The URI that should be mapped
        proxy:                           # Proxying the requests
          port: 8080                     # The port in the docker container to proxy to

main.cpp

Create this file in services/web-navigation/src. It contains all the necessary C++ code. First some general setup.

#include <mav/MessageSet.h>
#include <mav/TCPClient.h>
#include <mav/Network.h>
#include <restinio/all.hpp>
#include <cmath>

Then a struct for the vehicle coordinate and one for the system state.

struct Coordinate {
    double latitude;
    double longitude;
};

struct SystemState {
    Coordinate position;
    double altitude;
    double battery_percentage;
};

To later use for the change in position, functions which change the coordinate a given distance. For this example, this uses a crude distance estimation function, but is sufficient for demo purpose.

Coordinate extendSouth(Coordinate point, double distance) {
    double r_earth = 6378;
    double new_latitude = point.latitude - (distance / r_earth) * (180 / M_PI);
    return Coordinate{new_latitude, point.longitude};
}

Coordinate extendWest(Coordinate point, double distance) {
    double r_earth = 6378;
    double new_longitude = point.longitude - (distance / r_earth) * (180 / M_PI) / cos(point.latitude * M_PI / 180);
    return Coordinate{point.latitude, new_longitude};
}

The code from Telemetry Reading and Sending Commands will be added to the "App" class.

class App {
private:
    mav::MessageSet _message_set;
    std::shared_ptr<mav::TCPClient> _phy;
    std::shared_ptr<mav::NetworkRuntime> _runtime;
    std::shared_ptr<mav::Connection> _connection;

    std::mutex _system_state_mtx;
    SystemState _system_state;
    
    //add code here
    
public:
    App() : _message_set("mavlink/common.xml") {
    }
    
    void run() {
        connectMAVLink();
        std::cout << ".. Connected to MAVLink" << std::endl;
        auto global_position_int_id = _message_set.idForMessage("GLOBAL_POSITION_INT");
        auto battery_status_id = _message_set.idForMessage("BATTERY_STATUS");
    
        //add code here
    
    }
};

int main(int argc, char** argv) {
    App app;
    app.run();
    return 0;
}

Telemetry Reading

To get flight information or to influence the flight path Mavlink messages can be used. In the Tutorial App a Mavlink connection is established and then used to receive Telemetry data and send commands for a position change to the flight controller. In this App libmav is used.

To create an interface for the Mavlink connection and connect with Mavlink, add this to the private section of main.cpp. It will be called in run().

void connectMAVLink() {
   // Create interface
   _phy = std::make_shared<mav::TCPClient>("10.41.1.1", 5790);

   mav::Message heartbeat = _message_set.create("HEARTBEAT").set({
        {"type",          _message_set.e("MAV_TYPE_GENERIC")},
        {"autopilot",     _message_set.e("MAV_AUTOPILOT_INVALID")},
        {"base_mode",     _message_set.e("MAV_MODE_FLAG_CUSTOM_MODE_ENABLED")},
        {"custom_mode",   0},
        {"system_status", _message_set.e("MAV_STATE_ACTIVE")}
   });
   _runtime = std::make_shared<mav::NetworkRuntime>(_message_set, heartbeat, *_phy);
   _connection = _runtime->awaitConnection(1000);
}

Get the Telemetry information from the vehicle and safe the system state. This is a callback that needs to be added to run() in the public section.

_connection->addMessageCallback([this,
        global_position_int_id, battery_status_id](const mav::Message &message) {
    if (message.id() == global_position_int_id) {
        std::lock_guard<std::mutex> lock(_system_state_mtx);
        _system_state.position.latitude = message["lat"].as<double>() / 1e7;
        _system_state.position.longitude = message["lon"].as<double>() / 1e7;
        _system_state.altitude = message["alt"].as<double>() / 1e3;
    } else if (message.id() == battery_status_id) {
        std::lock_guard<std::mutex> lock(_system_state_mtx);
        _system_state.battery_percentage = message["battery_remaining"].as<double>();
    }
});

Sending Commands

The tutorial App uses a custom interface explained in the index.html section to change the position of the vehicle. The main.cpp handles these requests and communicates them to the flight controller.

Create a router to handle the http requests from the web interface. This router is created with restinio, to learn more go to RESTinio Documentation. Add this to the private section of the code.

std::unique_ptr<restinio::router::express_router_t<>> createRouter() {
    auto router = std::make_unique<restinio::router::express_router_t<>>();
    
    //add code for telemetry data
    //add code for reposition commands
    
    return router;
}

Add this to createRouter() to provide the telemetry data for the web interface.

router->http_get(
    R"(/telemetry)",
    [this](auto req, auto params) {
        std::lock_guard<std::mutex> lock(_system_state_mtx);
        return req->create_response()
            .append_header(restinio::http_field::content_type, "text/json; charset=utf-8")
            .append_header(restinio::http_field::access_control_allow_origin, "*")
            .set_body(fmt::format("{{\"latitude\": {}, \"longitude\": {}, \"altitude\": {}, \"battery_percentage\": {}}}",
                                 _system_state.position.latitude, _system_state.position.longitude, _system_state.altitude, _system_state.battery_percentage))
            .done();
    });

Add this to createRouter() to handle the reposition commands from the web interface

router->http_post(
    R"(/commands/reposition)",
    [this](auto req, auto params) {

        std::string direction = req->body();
        std::lock_guard<std::mutex> lock(_system_state_mtx);
        Coordinate new_position{};
        if (direction == "north") {
            new_position = extendSouth(_system_state.position, -0.001);
        } else if (direction == "south") {
            new_position = extendSouth(_system_state.position, 0.001);
        } else if (direction == "east") {
            new_position = extendWest(_system_state.position, -0.001);
        } else if (direction == "west") {
            new_position = extendWest(_system_state.position, 0.001);
        } else {
            return req->create_response(restinio::status_not_found())
                .append_header(restinio::http_field::content_type, "text/json; charset=utf-8")
                .set_body("{ \"status\": \"error\", \"message\": \"unknown direction\" }")
                .done();
        }
        std::cout << "Old position: " << _system_state.position.latitude << ", " << _system_state.position.longitude << std::endl;
        std::cout << "New position: " << new_position.latitude << ", " << new_position.longitude << std::endl;
        sendMAVLinkDoReposition(new_position.latitude, new_position.longitude, _system_state.altitude);
        return req->create_response()
            .append_header(restinio::http_field::content_type, "text/json; charset=utf-8")
            .set_body("{ \"status\": \"ok\" }")
            .done();
    });

Create and send a Mavlink message to send commands like a reposition to the vehicle. Add this to the private section.

void sendMAVLinkDoReposition(double latitude, double longitude, double altitude) {

    auto message = _message_set.create("COMMAND_INT").set({
        {"target_system", 1},
        {"target_component", 1},
        {"command", _message_set.e("MAV_CMD_DO_REPOSITION")},
        {"param1", 0},
        {"param2", 1}, // enforce mode change
        {"param3", 0},
        {"param4", 0},
        {"x", latitude * 1e7},
        {"y", longitude * 1e7},
        {"z", altitude},
        {"frame", _message_set.e("MAV_FRAME_GLOBAL_RELATIVE_ALT")},
        {"current", 0},
        {"autocontinue", 0}
    });
    auto exp = _connection->expect("COMMAND_ACK");
    _connection->send(message);
    _connection->receive(exp, 1000);
}

Add this to run() in the public section to start the server.

struct my_server_traits : public restinio::default_single_thread_traits_t {
    using request_handler_t = restinio::router::express_router_t<>;
};

std::cout << "Starting server on port 8080" << std::endl;
restinio::run(
    restinio::on_this_thread<my_server_traits>()
        .port(8080)
        .address("0.0.0.0")
        .request_handler(this->createRouter())
);

index.html

Create this file in services/web-navigation/website. It contains the scripts for the UI. The Interface can be designed with html and will be accessible in the local updater.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WEB Navigation example</title>

<script lang="javascript">

// add javascript code here

</script>

<!-- add html layout here --> 

A javascript function using the API is used to get the telemetry data and display it on the web interface.

function init() {
    setInterval(function() {
        const statusInfo = document.getElementById("status-info");

        fetch("api/telemetry").then(function(response) {
            return response.json();
        }).then(function(json) {
            statusInfo.innerHTML = `
             <table>
                <tr>
                    <th>Latitude</th>
                    <td>${json.latitude} deg</td>
                </tr>
                <tr>
                    <th>Longitude</th>
                    <td>${json.longitude} deg </td>
                </tr>
                <tr>
                    <th>Altitude</th>
                    <td>${json.altitude} m</td>
                </tr>
            </table>
            `
        }).catch(function(error) {
            statusInfo.innerHTML = "Error: " + error;
        });

    }, 1000);
}

window.onload = init;

A second javascript function which uses the Reposition command written in the API is used to command the change in position.

function goDirection(direction) {
    fetch("api/commands/reposition",
        {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: direction
        }
    ).then(function(response) {
        return response.json();
    }).then(function(json) {
        console.log(json);
    }).catch(function(error) {
        console.log(error);
    });
}

To create the page and call the reposition function html is used.

<style>
    body {
        font-family: Arial, Helvetica, sans-serif;

    }
</style>
</head>
<body>
    <h1>
        Tutorial app example
    </h1>
    <div id="status-info">
        Loading...
    </div>
    <hr />
    <button onclick="goDirection('north')">Go north (1m)</button>
    <button onclick="goDirection('east')">Go east (1m)</button>
    <button onclick="goDirection('south')">Go south (1m)</button>
    <button onclick="goDirection('west')">Go west (1m)</button>
</body>
</html>

After installing the App on a Skynode, open 10.41.1.1 and click "Show installed apps" to show all apps installed on the Skynode and click on the "Tutorial Web Navigation" Link to open the web interface.

CMakeList.txt

The CMakeList file contains the information on how to compile.

cmake_minimum_required(VERSION 3.22)
project(web-navigation)

set(CMAKE_CXX_STANDARD 17)

find_package(unofficial-http-parser REQUIRED)
find_package(fmt REQUIRED)
find_package(restinio CONFIG REQUIRED)
if (restinio_FOUND)
    message(STATUS "Found restinio: ${restinio_VERSION}")
endif ()

add_executable(web-navigation src/main.cpp)
target_include_directories(web-navigation PRIVATE ${CMAKE_SOURCE_DIR}/libmav/include)
target_link_libraries(web-navigation PRIVATE restinio::restinio)
target_link_libraries(web-navigation PRIVATE fmt::fmt)
target_link_libraries(web-navigation PRIVATE unofficial::http_parser::http_parser)

file(GLOB MAVLINK_XML ${CMAKE_CURRENT_SOURCE_DIR}/mavlink/message_definitions/v1.0/*.xml)
file(COPY ${MAVLINK_XML} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/mavlink)

Dockerfile

Add a file named "Dockerfile" to services/web-navigation.Describes how to actually build and run the app. Any docker command can be used in here. Apps shall inherit from the auterion/app-base image. The Dockerfile gets discovered in the build process by the tool looking at the locations indicated in the auterion-app.yml file.

This app will inherit from version 2 of the App Base.

FROM auterion/app-base:v2

This will install restinio. To learn more about restinio, and how to use it, go to the RESTinio Documentation.

ARG RESTINIO_VERSION=0.6.18


RUN apt update && \
    apt install -y \
    libasio-dev \
    libfmt-dev && \
    apt clean && \
    rm -rf /var/lib/apt/lists/*

# Install restinio
RUN curl -L https://github.com/Stiffstream/restinio/releases/download/v.${RESTINIO_VERSION}/restinio-${RESTINIO_VERSION}-full.tar.bz2 -o restinio.tar.bz2 && \
    tar xf restinio.tar.bz2 && \
    cd restinio-${RESTINIO_VERSION}/dev && \
    mkdir build && \
    cd build && \
    cmake -DCMAKE_BUILD_TYPE=Release -DRESTINIO_TEST=no -DRESTINIO_SAMPLE=no -DRESTINIO_INSTALL_SAMPLES=no -DRESTINIO_BENCH=no  .. && \
    make -j8 install && \
    cd ../../.. && \
    rm -rf restinio.zip restinio-${RESTINIO_VERSION}

This will copy the code to the specified folder, build it and then run the app.

COPY . /app

WORKDIR /app

RUN cmake . && make -j8

CMD mkdir -p /data/webroot && cp  website/index.html /data/webroot/ && ./web-navigation

Installation on Skynode

Discover Skynode using Auterion CLI

To install on a Skynode the device must be selected in the Auterion CLI. First discover the devices connected. When no device is selected and the Skynode is connected with USB it will be selected by default so this step can be skipped.

auterion-cli device discover

To select a device the serial number is needed. The "*" in the first column shows if the device is already selected and the serial number is in the second column.

selected       serial  version    addresses
----------  ---------  ---------  -------------
*           009128332  v2.15.0    {'10.41.1.1'}

Use the serial number to select the device.

auterion-cli device select <device serial number>

If the selection was successful this is the shown output.

$ auterion-cli device select 009128332
Selected device with ID 009128332 on address 10.41.1.1

Build and Install app on Skynode using Auterion CLI

First the App needs to be built. Execute this command in the folder the App is in.

auterion-cli app build

The App base version specified in the auterion-app.yml needs to be installed on the device first. The App can be installed either over the local updater on 10.41.1.1 or by using this command.

auterion-cli app install build/com.auterion.tutorial-web-navigation.auterionos

Get status and logs from app running on Skynode using Auterion CLI

Auterion CLI can also be used to get the log output from the app.

auterion-cli app logs -f <APP NAME>

To build an app for Virtual Skynode, you must also provide the --simulation flag to the build command. Refer to the page for more context.

Application Development
custom UI of the Tutorial App
Apps installed on a Skynode