### Python SDK Quickstart Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk/python/docs/examples.rst A basic example to get started with the Foxglove SDK. ```python import asyncio from foxglove_sdk import Client, Message, Pose, SceneUpdate, Color, Text, LinePrimitive async def main(): # Connect to Foxglove Studio async with Client("ws://localhost:8080") as client: # Send a scene update with a pose and a text message await client.send_message( "foxglove.SceneUpdate", SceneUpdate( objects=[ Pose( frame_id="map", position={"x": 1.0, "y": 2.0, "z": 3.0}, orientation={"x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0}, ) ], texts=[ Text( id="my-text", text="Hello, Foxglove!", position={"x": 0.0, "y": 0.0, "z": 0.0}, color=Color(r=1.0, g=1.0, b=1.0, a=1.0), ) ], lines=[ LinePrimitive( id="my-line", points=[ {"x": 0.0, "y": 0.0, "z": 0.0}, {"x": 1.0, "y": 1.0, "z": 1.0}, ], color=Color(r=1.0, g=0.0, b=0.0, a=1.0), thickness=0.01, ) ], ), ) # Send a custom message await client.send_message( "my_custom_topic", Message( timestamp=client.get_time(), data={"message": "This is a custom message!"}, ), ) # Keep the connection open for a bit await asyncio.sleep(5) if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Run Example WebSocket Server Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/foxglove/CONTRIBUTING.md Execute this command to start the example WebSocket server. Follow the subsequent steps to connect using the Foxglove desktop application. ```bash cargo run -p example_ws_server ``` -------------------------------- ### C++ Quickstart: Record and Visualize Data Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/foxglove/docs/examples.md This example demonstrates how to set up a Foxglove WebSocket server, record data to an MCAP file, and send messages for visualization in Foxglove Studio. It logs JSON data for a 'size' channel and 3D scene updates. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; int main() { foxglove::setLogLevel(foxglove::LogLevel::Debug); static std::function sigint_handler; std::signal(SIGINT, [](int) { if (sigint_handler) { sigint_handler(); } }); foxglove::McapWriterOptions mcap_options = {}; mcap_options.path = "quickstart-cpp.mcap"; auto writer_result = foxglove::McapWriter::create(mcap_options); if (!writer_result.has_value()) { std::cerr << "Failed to create writer: " << foxglove::strerror(writer_result.error()) << '\n'; return 1; } auto writer = std::move(writer_result.value()); // Start a server to communicate with the Foxglove app. foxglove::WebSocketServerOptions ws_options; ws_options.host = "127.0.0.1"; ws_options.port = 8765; auto server_result = foxglove::WebSocketServer::create(std::move(ws_options)); if (!server_result.has_value()) { std::cerr << "Failed to create server: " << foxglove::strerror(server_result.error()) << '\n'; return 1; } auto server = std::move(server_result.value()); std::cerr << "Server listening on port " << server.port() << '\n'; // Create a schema for a JSON channel for logging {size: number} foxglove::Schema schema; schema.encoding = "jsonschema"; std::string schema_data = R"({ "type": "object", "properties": { "size": { "type": "number" } } })"; schema.data = reinterpret_cast(schema_data.data()); schema.data_len = schema_data.size(); auto channel_result = foxglove::RawChannel::create("/size", "json", std::move(schema)); if (!channel_result.has_value()) { std::cerr << "Failed to create channel: " << foxglove::strerror(channel_result.error()) << '\n'; return 1; } auto size_channel = std::move(channel_result.value()); // Create a SceneUpdateChannel for logging changes to a 3d scene auto scene_channel_result = foxglove::messages::SceneUpdateChannel::create("/scene"); if (!scene_channel_result.has_value()) { std::cerr << "Failed to create scene channel: " << foxglove::strerror(scene_channel_result.error()) << '\n'; return 1; } auto scene_channel = std::move(scene_channel_result.value()); std::atomic_bool done = false; sigint_handler = [&] { done = true; }; while (!done) { auto now = std::chrono::duration_cast>( std::chrono::system_clock::now().time_since_epoch() ) .count(); double size = std::abs(std::sin(now)) + 1.0; std::string msg = "{\"size\": " + std::to_string(size) + "}"; size_channel.log(reinterpret_cast(msg.data()), msg.size()); foxglove::messages::CubePrimitive cube; cube.size = foxglove::messages::Vector3{size, size, size}; cube.color = foxglove::messages::Color{1, 0, 0, 1}; foxglove::messages::SceneEntity entity; entity.id = "box"; entity.cubes.push_back(cube); foxglove::messages::SceneUpdate scene_update; scene_update.entities.push_back(entity); scene_channel.log(scene_update); std::this_thread::sleep_for(33ms); } return 0; } ``` -------------------------------- ### Install Example Dependencies Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk-examples/so101-visualization/README.md Installs additional Python dependencies required for this specific visualization example. Make sure the 'lerobot' conda environment is activated before running. ```bash # Make sure you're in the lerobot conda environment conda activate lerobot # Install additional dependencies for this example pip install -r requirements.txt ``` -------------------------------- ### Setup for Jupyter Integration Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk/CONTRIBUTING.md Installs the SDK with the notebook extra, JupyterLab, and launches JupyterLab for testing integration. Ensure your virtual environment is set up. ```sh # Install the SDK with the notebook extra. uv pip install --editable '.[notebook]' # Install Jupyter lab. uv pip install jupyterlab # Launch Jupyter lab. uv run jupyter lab ``` -------------------------------- ### Run Example (Default Camera) Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/examples/rgb-camera-visualization/README.md Execute the RGB camera visualization example using the default camera. ```bash ./example_rgb_camera_visualization ``` -------------------------------- ### Run Specific Example with Local Changes Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk/README.md Navigate to an example directory and use uv to run the example with local changes to the foxglove-sdk. Remember to clean the uv cache if changes are not reflected. ```bash cd python/foxglove-sdk-examples/write-mcap-file uv run --with ../../foxglove-sdk main.py [args] ``` -------------------------------- ### Run Example (Specify Camera ID) Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/examples/rgb-camera-visualization/README.md Execute the RGB camera visualization example and specify a particular camera ID to use. ```bash ./example_rgb_camera_visualization --camera-id 4 ``` -------------------------------- ### Parameter Server for Runtime Parameter Get/Set/Subscribe (Python) Source: https://context7.com/foxglove/foxglove-sdk/llms.txt Implement `foxglove.websocket.ServerListener` and start the server with `Capability.Parameters` to allow the Foxglove Parameters panel to read and write your application's runtime values. This example demonstrates a simple parameter store with get and set functionality. ```python import time import foxglove from foxglove.websocket import Capability, Client, Parameter, ServerListener from typing import List, Optional class ParamStore(ServerListener): def __init__(self): self.params = { "max_speed": Parameter("max_speed", value=2.0), "enabled": Parameter("enabled", value=True), "label": Parameter("label", value="robot-1"), } def on_get_parameters(self, client: Client, names: List[str], request_id: Optional[str] = None) -> List[Parameter]: return list(self.params.values()) if not names else [self.params[n] for n in names if n in self.params] def on_set_parameters(self, client: Client, parameters: List[Parameter], request_id: Optional[str] = None) -> List[Parameter]: for p in parameters: if p.value is None: self.params.pop(p.name, None) else: self.params[p.name] = p return parameters store = ParamStore() server = foxglove.start_server( server_listener=store, capabilities=[Capability.Parameters], ) try: while True: server.publish_parameter_values(list(store.params.values())) time.sleep(5) except KeyboardInterrupt: server.stop() ``` -------------------------------- ### Install @foxglove/schemas Source: https://github.com/foxglove/foxglove-sdk/blob/main/typescript/schemas/README.md Install the package using npm. ```bash npm install @foxglove/schemas ``` -------------------------------- ### Build Docker Image for Protobuf Example Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/examples/custom-protobuf/README.md Build the Docker image for the custom protobuf example. This command runs CMake to build the example within the image. ```sh docker build --platform linux/amd64 -t foxglove-protobuf . ``` -------------------------------- ### Build RGB Camera Example Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/examples/rgb-camera-visualization/README.md Build all C++ examples, including the RGB camera visualization, by enabling the BUILD_OPENCV_EXAMPLE flag. ```bash make BUILD_OPENCV_EXAMPLE=ON build ``` -------------------------------- ### Start Playground Development Server Source: https://github.com/foxglove/foxglove-sdk/blob/main/playground/README.md Navigate to the playground directory and start the development server using yarn. ```sh cd ../../playground yarn start ``` -------------------------------- ### Run RGB Camera Example (Default Camera) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/examples/rgb_camera_visualization/README.md Runs the RGB camera visualization example using the default camera. Connect to ws://localhost:8765 in Foxglove to view the feed. ```bash cargo run --manifest-path rust/examples/rgb_camera_visualization/Cargo.toml ``` -------------------------------- ### Build RGB Camera Example Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/examples/rgb_camera_visualization/README.md Builds the RGB camera visualization example using Cargo. This command must be executed from the root of the repository. ```bash cargo build --manifest-path rust/examples/rgb_camera_visualization/Cargo.toml ``` -------------------------------- ### Run Example Program Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/README.md Executes a compiled example program. The build directory may vary based on build settings like sanitizers. ```bash ./build/example_server ``` -------------------------------- ### Install OpenCV Dependencies (Ubuntu/Debian) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/examples/rgb_camera_visualization/README.md Installs OpenCV development libraries and clang on Ubuntu/Debian systems. These are required for the RGB camera visualization example. ```bash sudo apt update sudo apt install libopencv-dev clang libclang-dev ``` -------------------------------- ### Start Web Frontend (Flat Mode) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/remote_access_tests/NETEM.md Run this command in the third terminal to start the web frontend for the Foxglove app. ```sh (cd ../app && yarn web serve:local) ``` -------------------------------- ### Install LeRobot Dependencies Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk-examples/so101-visualization/README.md Installs necessary system packages, clones the LeRobot repository, creates a conda environment, and installs LeRobot with its dependencies. Ensure you are in the correct directory after cloning. ```bash sudo apt-get install cmake build-essential python-dev pkg-config libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libswresample-dev libavfilter-dev pkg-config git clone https://github.com/huggingface/lerobot.git cd lerobot conda create -y -n lerobot python=3.10 conda activate lerobot conda install ffmpeg -c conda-forge pip install -e . pip install -e ".[feetech]" ``` -------------------------------- ### Run RGB Camera Example (Specify Camera ID) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/examples/rgb_camera_visualization/README.md Runs the RGB camera visualization example, specifying a particular camera ID. This allows selection of non-default cameras. ```bash cargo run --manifest-path rust/examples/rgb_camera_visualization/Cargo.toml -- --camera-id 2 ``` -------------------------------- ### Start LiveKit + NETEM (Per-Link Mode) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/remote_access_tests/NETEM.md Run this command in the first terminal to start LiveKit and NETEM with per-link sidecars enabled for independent impairment. ```sh yarn start-netem --perlink ``` -------------------------------- ### Run MCAP Playback Control Example Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk-examples/ws-playback-control-mcap/README.md Execute the example using uv to manage dependencies. Specify the path to your MCAP file using the --file argument. ```bash uv run python main.py --file /path/to/file.mcap ``` -------------------------------- ### Start NETEM and LiveKit (Flat Mode) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/remote_access_tests/NETEM.md Run this command in the first terminal to start LiveKit and NETEM for uniform impairment across all traffic. ```sh yarn start-netem ``` -------------------------------- ### Install Emscripten Toolchain Source: https://github.com/foxglove/foxglove-sdk/blob/main/playground/README.md Clone the emsdk repository, install a specific version, activate it, and source the environment variables. ```sh git clone https://github.com/emscripten-core/emsdk.git emsdk/emsdk install 3.1.58 emsdk/emsdk activate 3.1.58 source emsdk/emsdk_env.sh ``` -------------------------------- ### Source ROS setup and launch foxglove_bridge Source: https://github.com/foxglove/foxglove-sdk/blob/main/ros/src/foxglove_bridge/README.md Sources the local ROS setup file to make the package discoverable, then launches the foxglove_bridge node on a specified port. ```bash source install/local_setup.bash ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765 ``` -------------------------------- ### Install OpenCV Dependencies (Ubuntu/Debian) Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/examples/rgb-camera-visualization/README.md Install the OpenCV development libraries on Ubuntu or Debian systems using apt. ```bash sudo apt update sudo apt install libopencv-dev ``` -------------------------------- ### Install Foxglove C Headers Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/CMakeLists.txt Installs the C header files for the Foxglove SDK into the system's include directory. ```cmake install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../c/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" ) ``` -------------------------------- ### C++ Connection Graph Example Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/foxglove/docs/examples.md Constructs a connection graph that can be viewed as a Topic Graph in Foxglove. This example sets up a WebSocket server and publishes connection graph updates. ```cpp #include #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; /** * This example constructs a connection graph which can be viewed as a Topic Graph in Foxglove: * https://docs.foxglove.dev/docs/visualization/panels/topic-graph */ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static std::function sigint_handler; // NOLINTNEXTLINE(bugprone-exception-escape) int main() { std::signal(SIGINT, [](int) { if (sigint_handler) { sigint_handler(); } }); foxglove::setLogLevel(foxglove::LogLevel::Debug); foxglove::WebSocketServerOptions options = {}; options.name = "ws-demo-cpp"; options.host = "127.0.0.1"; options.port = 8765; options.capabilities = foxglove::WebSocketServerCapabilities::ConnectionGraph; options.callbacks.onConnectionGraphSubscribe = []() { std::cerr << "Connection graph subscribed\n"; }; options.callbacks.onConnectionGraphUnsubscribe = []() { std::cerr << "Connection graph unsubscribed\n"; }; auto graph = foxglove::ConnectionGraph(); auto err = graph.setPublishedTopic("/example-topic", {"1", "2"}); if (err != foxglove::FoxgloveError::Ok) { std::cerr << "Failed to set published topic: " << foxglove::strerror(err) << '\n'; } graph.setSubscribedTopic("/subscribed-topic", {"3", "4"}); graph.setAdvertisedService("example-service", {"5", "6"}); auto server_result = foxglove::WebSocketServer::create(std::move(options)); if (!server_result.has_value()) { std::cerr << "Failed to create server: " << foxglove::strerror(server_result.error()) << '\n'; return 1; } auto server = std::move(server_result.value()); std::atomic_bool done = false; sigint_handler = [&] { std::cerr << "Shutting down...\n"; server.stop(); done = true; }; while (!done) { server.publishConnectionGraph(graph); std::this_thread::sleep_for(1s); } std::cerr << "Done\n"; return 0; } ``` -------------------------------- ### Run Custom Protobuf Example Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk-examples/custom-protobuf/README.md Execute the Python script using uv to log custom protobuf messages. ```bash uv run python main.py ``` -------------------------------- ### Install Development Dependencies Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk/CONTRIBUTING.md Installs all development dependencies for the project, including optional extras. Ensure you have a local virtual environment managed by uv. ```sh uv sync --all-extras ``` -------------------------------- ### Install foxglove-schemas-protobuf with uv Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-schemas-protobuf/README.md Use this command to add the package to your project if you are using uv for dependency management. ```sh uv add foxglove-schemas-protobuf ``` -------------------------------- ### Build Foxglove C++ SDK Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/README.md Standard command to build the Foxglove C++ library and its examples. ```bash make build ``` -------------------------------- ### Install Foxglove C++ Headers Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/CMakeLists.txt Installs the C++ header files for the Foxglove SDK into the system's include directory. ```cmake install(DIRECTORY foxglove/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp" ) ``` -------------------------------- ### Run Example with Specific Camera ID Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk-examples/rgb-camera-visualization/README.md Execute the Python script, specifying a particular camera ID to stream its feed. Use this when multiple cameras are available. ```bash uv run python main.py --camera-id 4 ``` -------------------------------- ### Install foxglove_bridge using apt Source: https://github.com/foxglove/foxglove-sdk/blob/main/ros/src/foxglove_bridge/README.md Installs the foxglove_bridge package using the ROS package manager. Ensure your ROS distribution is set correctly. ```bash sudo apt install ros-$ROS_DISTRO-foxglove-bridge ``` -------------------------------- ### Start Foxglove App (Flat Mode) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/remote_access_tests/NETEM.md Run this command in the second terminal to start the Foxglove application if it's not already running. ```sh (cd ../app && docker compose up -d && yarn start) ``` -------------------------------- ### Start Foxglove App with LiveKit URL Override (Per-Link Mode) Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/remote_access_tests/NETEM.md Start the Foxglove app in the second terminal, overriding the LiveKit host to use `host.docker.internal` for proper resolution from both the browser and Docker containers. ```sh (cd ../app && docker compose up -d && LIVEKIT_HOST=ws://host.docker.internal:7880 yarn start) ``` -------------------------------- ### Install foxglove-schemas-protobuf with Poetry Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-schemas-protobuf/README.md Use this command to add the package to your project if you are using Poetry for dependency management. ```sh poetry add foxglove-schemas-protobuf ``` -------------------------------- ### foxglove.start_server() Source: https://context7.com/foxglove/foxglove-sdk/llms.txt Starts a WebSocket server to stream live data to the Foxglove app. Returns a WebSocketServer handle that can be used to shut down the server. ```APIDOC ## `foxglove.start_server()` — stream live data to the Foxglove app (Python) Starts a WebSocket server. Returns a `WebSocketServer` handle; call `.stop()` to shut down. Accepts `capabilities`, `services`, `server_listener`, `asset_handler`, and `channel_filter` keyword arguments. ```python import math, time import foxglove from foxglove.channels import SceneUpdateChannel from foxglove.messages import Color, CubePrimitive, SceneEntity, SceneUpdate, Vector3 scene_chan = SceneUpdateChannel("/scene") size_chan = foxglove.Channel("/size", message_encoding="json") with foxglove.open_mcap("live.mcap"): server = foxglove.start_server(name="my-robot", host="127.0.0.1", port=8765) try: while True: size = abs(math.sin(time.time())) + 1.0 size_chan.log({"size": size}) # dict auto-serialized to JSON scene_chan.log(SceneUpdate( entities=[ SceneEntity( cubes=[ CubePrimitive( size=Vector3(x=size, y=size, z=size), color=Color(r=1.0, g=0.0, b=0.0, a=1.0), ) ], ) ], )) time.sleep(0.033) except KeyboardInterrupt: server.stop() ``` ``` -------------------------------- ### Install SDK in Editable Mode Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk/CONTRIBUTING.md Installs the SDK in editable mode into the local virtual environment. Changes to Python sources are reflected immediately. Rust source changes require reinstallation. ```sh uv pip install --editable . ``` -------------------------------- ### Run Unit Tests with Pytest Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk/CONTRIBUTING.md Installs the SDK with the notebook extra and runs unit tests using Pytest. This command is executed within the uv-managed virtual environment. ```sh uv pip install -e '.[notebook]' uv run pytest ``` -------------------------------- ### Run Benchmark Tests Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk/CONTRIBUTING.md Installs the SDK with the notebook extra and runs benchmark tests. Benchmarks are marked with `@pytest.mark.benchmark` and are not run by default. ```sh uv pip install -e '.[notebook]' # to run with benchmarks uv run pytest --with-benchmarks # to run only benchmarks uv run pytest -m benchmark ``` -------------------------------- ### Run Remote Access Example Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk-examples/remote-access/README.md Set the FOXGLOVE_DEVICE_TOKEN environment variable before running the main Python script. This token is obtained from the Foxglove platform. ```bash FOXGLOVE_DEVICE_TOKEN=your-token-here uv run main.py ``` -------------------------------- ### Start Foxglove Server for Live Data Streaming (Python) Source: https://context7.com/foxglove/foxglove-sdk/llms.txt Starts a WebSocket server to stream live data to the Foxglove application. Call `.stop()` on the returned handle to shut down the server. Accepts optional arguments for capabilities, services, listeners, asset handlers, and channel filters. ```python import math, time import foxglove from foxglove.channels import SceneUpdateChannel from foxglove.messages import Color, CubePrimitive, SceneEntity, SceneUpdate, Vector3 scene_chan = SceneUpdateChannel("/scene") size_chan = foxglove.Channel("/size", message_encoding="json") with foxglove.open_mcap("live.mcap"): server = foxglove.start_server(name="my-robot", host="127.0.0.1", port=8765) try: while True: size = abs(math.sin(time.time())) + 1.0 size_chan.log({"size": size}) # dict auto-serialized to JSON scene_chan.log(SceneUpdate( entities=[ SceneEntity( cubes=[ CubePrimitive( size=Vector3(x=size, y=size, z=size), color=Color(r=1.0, g=0.0, b=0.0, a=1.0), ) ], ) ], )) time.sleep(0.033) except KeyboardInterrupt: server.stop() ``` -------------------------------- ### Generate Protobuf Schemas with Cargo Source: https://github.com/foxglove/foxglove-sdk/blob/main/rust/foxglove/CONTRIBUTING.md Run this command to generate the necessary Protobuf schemas for the SDK. Ensure you have Rust and Cargo installed. ```bash cargo run --bin foxglove_proto_gen ``` -------------------------------- ### Integration Tests Setup Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/CMakeLists.txt Configures integration tests, requiring remote access and LiveKit. It fetches and builds necessary dependencies like the LiveKit C++ SDK and jwt-cpp. ```cmake if(FOXGLOVE_BUILD_INTEGRATION_TESTS) if(NOT FOXGLOVE_REMOTE_ACCESS) message(FATAL_ERROR "FOXGLOVE_BUILD_INTEGRATION_TESTS requires FOXGLOVE_REMOTE_ACCESS=ON") endif() # LiveKit C++ SDK set(LIVEKIT_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(LIVEKIT_BUILD_TESTS OFF CACHE BOOL "" FORCE) FetchContent_Declare( livekit GIT_REPOSITORY https://github.com/livekit/client-sdk-cpp.git GIT_TAG v0.3.4 ) FetchContent_MakeAvailable(livekit) # jwt-cpp (header-only JWT library for generating LiveKit access tokens) set(JWT_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(JWT_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(JWT_DISABLE_PICOJSON OFF CACHE BOOL "" FORCE) FetchContent_Declare( jwt-cpp GIT_REPOSITORY https://github.com/Thalhammer/jwt-cpp.git GIT_TAG v0.7.0 EXCLUDE_FROM_ALL ) FetchContent_MakeAvailable(jwt-cpp) file(GLOB foxglove_integration_test_srcs CONFIGURE_DEPENDS "foxglove/tests/integration/*.hpp" "foxglove/tests/integration/*.cpp" ) add_executable(integration_tests "${foxglove_integration_test_srcs}") set_property(TARGET integration_tests PROPERTY CXX_STANDARD 17) set_property(TARGET integration_tests PROPERTY CXX_STANDARD_REQUIRED True) target_compile_options(integration_tests PRIVATE ${SANITIZER_COMPILE_OPTIONS}) target_link_options(integration_tests PRIVATE ${SANITIZER_LINK_OPTIONS}) target_link_libraries(integration_tests PRIVATE foxglove_cpp_shared Catch2::Catch2WithMain nlohmann_json::nlohmann_json httplib::httplib livekit livekit_ffi jwt-cpp::jwt-cpp ) # Suppress warnings from third-party headers. foreach(_lib nlohmann_json::nlohmann_json httplib::httplib jwt-cpp::jwt-cpp) if(TARGET ${_lib}) get_target_property(_inc ${_lib} INTERFACE_INCLUDE_DIRECTORIES) if(_inc) target_include_directories(integration_tests SYSTEM PRIVATE ${_inc}) endif() endif() endforeach() if(TARGET livekit) get_target_property(_lk_inc livekit INTERFACE_INCLUDE_DIRECTORIES) if(_lk_inc) target_include_directories(integration_tests SYSTEM PRIVATE ${_lk_inc}) endif() endif() if(NOT CMAKE_CROSSCOMPILING AND NOT FOXGLOVE_SKIP_TEST_DISCOVERY) catch_discover_tests(integration_tests TEST_PREFIX "integration/" PROPERTIES LABELS "integration" TIMEOUT 30 ) endif() endif() ``` -------------------------------- ### Install foxglove-schemas-flatbuffer with uv Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-schemas-flatbuffer/README.md Use this command to add the foxglove-schemas-flatbuffer package to your project when using uv for dependency management. ```sh uv add foxglove-schemas-flatbuffer ``` -------------------------------- ### Start Remote Access Gateway with WebRTC Source: https://context7.com/foxglove/foxglove-sdk/llms.txt Connects a device to the Foxglove platform for remote visualization and teleoperation. Requires a device token and the `remote-access` feature. Implements a `Listener` for callbacks. ```rust use foxglove::{ChannelDescriptor, bytes::Bytes}; use foxglove::messages::{RawImage, Timestamp}; use foxglove::remote_access::{Capability, Client, ConnectionStatus, Gateway, Listener, QosProfile, Reliability}; struct Handler; impl Listener for Handler { fn on_connection_status_changed(&self, status: ConnectionStatus) { println!("Status: {status}"); } fn on_message_data(&self, client: &Client, channel: &ChannelDescriptor, msg: &[u8]) { println!("Teleop from {} on {}: {:?}", client.id(), channel.topic(), msg); } } #[tokio::main] async fn main() { let handle = Gateway::new() .name("my-robot") .capabilities([Capability::ClientPublish]) .supported_encodings(["json"]) .listener(std::sync::Arc::new(Handler)) .qos_classifier_fn(|ch: &ChannelDescriptor| { if ch.topic() == "/tf_static" { QosProfile::builder().reliability(Reliability::Reliable).build() } else { QosProfile::default() } }) .start() .expect("Failed to start remote access gateway"); // Log camera images; the gateway encodes them as a video stream foxglove::log!("/camera/image", RawImage { timestamp: Some(Timestamp::now()), frame_id: "camera".into(), width: 640, height: 480, encoding: "rgb8".into(), step: 640 * 3, data: Bytes::from(vec![0u8; 640 * 480 * 3]), }); _ = handle.stop().await; } ``` -------------------------------- ### Parameter server Source: https://context7.com/foxglove/foxglove-sdk/llms.txt Implement `foxglove.websocket.ServerListener` and start the server with `Capability.Parameters` to allow the Foxglove Parameters panel to read and write your application's runtime values. ```APIDOC ## Parameter server ### Description Implement `foxglove.websocket.ServerListener` and start the server with `Capability.Parameters` to allow the Foxglove Parameters panel to read and write your application's runtime values. ### Method Python function call ### Parameters - **server_listener** (ServerListener) - Required - An instance of a class implementing `ServerListener`. - **capabilities** (list of Capability) - Required - Must include `Capability.Parameters`. ### Request Example ```python import time import foxglove from foxglove.websocket import Capability, Client, Parameter, ServerListener from typing import List, Optional class ParamStore(ServerListener): def __init__(self): self.params = { "max_speed": Parameter("max_speed", value=2.0), "enabled": Parameter("enabled", value=True), "label": Parameter("label", value="robot-1"), } def on_get_parameters(self, client: Client, names: List[str], request_id: Optional[str] = None) -> List[Parameter]: return list(self.params.values()) if not names else [self.params[n] for n in names if n in self.params] def on_set_parameters(self, client: Client, parameters: List[Parameter], request_id: Optional[str] = None) -> List[Parameter]: for p in parameters: if p.value is None: self.params.pop(p.name, None) else: self.params[p.name] = p return parameters store = ParamStore() server = foxglove.start_server( server_listener=store, capabilities=[Capability.Parameters], ) try: while True: server.publish_parameter_values(list(store.params.values())) time.sleep(5) except KeyboardInterrupt: server.stop() ``` ### Response This function starts a server and does not return a value directly related to parameter operations. The server runs in the background, and parameter updates are handled via the `ServerListener` callbacks. ``` -------------------------------- ### C++ McapWriter and WebSocketServer Quickstart Source: https://context7.com/foxglove/foxglove-sdk/llms.txt Demonstrates creating an MCAP writer and a WebSocket server, logging SceneUpdate messages to a typed channel and JSON to a raw channel. Includes error handling for creation of writer, server, and channels. ```cpp #include #include #include #include #include #include #include using namespace std::chrono_literals; int main() { foxglove::setLogLevel(foxglove::LogLevel::Debug); // Create an MCAP writer foxglove::McapWriterOptions mcap_opts = {}; mcap_opts.path = "output.mcap"; auto writer = foxglove::McapWriter::create(mcap_opts); if (!writer) { std::cerr << "MCAP error\n"; return 1; } // Create a WebSocket server foxglove::WebSocketServerOptions ws_opts; ws_opts.host = "127.0.0.1"; ws_opts.port = 8765; auto server = foxglove::WebSocketServer::create(std::move(ws_opts)); if (!server) { std::cerr << "WS error\n"; return 1; } std::cerr << "Listening on port " << server->port() << "\n"; // Typed channel for SceneUpdate messages auto scene_ch = foxglove::messages::SceneUpdateChannel::create("/scene"); if (!scene_ch) { std::cerr << "Channel error\n"; return 1; } // Raw channel for JSON foxglove::Schema schema; schema.encoding = "jsonschema"; std::string sd = R"({"type":"object","properties":{"v":{"type":"number"}}})"; schema.data = reinterpret_cast(sd.data()); schema.data_len = sd.size(); auto raw_ch = foxglove::RawChannel::create("/value", "json", std::move(schema)); if (!raw_ch) { std::cerr << "Raw channel error\n"; return 1; } for (int i = 0; i < 100; ++i) { double v = std::abs(std::sin(i * 0.1)) + 0.5; std::string msg = "{\"v\":" + std::to_string(v) + "}"; raw_ch->log(reinterpret_cast(msg.data()), msg.size()); foxglove::messages::SceneUpdate su; foxglove::messages::SceneEntity ent; ent.id = "sphere"; foxglove::messages::SpherePrimitive sph; sph.size = {v, v, v}; sph.color = {0.2f, 0.6f, 1.0f, 1.0f}; ent.spheres.push_back(sph); su.entities.push_back(ent); scene_ch->log(su); std::this_thread::sleep_for(33ms); } return 0; } ``` -------------------------------- ### Install Foxglove C++ Libraries Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/CMakeLists.txt Configures the installation of the Foxglove C++ static and shared libraries. The behavior differs based on whether FOXGLOVE_REMOTE_ACCESS is enabled, affecting which library targets are installed. ```cmake if(FOXGLOVE_REMOTE_ACCESS) install(TARGETS foxglove_cpp_shared EXPORT foxglove-sdkTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) else() install(TARGETS foxglove_cpp_static foxglove_cpp_shared EXPORT foxglove-sdkTargets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) # Install the Rust/C static library install(FILES $ DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() # Install the Rust/C shared library install(FILES $ DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ``` -------------------------------- ### Install Bridge Header Source: https://github.com/foxglove/foxglove-sdk/blob/main/ros/src/foxglove_bridge/CMakeLists.txt Installs the main header file for the foxglove_bridge package. ```cmake install(FILES include/foxglove_bridge/ros2_foxglove_bridge.hpp DESTINATION include/${PROJECT_NAME}/ ) ``` -------------------------------- ### Install OpenCV Dependencies (macOS) Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/examples/rgb-camera-visualization/README.md Install OpenCV on macOS using Homebrew. ```bash brew install opencv ``` -------------------------------- ### Generate and Install CMake Package Config Files Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/CMakeLists.txt Generates and installs the CMake package configuration files (`foxglove-sdkConfig.cmake` and `foxglove-sdkConfigVersion.cmake`) which allow other CMake projects to find and use the installed Foxglove SDK. ```cmake configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/foxglove-sdkConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/foxglove-sdkConfig.cmake" INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/foxglove-sdk ) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/foxglove-sdkConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMinorVersion ) install(EXPORT foxglove-sdkTargets FILE foxglove-sdkTargets.cmake NAMESPACE foxglove-sdk:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/foxglove-sdk ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/foxglove-sdkConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/foxglove-sdkConfigVersion.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/foxglove-sdk ) ``` -------------------------------- ### Install Bridge Component Library Source: https://github.com/foxglove/foxglove-sdk/blob/main/ros/src/foxglove_bridge/CMakeLists.txt Installs the foxglove_bridge_component library to the appropriate locations (lib, archive, runtime). ```cmake install(TARGETS foxglove_bridge_component ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin ) ``` -------------------------------- ### Install Rust Toolchain for WASM Source: https://github.com/foxglove/foxglove-sdk/blob/main/playground/README.md Install Rust toolchain version 1.86.0 and add the wasm32-unknown-emscripten target. ```sh rustup toolchain install 1.86.0 rustup target add wasm32-unknown-emscripten --toolchain 1.86.0 ``` -------------------------------- ### Configure Install RPATH for Component Source: https://github.com/foxglove/foxglove-sdk/blob/main/ros/src/foxglove_bridge/CMakeLists.txt Sets the installation RPATH for the foxglove_bridge_component to '$ORIGIN', ensuring runtime libraries are found. ```cmake set_target_properties(foxglove_bridge_component PROPERTIES INSTALL_RPATH "$ORIGIN" BUILD_WITH_INSTALL_RPATH TRUE ) ``` -------------------------------- ### Stream Data to Foxglove with C++ WebSocket Server Source: https://github.com/foxglove/foxglove-sdk/blob/main/cpp/foxglove/docs/examples.md This example demonstrates how to set up a C++ WebSocket server using the Foxglove SDK to stream data. It includes configuring server options, handling client subscriptions and unsubscriptions, advertising channels, and publishing messages. The server continuously publishes messages with a counter until interrupted. ```cpp #include #include #include #include #include #include #include #include #include #include using namespace std::chrono_literals; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static std::function sigint_handler; // NOLINTNEXTLINE(bugprone-exception-escape) int main() { std::signal(SIGINT, [](int) { if (sigint_handler) { sigint_handler(); } }); foxglove::setLogLevel(foxglove::LogLevel::Debug); foxglove::WebSocketServerOptions options = {}; options.name = "ws-demo-cpp"; options.host = "127.0.0.1"; options.port = 8765; options.capabilities = foxglove::WebSocketServerCapabilities::ClientPublish; options.supported_encodings = {"json"}; options.callbacks.onSubscribe = [](uint64_t channel_id, const foxglove::ClientMetadata& client) { std::cerr << "Client " << client.id << " subscribed to channel " << channel_id << '\n'; }; options.callbacks.onUnsubscribe = [](uint64_t channel_id, const foxglove::ClientMetadata& client) { std::cerr << "Client " << client.id << " unsubscribed from channel " << channel_id << '\n'; }; options.callbacks.onClientAdvertise = [](uint32_t client_id, const foxglove::ClientChannel& channel) { std::cerr << "Client " << client_id << " advertised channel " << channel.id << ":\n"; std::cerr << " Topic: " << channel.topic << '\n'; std::cerr << " Encoding: " << channel.encoding << '\n'; std::cerr << " Schema name: " << channel.schema_name << '\n'; std::cerr << " Schema encoding: " << (!channel.schema_encoding.empty() ? channel.schema_encoding : "(none)") << '\n'; std::cerr << " Schema: " << (channel.schema != nullptr ? std::string(reinterpret_cast(channel.schema), channel.schema_len) : "(none)") << '\n'; }; options.callbacks.onMessageData = [](uint32_t client_id, uint32_t client_channel_id, const std::byte* data, size_t data_len) { std::cerr << "Client " << client_id << " published on channel " << client_channel_id << ": " << std::string(reinterpret_cast(data), data_len) << '\n'; }; options.callbacks.onClientUnadvertise = [](uint32_t client_id, uint32_t client_channel_id) { std::cerr << "Client " << client_id << " unadvertised channel " << client_channel_id << '\n'; }; auto server_result = foxglove::WebSocketServer::create(std::move(options)); if (!server_result.has_value()) { std::cerr << "Failed to create server: " << foxglove::strerror(server_result.error()) << '\n'; return 1; } auto server = std::move(server_result.value()); std::atomic_bool done = false; sigint_handler = [&] { std::cerr << "Shutting down...\n"; server.stop(); done = true; }; foxglove::Schema schema; schema.name = "Test"; schema.encoding = "jsonschema"; std::string schema_data = R"({ "type": "object", "properties": { "val": { "type": "number" } } })"; schema.data = reinterpret_cast(schema_data.data()); schema.data_len = schema_data.size(); auto channel_result = foxglove::RawChannel::create("example", "json", std::move(schema)); if (!channel_result.has_value()) { std::cerr << "Failed to create channel: " << foxglove::strerror(channel_result.error()) << '\n'; return 1; } auto channel = std::move(channel_result.value()); uint32_t i = 0; while (!done) { std::this_thread::sleep_for(100ms); std::string msg = "{\"val\": " + std::to_string(i) + "}"; auto now = std::chrono::nanoseconds(std::chrono::system_clock::now().time_since_epoch()).count(); channel.log(reinterpret_cast(msg.data()), msg.size(), now); ++i; } std::cerr << "Done\n"; return 0; } ``` -------------------------------- ### Run Visualization with Camera Feeds Source: https://github.com/foxglove/foxglove-sdk/blob/main/python/foxglove-sdk-examples/so101-visualization/README.md Launches the visualization script, including feeds from the wrist and environment cameras. Provide the respective camera IDs for accurate data streaming. ```bash python main.py \ --robot.port=/dev/ttyUSB0 \ --robot.id=my_so101_arm \ --robot.wrist_cam_id=0 \ --robot.env_cam_id=4 ``` -------------------------------- ### foxglove.start_gateway() Source: https://context7.com/foxglove/foxglove-sdk/llms.txt Connects to the Foxglove platform and opens a WebRTC gateway for remote visualization and bidirectional teleoperation. Requires the FOXGLOVE_DEVICE_TOKEN environment variable or an explicit device_token argument. ```APIDOC ## `foxglove.start_gateway()` — remote visualization over WebRTC (Python) Connects to the Foxglove platform and opens a WebRTC gateway for remote visualization and bidirectional teleop. Requires `FOXGLOVE_DEVICE_TOKEN` environment variable or explicit `device_token=` argument. Implement `RemoteAccessListener` to handle incoming teleop messages. ```python import json, logging, time import foxglove from foxglove import ChannelDescriptor from foxglove.channels import RawImageChannel from foxglove.messages import RawImage from foxglove.remote_access import Capability, Client, RemoteAccessConnectionStatus, RemoteAccessListener class MyListener(RemoteAccessListener): def on_connection_status_changed(self, status: RemoteAccessConnectionStatus) -> None: logging.info(f"Gateway status: {status}") def on_message_data(self, client: Client, channel: ChannelDescriptor, data: bytes) -> None: cmd = json.loads(data) logging.info(f"Teleop from {client.id} on {channel.topic}: {cmd}") foxglove.set_log_level(logging.INFO) gateway = foxglove.start_gateway( name="my-robot", capabilities=[Capability.ClientPublish], supported_encodings=["json"], listener=MyListener(), ) img_chan = RawImageChannel("/camera/image") try: frame = 0 while True: raw_pixels = bytes([frame % 256] * (640 * 480 * 3)) # dummy RGB8 frame img_chan.log(RawImage( frame_id="camera", width=640, height=480, encoding="rgb8", step=640*3, data=raw_pixels, ), log_time=time.time_ns()) frame += 1 time.sleep(1/30) except KeyboardInterrupt: gateway.stop() ``` ```