Skip to content

7.2 Hello World with protobuf

In the last section you learned how to send strings to an eCAL Topic. Using strings is great for simple data that has a textual representation. Quite often however your data will be more complex, so you need some kind of protocol that defines how your data is structured.

Of course, you can define your own protocol and pass the raw memory to eCAL (you would use the raw eCAL::CPublisher() to do that). Our recommended way however is to use Google protobuf, because:

  • It solves the problem of how to serialize and de-serialize data for you
  • You get downward compatibility out of the box (if you follow the guidelines)
  • It is maintained by Google and the API is stable
  • The eCAL Monitor can display a nice reflection view of the data

7.2.1 Protobuf sender

Let’s implement a small application, that lets the user input his name and send a message to an eCAL topic. As the sender and receiver need the same .proto files, we place them in a separate directory next to the source directories for the sender and the receiver:

  • Directory
    • Directoryproto_messages
      • hello_world.proto
    • Directoryprotobuf_snd/
    • Directoryprotobuf_rec/

Let’s start with the proto_messages/hello_world.proto file!

hello_world.proto
1
syntax = "proto3";
2
3
package proto_messages;
4
5
message HelloWorld
6
{
7
string name = 1;
8
uint32 id = 2;
9
string msg = 3;
10
}

Now start implementing the actual sender application. Just as in the last section create the CMakeLists.txt and main.cpp in the protobuf_snd directory and paste the following content:

  • CMakeLists.txt
    1
    cmake_minimum_required(VERSION 3.0)
    2
    set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
    3
    4
    project(protobuf_snd)
    5
    6
    set(CMAKE_CXX_STANDARD 14)
    7
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    8
    9
    find_package(eCAL REQUIRED)
    10
    find_package(Protobuf REQUIRED)
    11
    12
    set(source_files
    13
    main.cpp
    14
    )
    15
    16
    set(protobuf_files
    17
    ${CMAKE_CURRENT_SOURCE_DIR}/../proto_messages/hello_world.proto
    18
    )
    19
    20
    add_executable(${PROJECT_NAME} ${source_files})
    21
    22
    PROTOBUF_TARGET_CPP(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/../proto_messages/ ${protobuf_files})
    23
    24
    target_link_libraries(${PROJECT_NAME}
    25
    eCAL::core
    26
    protobuf::libprotobuf
    27
    )
  • main.cpp
    1
    #include <ecal/ecal.h>
    2
    #include <ecal/msg/protobuf/publisher.h>
    3
    4
    #include <iostream>
    5
    #include <thread>
    6
    7
    #include "hello_world.pb.h"
    8
    9
    int main(int argc, char** argv)
    10
    {
    11
    // Initialize eCAL and create a protobuf publisher
    12
    eCAL::Initialize(argc, argv, "Hello World Protobuf Publisher");
    13
    eCAL::protobuf::CPublisher<proto_messages::HelloWorld> publisher("hello_world_protobuf");
    14
    15
    // Ask the user to input his name
    16
    std::cout << "Please enter your name: ";
    17
    std::string name;
    18
    std::getline(std::cin, name);
    19
    20
    unsigned int id = 0;
    21
    22
    // Infinite loop (using eCAL::Ok() will enable us to gracefully shutdown the
    23
    // Process from another application)
    24
    while (eCAL::Ok())
    25
    {
    26
    // Let the user input a message
    27
    std::cout << "Type the message you want to send: ";
    28
    std::string message;
    29
    std::getline(std::cin, message);
    30
    31
    // Create a protobuf message object
    32
    proto_messages::HelloWorld hello_world_message;
    33
    hello_world_message.set_name(name);
    34
    hello_world_message.set_msg (message);
    35
    hello_world_message.set_id (id++);
    36
    37
    // Send the message
    38
    publisher.Send(hello_world_message);
    39
    std::cout << "Sent message!" << std::endl << std::endl;
    40
    }
    41
    42
    // finalize eCAL API
    43
    eCAL::Finalize();
    44
    }

Again, you can already watch the sender doing its work by inspecting the topic in the eCAL Monitor! (Compile the application just as in the last section)

Hello World Protobuf sender and eCAL Monitor

7.2.2 Protobuf receiver

  • CMakeLists.txt
    1
    cmake_minimum_required(VERSION 3.0)
    2
    set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
    3
    4
    project(protobuf_rec)
    5
    6
    set(CMAKE_CXX_STANDARD 14)
    7
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    8
    9
    find_package(eCAL REQUIRED)
    10
    find_package(Protobuf REQUIRED)
    11
    12
    set(source_files
    13
    main.cpp
    14
    )
    15
    16
    set(protobuf_files
    17
    ${CMAKE_CURRENT_SOURCE_DIR}/../proto_messages/hello_world.proto
    18
    )
    19
    20
    add_executable(${PROJECT_NAME} ${source_files})
    21
    22
    PROTOBUF_TARGET_CPP(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/../proto_messages/ ${protobuf_files})
    23
    24
    target_link_libraries(${PROJECT_NAME}
    25
    eCAL::core
    26
    protobuf::libprotobuf
    27
    )
  • main.cpp
    1
    #include <ecal/ecal.h>
    2
    #include <ecal/msg/protobuf/subscriber.h>
    3
    4
    #include <iostream>
    5
    #include <thread>
    6
    7
    #include "hello_world.pb.h"
    8
    9
    void HelloWorldCallback(const proto_messages::HelloWorld& hello_world_msg)
    10
    {
    11
    std::cout << hello_world_msg.name() << " sent a message with ID "
    12
    << hello_world_msg.id() << ":" << std::endl
    13
    << hello_world_msg.msg() << std::endl << std::endl;
    14
    }
    15
    16
    int main(int argc, char** argv)
    17
    {
    18
    // Initialize eCAL and create a protobuf subscriber
    19
    eCAL::Initialize(argc, argv, "Hello World Protobuf Subscriber");
    20
    eCAL::protobuf::CSubscriber<proto_messages::HelloWorld> subscriber("hello_world_protobuf");
    21
    22
    // Set the Callback
    23
    subscriber.AddReceiveCallback(std::bind(&HelloWorldCallback, std::placeholders::_2));
    24
    25
    // Just don't exit
    26
    while (eCAL::Ok())
    27
    {
    28
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    29
    }
    30
    31
    // finalize eCAL API
    32
    eCAL::Finalize();
    33
    }

Now compile and start both the sender and the receiver application and send some messages!

Hello World Protobuf sender and receiver

Congratulations, you have completed the Getting Started chapter! Now go ahead and use eCAL in your real-world scenario.

If you experience issues, you can create a GitHub issue, to get help.

7.2.3 Files