Skip to main content

Create topic converter

This guide shows how to build a topic message converter that computes and plots the absolute value of acceleration data from a topic.

Setting up

In a Terminal window, cd into the directory where your source code will live and run the following command:

npm init foxglove-extension@latest myExtensionName

This uses create-foxglove-extension to create a myExtensionName directory containing source code for an example message converter.

Registering a converter

The index.ts file in your project's src folder is the entry point for your extension source code. It must export an activate function that accepts a single extensionContext argument of type ExtensionContext.

To register a message converter, we call registerMessageConverter on the extensionContext argument with the type topic and several arguments to define the input and output.

import { ExtensionContext, Immutable } from "@foxglove/extension";

type MySignal = { acceleration: number };

export function activate(extensionContext: ExtensionContext): void {
extensionContext.registerMessageConverter({
type: "topic",
inputTopics: ["/acceleration"],
outputTopic: "/acceleration/absolute",
outputSchemaName: "AccelerationAbsolute",
outputSchemaDescription: { value: "number" },
create: () => {
// create() returns a function that the app will call with a MessageEvent
// for every input message. The input MessageEvents are in log time order.
return (msgEvent) => {
const msg = msgEvent.message as Immutable<MySignal>;
return { value: Math.abs(msg.acceleration) };
};
},
});
}

Line-by-line explanation

Let's go through the lines above to explain what happens.

type: "topic"

This tells Foxglove that we're registering a topic message converter. Topic message converters use messages from one or more input topics to compute a new message on an output topic.

inputTopics: ["/acceleration"]

This tells Foxglove that we want to process incoming messages on the /acceleration topic.

outputTopic: "/acceleration/absolute"

This tells Foxglove that we want to output messages to the /acceleration/absolute topic.

note

The output topic is local to the app, it is not published back to a live connection or external system.

outputSchemaName: "AccelerationAbsolute"

We've set the schema name for our output topic to AccelerationAbsolute.

All topics have an associated schema name for the type of messages they contain. Since our topic is producing a new custom message type, we can pick any schema name we want.

tip

For topics that produce custom messages, avoid schema names that conflict with existing schema names in your data source or well-known schema names.

outputSchemaDescription: { value: "number" }

Here we define the actual schema for the output message. Our converter will output one field, named value in the new message and that field will be a number.

To power message path selection and autocomplete (i.e. in the plot panel series config or raw message panel), the app needs to know the shape of the messages you are creating.

API Reference: MessageSchemaDescription

tip

If your topic converter outputs official ROS schemas or Foxglove schemas (like foxglove.LocationFix, foxglove.PointCloud, sensor_msgs/PointCloud2, etc.), do NOT provide an outputSchemaDescription. Providing one will attempt to override the existing schema and produce an error.

Only use outputSchemaDescription when creating custom message types. For official schemas, only set the outputSchemaName to the schema name. The most recent versions of these schemas are built into Foxglove and aren't necessary to define again.

create: () => { ... }

The create function initializes the converter. It is called by the app to create the converter when some panel subscribes to the output topic.

It should return a function that will be called with a MessageEvent for every input message (from the input topics).

return (msgEvent) => { ... }

This function, returned by the create function, is called with a MessageEvent for every input message. It performs any computation and returns a new message matching the schema description. You can optionally return undefined to skip producing a message for the given input.

Example: Using Foxglove schemas

Here's an example of a topic converter that outputs the official foxglove.LocationFix schema:

import { ExtensionContext, Immutable } from "@foxglove/extension";

export function activate(extensionContext: ExtensionContext): void {
extensionContext.registerMessageConverter({
type: "topic",
inputTopics: ["/gps/raw"],
outputTopic: "/gps/location",
outputSchemaName: "foxglove.LocationFix",
// Do not provide outputSchemaDescription - Foxglove will use the built-in schema
create: () => {
return (msgEvent) => {
const raw = msgEvent.message as any;
// Convert your custom GPS data to foxglove.LocationFix format
return {
timestamp: msgEvent.receiveTime,
frame_id: "gps",
latitude: raw.lat,
longitude: raw.lon,
altitude: raw.alt,
position_covariance_type: 0, // COVARIANCE_TYPE_UNKNOWN
position_covariance: new Float64Array(9).fill(0),
};
};
},
});
}

Note that we only specify outputSchemaName and omit outputSchemaDescription entirely. This allows the topic converter to use the official schema definition that's already built into Foxglove.

Testing

Once we've packaged and installed our extension, load any data source containing our custom /acceleration topic and visualize them with the Plot panel by selecting the message path /acceleration/absolute.value as the series to plot.

note

Message converters run on-demand only when the topic is subscribed to by a panel.