Running Your First App
Caution
This section is only relevant to users who are working within the pntOS-Python repository. Downstream users will need to write their own apps to run. For help on building your own apps, see The Exercises
In the apps/ directory, there are several off-the-shelf apps of increasing complexity assembled from off-the-shelf Cobra plugins that
serve to demonstrate pntOS-Python and the development process for you to
build your own apps. This page serves as an introduction to running an
arbitrary Cobra app. For more details on any particular app, refer
to the corresponding page in the Tutorial Apps section of the docs.
Running an App
A Python app consists of a Python script containing all plugin imports, config, and code needed to start a particular instance of a pntOS-Python implementation. The Cobra plugin set contains a Transport plugin that retrieves ASPN messages from an LCM relay. This allows pntOS to ingest data either from sensors sending ASPN measurements live, or (in the case of the tutorial apps) from an LCM log file replaying data over the relay.
These instructions will walk you through starting a generic app, spinning up the LCM relay, and playing back a log file to feed data into pntOS.
Activate Virtual Environment
These instructions assume an active virtual environment as outlined in the Installation Guide. If you currently have that virtual environment activated, skip to Select and Run an App.
If you have not yet created a Python virtual environment for the pntos-python
repository, follow the instructions in Installation Guide then go
to Select and Run an App.
If you have created the virtual environment but it is not currently activated, run the below command from the root directory to enter the virtual environment. The command varies depending on your shell:
source .venv/bin/activate
source .venv/bin/activate.fish
Select and Run an App
The available apps can be found in each subfolder of the {workspace-root}/apps
directory. If this is your first time with pntOS-Python, it is recommended you
start with the pos_ins app. If you are running your own custom app, just switch out
the paths to the off-the-shelf apps with the path to your app in the following
instructions.
The available off-the-shelf apps are in the Tutorial Apps section of these docs.
For documentation specifically explaining this app, see POS INS App.
Run the POS INS Tutorial App
To run this app, run this command from the root workspace directory (with the Python virtual environment activated):
apps/tutorial/pos_ins.py
Once the app is started, it will immediately start processing messages from the input log, with a progress bar tracking the percentage of messages that have been processed. Once the entire input log has been processed, you should see something like the following:
[17/02/2026 14:47:19] [LoggingPlugin] [INFO] using hard-coded global logging level INFO
[17/02/2026 14:47:19] [OrchestrationPlugin] [INFO] Aligned filter at 1747680879.539799929s
[17/02/2026 14:47:19] [TransportPlugin] [INFO] LCM log reader is running.
[17/02/2026 14:47:19] [ControllerPlugin] [INFO] Press Ctrl + C at any time to shut down pntOS...
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/vn-100/imu with a timestamp of 1747680879.539799690s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ins-d/pva with a timestamp of 1747680879.543048859s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/simulated/velocity with a timestamp of 1747680879.543048859s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/position with a timestamp of 1747680880.300589800s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/velocity with a timestamp of 1747680880.300589800s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/pva with a timestamp of 1747680880.300589800s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/bmp388/baro_pressure with a timestamp of 1747680880.328312635s
100%|██████████████████████████████████████████████████████████████████████████████████████████████| 472M/472M [00:37<00:00, 12.7MB/s]
[18/02/2026 15:10:38] [TransportPlugin] [INFO] Done processing LCM log. Press Ctrl + C to shut down pntOS.
For tutorial apps, a UI plugin for LCM log plotting is initiated on shutdown. Pressing Ctrl + C after running the tutorial app will start the shutdown process and display something like the following:
[17/02/2026 14:51:41] [ControllerPlugin] [INFO] Keyboard Interrupt Detected.
[17/02/2026 14:51:41] [ControllerPlugin] [INFO] Shutting down all plugins...
[17/02/2026 14:51:41] [TransportPlugin] [INFO] Shutdown plugin for Cobra LCM Log Transport Plugin.
Reading measurements from log...
100%|█████████████████████████████████████████████████████████████████████████████████████████████████| 475M/475M [00:13<00:00, 34.0MB/s]
[17/02/2026 14:51:57] [UiPlugin] [INFO] Plotting results. Close all windows to continue shutdown.
[17/02/2026 14:52:10] [UiPlugin] [INFO] Plots saved to pntos_output.
The results from the tutorial app will be displayed in separate windows. To continue with the shutdown, simply close all the plotting windows.
Note
The UI plotting plugin is only used in tutorial apps.
However, most apps record the pntOS solution to pntos_output.log by default for plotting or further processing.
For information on how to plot the pntOS solution from a log file, see View Results from a Log File.
For documentation specifically explaining this app, see POS Velocity INS App.
Run the Position and Velocity Update App
To run this app, run this command from the root workspace directory (with the Python virtual environment activated):
apps/tutorial/pos_vel_ins.py
Once the app is started, it will immediately start processing messages from the input log, with a progress bar tracking the percentage of messages that have been processed. Once the entire input log has been processed, you should see something like the following:
[17/02/2026 14:47:19] [LoggingPlugin] [INFO] using hard-coded global logging level INFO
[17/02/2026 14:47:19] [OrchestrationPlugin] [INFO] Aligned filter at 1747680879.539799929s
[17/02/2026 14:47:19] [TransportPlugin] [INFO] LCM log reader is running.
[17/02/2026 14:47:19] [ControllerPlugin] [INFO] Press Ctrl + C at any time to shut down pntOS...
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/vn-100/imu with a timestamp of 1747680879.539799690s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ins-d/pva with a timestamp of 1747680879.543048859s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/simulated/velocity with a timestamp of 1747680879.543048859s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/position with a timestamp of 1747680880.300589800s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/velocity with a timestamp of 1747680880.300589800s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/pva with a timestamp of 1747680880.300589800s
[18/02/2026 15:10:01] [TransportPlugin] [INFO] Found new channel /sensor/bmp388/baro_pressure with a timestamp of 1747680880.328312635s
100%|██████████████████████████████████████████████████████████████████████████████████████████████| 472M/472M [00:37<00:00, 12.7MB/s]
[18/02/2026 15:10:38] [TransportPlugin] [INFO] Done processing LCM log. Press Ctrl + C to shut down pntOS.
For tutorial apps, a UI plugin for LCM log plotting is initiated on shutdown. Pressing Ctrl + C after running the tutorial app will start the shutdown process and display something like the following:
[17/02/2026 14:51:41] [ControllerPlugin] [INFO] Keyboard Interrupt Detected.
[17/02/2026 14:51:41] [ControllerPlugin] [INFO] Shutting down all plugins...
[17/02/2026 14:51:41] [TransportPlugin] [INFO] Shutdown plugin for Cobra LCM Log Transport Plugin.
Reading measurements from log...
100%|█████████████████████████████████████████████████████████████████████████████████████████████████| 475M/475M [00:13<00:00, 34.0MB/s]
[17/02/2026 14:51:57] [UiPlugin] [INFO] Plotting results. Close all windows to continue shutdown.
[17/02/2026 14:52:10] [UiPlugin] [INFO] Plots saved to pntos_output.
The results from the tutorial app will be displayed in separate windows. To continue with the shutdown, simply close all the plotting windows.
Note
The UI plotting plugin is only used in tutorial apps.
However, most apps record the pntOS solution to pntos_output.log by default for plotting or further processing.
For information on how to plot the pntOS solution from a log file, see View Results from a Log File.
For documentation specifically explaining this app, see Standard POS INS App.
Run the POS INS Standard App
To run this app, run this command from the root workspace directory (with the Python virtual environment activated):
apps/standard/pos_ins.py
Once the app is started, it will immediately start processing messages from the input log, with a progress bar tracking the percentage of messages that have been processed. Once the entire input log has been processed, you should see something like the following:
[18/02/2026 15:47:50] [LoggingPlugin] [INFO] using hard-coded global logging level INFO
[18/02/2026 15:47:50] [TransportPlugin] [INFO] LCM log reader is running.
[18/02/2026 15:47:50] [ControllerPlugin] [INFO] Press Ctrl + C at any time to shut down pntOS...
[18/02/2026 15:47:50] [TransportPlugin] [INFO] Found new channel /sensor/vn-100/imu with a timestamp of 1747680879.539799690s
[18/02/2026 15:47:50] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/position with a timestamp of 1747680880.300589800s
[18/02/2026 15:47:50] [OrchestrationPlugin] [INFO] Aligned filter at 1747680889.549539804s
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████▉| 472M/472M [00:26<00:00, 18.0MB/s]
[18/02/2026 15:48:16] [TransportPlugin] [INFO] Done processing LCM log. Press Ctrl + C to shut down pntOS.
The pntOS solution will be recorded to pntos_output.log and you can press Ctrl + C to shut down pntOS.
For information on how to plot the pntOS solution from a log file, see View Results from a Log File.
The LCM Relay App is similar to the POS INS Standard App, but uses a different transport plugin that requires the user to separately spin up an LCM relay, and manually record the output log file. The purpose of this app is to support real-time use cases where pntOS may ingest sensor data over the network, and broadcast a live solution.
To run this app, follow the steps below:
Warning
The following commands each require separate terminals. Be sure to activate the virtual environment for each terminal as described in Activate Virtual Environment before running these commands.
Start a Local TCP Server
In order to feed messages into the transport plugin from an LCM log file, we need to first start a local TCP server (located in the virtual environment) in a new terminal:
java -classpath $VIRTUAL_ENV/lib/python3.*/site-packages/share/java/lcm.jar lcm.lcm.TCPService
Play LCM Log File
The pntos-python-datasets package installs a script to find the installed data and start playing
it back:
play-dataset
Note
If you would like to see what the above command is doing or would like to know where the dataset
exists on the disk, you can run the command with a -v verbose flag:
play-dataset -v
Running the above will print out the exact command the script executes before executing it.
This should open the LCM LogPlayer GUI with a play button. You should see the following channels:
/sensor/bmp388/baro_pressure
/sensor/ins-d/pva
/sensor/simulated/velocity
/sensor/ublox-ZED-F9T/position
/sensor/ublox-ZED-F9T/pva
/sensor/ublox-ZED-F9T/velocity
/sensor/vn-100/imu
Record Output
If you wish to record the pntOS solutions that are published by the LCM transport plugin, start the lcm-logger:
Warning
You must delete or rename any existing pntos_output.log files before running this command.
lcm-logger --lcm-url=tcpq:// pntos_output.log
This process will listen to any messages transmitted over LCM and record them to pntos_output.log.
Alternatively, to just see the solution printed to the terminal, set the logging level
to DEBUG when initializing the pntos.cobra.StandardLoggingPlugin.
Run the LCM Relay App
Finally, to start the LCM Relay App run the following command in a new terminal:
apps/standard/lcm_relay.py
This will spin up pntOS and it is ready to start processing messages. To produce solutions, simply
push the play button in the LogPlayer to start the datastream. You should see something similar to the following:
[20/02/2026 12:14:00] [LoggingPlugin] [INFO] using hard-coded global logging level INFO
LCM tcpq: connecting...
[20/02/2026 12:14:00] [TransportPlugin] [INFO] LCM message handler is running.
[20/02/2026 12:14:00] [ControllerPlugin] [INFO] Press Ctrl + C at any time to shut down pntOS...
[20/02/2026 12:14:03] [TransportPlugin] [INFO] Found new channel /sensor/ins-d/pva with a timestamp of 1747680882.938483715s
[20/02/2026 12:14:03] [TransportPlugin] [INFO] Found new channel /sensor/vn-100/imu with a timestamp of 1747680882.940131664s
[20/02/2026 12:14:03] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/position with a timestamp of 1747680883.294163942s
[20/02/2026 12:14:03] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/velocity with a timestamp of 1747680883.294163942s
[20/02/2026 12:14:03] [TransportPlugin] [INFO] Found new channel /sensor/ublox-ZED-F9T/pva with a timestamp of 1747680883.294163942s
[20/02/2026 12:14:04] [TransportPlugin] [INFO] Found new channel /sensor/simulated/velocity with a timestamp of 1747680883.543442726s
[20/02/2026 12:14:06] [TransportPlugin] [INFO] Found new channel /sensor/bmp388/baro_pressure with a timestamp of 1747680885.336656809s
[20/02/2026 12:14:13] [OrchestrationPlugin] [INFO] Aligned filter at 1747680892.949498653s
Unlike the other apps, there will be no progess bar displayed in the console. The LogPlayer will have a progress bar where you can track the progress
of the log file. Once it is done processing, you may press Ctrl + C to shutdown pntOS.
Note
You may click the >> button in the LogPlayer GUI to speed up the playback. However, if the data is played
too fast, pntOS may not be able to provide solutions at the requested rate. In this case, you will want
to wait for pntOS to process all messages before shutting down. To know when pntOS is done processing
data, you can observe the terminal output where the lcm-logger command was run (see Record Output),
which will print summary statements at 1 second intervals until no more traffic is observed on the network
bus.
pntOS includes several other off-the-shelf apps that are not mentioned on this page.
Each app is categorized as a dummy, tutorial, standard, or advanced app where each
type showcases certain capabilities and features of pntOS from low to high complexity.
Any other apps not mentioned here may be run with the following command:
apps/{app-type}/{app-name}.py
Where you would replace {app-type} with the app’s designated type, and replace {app-name} with the name
of the Python script of the actual app. This is essentially just a path to the executable Python file.
View Results from a Log File
To view the plots of the results from a log file run:
postprocessing/plot_results.py pntos_output.log
This should display the pntOS results in individual windows and save the plots
to the {workspace-root}/pntos_output directory.
Tip
Included in the source code is a convenience script that will run an app, process an example log file, and plot the results all via a single command. It will work on any of the existing apps that produce a PVA solution from the example LCM or ROS logs.
To use it, simply run:
postprocessing/run_app_and_record_data.py <path/to/app.py>
Where <path/to/app.py> should be replaced with the path to the app you want to run.