Skip to main content

C++

Connect directly to Foxglove or play back local data recorded with the C++ SDK.

Install the SDK

The C++ SDK is a wrapper around a C library. To build it, you will need to link that library and compile the SDK source as part of your build process. The SDK assumes C++17 or newer.

Download the library, source, and header files for your platform from the SDK release assets.

If you're using CMake, you can use the following as a starting point. For more detail, see the quickstart example.

cmake_minimum_required(VERSION 3.20)

# TODO: replace "my_program" throughout with the name of your project
project(my_program LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)

# Fetch Foxglove SDK
include(FetchContent)
FetchContent_Declare(
foxglove
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
# TODO: Copy the URL and SHA for the appropriate .zip file from here:
# https://github.com/foxglove/foxglove-sdk/releases?q=sdk%2F&expanded=true
URL <download URL from the GitHub release>
URL_HASH SHA256=<sha from the GitHub release>
)
FetchContent_MakeAvailable(foxglove)

# Assuming the project consists of a single source file, main.cpp
add_executable(my_program main.cpp)

# Add include directory for Foxglove SDK
target_include_directories(my_program PRIVATE ${foxglove_SOURCE_DIR}/include)
target_include_directories(my_program PRIVATE ${foxglove_SOURCE_DIR}/include/foxglove)

# Find all Foxglove SDK source files
file(GLOB FOXGLOVE_SOURCES CONFIGURE_DEPENDS
"${foxglove_SOURCE_DIR}/src/*.cpp"
"${foxglove_SOURCE_DIR}/src/server/*.cpp"
)

# Add Foxglove SDK source files
target_sources(my_program PRIVATE ${FOXGLOVE_SOURCES})

# Link against libfoxglove.a
target_link_libraries(my_program PRIVATE ${foxglove_SOURCE_DIR}/lib/libfoxglove.a)

Live data

Log messages from C++

#include <foxglove/foxglove.hpp>
#include <foxglove/server.hpp>

#include <chrono>
#include <csignal>
#include <iostream>
#include <thread>

using namespace std::chrono_literals;

int main(int argc, const char *argv[]) {
foxglove::WebSocketServerOptions options;
auto serverResult = foxglove::WebSocketServer::create(std::move(options));
if (!serverResult.has_value()) {
std::cerr << foxglove::strerror(serverResult.error()) << '\n';
return 1;
}

auto server = std::move(serverResult.value());
auto channel = foxglove::RawChannel::create("/hello", "json").value();
auto start = std::chrono::steady_clock::now();

// Log until interrupted
static std::function<void()> sigint_handler;
std::atomic_bool done = false;
sigint_handler = [&] { done = true; };
std::signal(SIGINT, [](int) {
if (sigint_handler) {
sigint_handler();
}
});

while (!done) {
auto dur = std::chrono::steady_clock::now() - start;
float elapsed_seconds = std::chrono::duration<float>(dur).count();
std::string msg = "{\"elapsed\": " + std::to_string(elapsed_seconds) + "}";
channel.log(reinterpret_cast<const std::byte *>(msg.data()), msg.size());

std::this_thread::sleep_for(33ms);
}

return 0;
}

Run the example

If you're using something like the CMake configuration above, you can create a build directory and run the following.

cd build
cmake ..
cmake --build .
./my_program

Connect

In Foxglove, select "Open connection" from the dashboard or left-hand menu.

Select open connection

Select "Foxglove WebSocket" in the "Open a new connection" dialog, then click "Open" to accept the default connection string:

Foxglove WebSocket dialog

Local data

Recording data to a file

The SDK can also log data to disk. Let's augment the example above to also produce an MCAP file which can later be opened in Foxglove:

#include <foxglove/foxglove.hpp>
#include <foxglove/mcap.hpp>
#include <foxglove/server.hpp>

#include <chrono>
#include <csignal>
#include <iostream>
#include <thread>

using namespace std::chrono_literals;

int main(int argc, const char *argv[]) {
foxglove::WebSocketServerOptions options;
auto serverResult = foxglove::WebSocketServer::create(std::move(options));
if (!serverResult.has_value()) {
std::cerr << foxglove::strerror(serverResult.error()) << '\n';
return 1;
}

auto server = std::move(serverResult.value());
auto channel = foxglove::RawChannel::create("/hello", "json").value();
auto start = std::chrono::steady_clock::now();

foxglove::McapWriterOptions mcap_options;
mcap_options.path = "example.mcap";
auto writerResult = foxglove::McapWriter::create(mcap_options);
if (!writerResult.has_value()) {
std::cerr << foxglove::strerror(writerResult.error()) << '\n';
return 1;
}
// Keep a reference to the writer. It will be closed when the writer is
// destroyed, or we could call `.close()` to close it manually.
auto writer = std::move(writerResult.value());

// Log until interrupted
static std::function<void()> sigint_handler;
std::atomic_bool done = false;
sigint_handler = [&] { done = true; };
std::signal(SIGINT, [](int) {
if (sigint_handler) {
sigint_handler();
}
});

while (!done) {
auto dur = std::chrono::steady_clock::now() - start;
float elapsed_seconds = std::chrono::duration<float>(dur).count();
std::string msg = "{\"elapsed\": " + std::to_string(elapsed_seconds) + "}";
channel.log(reinterpret_cast<const std::byte *>(msg.data()), msg.size());

std::this_thread::sleep_for(33ms);
}

return 0;
}

Viewing data from a file

Open your recording(s) directly from your computer by:

  • Dragging and dropping them into Foxglove
  • Using Cmd/Ctrl + o
  • Clicking Open local file(s) in the app

Local file dialog

note

When opening multiple files, Foxglove will display the data as a single merged timeline. The files must be of the same format.

Explore your data

Your data is now available for exploring in Foxglove. Add some panels to begin visualizing what your robot is seeing and producing. Not sure where to start? Try adding a Raw Messages panel, Plot panel, or 3D panel.