Part 1 (Publishers)

This tutorial will walk you through the creation of a basic pipeline, including the ability to serialize data, log it, and view it in the C++ visualizer.

First, we’ll make a few assumptions:

  • Ark is installed in ${APP_ROOT}/ark
  • You have successfully built Ark (and all required dependencies are installed)

Creating Your First Stage

The first thing we’ll build is a simple stage that emits a message out at a fixed interface. This will demonstrate compiling a stage and the creation of both publishers and periodic timers.

First, let’s make a directory for your example and stages:

cd ${APP_ROOT}/ark
mkdir -p tutorial/first_stage
cd tutorial/first_stage

Next, let’s create the stage itself. We’ll be using C++, so the first thing to do is to define the header file. Place this in ${APP_ROOT}/tutorial/first_stage/first_stage.hh:

#pragma once

#include "ark/pipeline/stage.hh"

#include <string>

class FirstStage : public ark::pipeline::Stage
{
public:
    /// Constructor -- this initializes the parent class (Stage)
    /// with a name. Names must be unique.
    FirstStage() : ark::pipeline::Stage("FirstStage")
    {
    }

    /// This is invoked when the system starts up, and gives us a chance
    /// to register callbacks.
    void initialize(ark::pipeline::StageInterface &interface) override;
};

Make sure to see the comments above for rationale as to why that code exists. The key point is that we have an initialize method that will be invoked by Ark to give you a chance to register a timer.

Next up, let’s implement the class. Place this in ${APP_ROOT}/tutorial/first_stage/first_stage.cc:

#include "tutorial/first_stage/first_stage.hh"

#include "ark/pipeline/publisher.hh"
#include "ark/pipeline/periodic_timer_config.hh"
#include "ark/pipeline/stage_interface.hh"

#include "fmt/format.h"

void FirstStage::initialize(ark::pipeline::StageInterface &interface)
{
    // First, create your publisher. This is the 'channel' that you will
    // emit strings on. Other stages will be able to receive these strings.
    auto publisher = interface.add_publisher<std::string>("/my_strings");

    // Next, we'll register a timer. This timer will run at 1Hz and emit
    // a string execution.
    {
        ark::pipeline::PeriodicTimerConfiguration config;

        config.name = "emit_string";
        config.rate = std::chrono::seconds{1};
        config.callback = [publisher](const auto &now) {
            // 'now' contains the current "pipeline time". Convert it into
            // a double for easier printing.
            auto time_s = std::chrono::duration<double>(now.time_since_epoch());

            publisher->push(fmt::format("Hello world, it's now {}.", time_s.count()));
        };

        interface.add_timer(config);
    }
}

This populates the initialize method with two things: a publisher, which writes messages over the /my_strings channel, and a periodic timer, which runs every second, and pushes a string with the current time onto the publisher.

Compiling

To build this stage, we’ll need a cmake file. Place this in ${APP_ROOT}/tutorial/first_stage/CMakeLists.txt:

add_library(first_stage first_stage.cc)

target_link_libraries(first_stage
    PUBLIC ark::pipeline
    PRIVATE fmt::fmt)

Then add this line at the bottom of ${APP_ROOT}/CMakeLists.txt:

add_subdirectory(tutorial/first_stage)

Now, you should be able to build your stage! Execute:

cd ${APP_ROOT}
./make.sh

You should compile without any errors. However, you don’t have a pipeline yet, so you can’t actually run anything.

Move on to Step 2.