# Basalt VIO

The example creates a pipeline to capture 640x400 stereo camera frames at 60 FPS and IMU data at 200 Hz, processes them with
BasaltVIO for visual odometry, and streams the resulting transformations and images to a RerunNode for real-time visualization.

> VSLAM host nodes are available on the
> `depthai-core`
> main branch by default, but they remain in early access and may be less stable or less thoroughly tested than other nodes.

This example requires the DepthAI v3 API, see [installation instructions](https://docs.luxonis.com/software-v3/depthai.md).

## Pipeline

### examples/basalt_vio.pipeline.json

```json
{"pipeline": {"connections": [{"node1Id": 4, "node1Output": "out", "node1OutputGroup": "", "node2Id": 6, "node2Input": "in", "node2InputGroup": ""}, {"node1Id": 2, "node1Output": "out", "node1OutputGroup": "", "node2Id": 8, "node2Input": "in", "node2InputGroup": ""}, {"node1Id": 1, "node1Output": "0", "node1OutputGroup": "dynamicOutputs", "node2Id": 4, "node2Input": "right", "node2InputGroup": "inputs"}, {"node1Id": 0, "node1Output": "0", "node1OutputGroup": "dynamicOutputs", "node2Id": 4, "node2Input": "left", "node2InputGroup": "inputs"}], "globalProperties": {"calibData": null, "cameraTuningBlobSize": null, "cameraTuningBlobUri": "", "leonCssFrequencyHz": 700000000.0, "leonMssFrequencyHz": 700000000.0, "pipelineName": null, "pipelineVersion": null, "sippBufferSize": 18432, "sippDmaBufferSize": 16384, "xlinkChunkSize": -1}, "nodes": [[8, {"alias": "", "id": 8, "ioInfo": [[["", "in"], {"blocking": true, "group": "", "id": 14, "name": "in", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "XLinkOut", "parentId": -1, "properties": {"maxFpsLimit": -1.0, "metadataOnly": false, "streamName": "__x_2__out"}}], [6, {"alias": "", "id": 6, "ioInfo": [[["", "in"], {"blocking": true, "group": "", "id": 13, "name": "in", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "XLinkOut", "parentId": -1, "properties": {"maxFpsLimit": -1.0, "metadataOnly": false, "streamName": "__x_4__out"}}], [4, {"alias": "sync", "id": 4, "ioInfo": [[["", "out"], {"blocking": false, "group": "", "id": 12, "name": "out", "queueSize": 8, "type": 0, "waitForMessage": false}], [["inputs", "left"], {"blocking": false, "group": "inputs", "id": 11, "name": "left", "queueSize": 10, "type": 3, "waitForMessage": false}], [["inputs", "right"], {"blocking": false, "group": "inputs", "id": 10, "name": "right", "queueSize": 10, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "Sync", "parentId": 3, "properties": {"syncAttempts": -1, "syncThresholdNs": 10000000}}], [2, {"alias": "", "id": 2, "ioInfo": [[["", "out"], {"blocking": false, "group": "", "id": 9, "name": "out", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "mockIn"], {"blocking": true, "group": "", "id": 8, "name": "mockIn", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "IMU", "parentId": -1, "properties": {"batchReportThreshold": 1, "enableFirmwareUpdate": false, "imuSensors": [{"changeSensitivity": 0, "reportRate": 200, "sensitivityEnabled": false, "sensitivityRelative": false, "sensorId": 20}, {"changeSensitivity": 0, "reportRate": 200, "sensitivityEnabled": false, "sensitivityRelative": false, "sensorId": 21}], "maxBatchReports": 10}}], [1, {"alias": "", "id": 1, "ioInfo": [[["dynamicOutputs", "0"], {"blocking": false, "group": "dynamicOutputs", "id": 7, "name": "0", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "raw"], {"blocking": false, "group": "", "id": 6, "name": "raw", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "mockIsp"], {"blocking": true, "group": "", "id": 5, "name": "mockIsp", "queueSize": 8, "type": 3, "waitForMessage": false}], [["", "inputControl"], {"blocking": true, "group": "", "id": 4, "name": "inputControl", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "Camera", "parentId": -1, "properties": {"boardSocket": 2, "cameraName": "", "fps": 60.0, "imageOrientation": -1, "initialControl": {"aeLockMode": false, "aeMaxExposureTimeUs": 1931502958, "aeRegion": {"height": 8224, "priority": 538976288, "width": 8224, "x": 23861, "y": 2604}, "afRegion": {"height": 25954, "priority": 1530753900, "width": 24940, "x": 8224, "y": 8224}, "antiBandingMode": 110, "autoFocusMode": 3, "awbLockMode": false, "awbMode": 34, "brightness": 112, "captureIntent": 101, "chromaDenoise": 114, "cmdMask": 0, "contrast": 32, "controlMode": 32, "effectMode": 115, "enableHdr": false, "expCompensation": 105, "expManual": {"exposureTimeUs": 808333403, "frameDurationUs": 808463920, "sensitivityIso": 539768114}, "frameSyncMode": 116, "lensPosAutoInfinity": 100, "lensPosAutoMacro": 105, "lensPosition": 0, "lensPositionRaw": 0.0, "lowPowerNumFramesBurst": 44, "lowPowerNumFramesDiscard": 10, "lumaDenoise": 101, "miscControls": [], "saturation": 116, "sceneMode": 111, "sharpness": 104, "strobeConfig": {"activeLevel": 105, "enable": 114, "gpioNumber": 112}, "strobeTimings": {"durationUs": 1864393838, "exposureBeginOffsetUs": 577073765, "exposureEndOffsetUs": 1629626412}, "wbColorTemp": 23842}, "isp3aFps": 0, "mockIspHeight": -1, "mockIspWidth": -1, "numFramesPoolIsp": 3, "numFramesPoolPreview": 4, "numFramesPoolRaw": 3, "numFramesPoolStill": 4, "numFramesPoolVideo": 4, "outputRequests": [{"enableUndistortion": null, "fps": {"value": null}, "resizeMode": 0, "size": {"value": {"index": 0, "value": [640, 400]}}, "type": null}], "resolutionHeight": -1, "resolutionWidth": -1}}], [0, {"alias": "", "id": 0, "ioInfo": [[["dynamicOutputs", "0"], {"blocking": false, "group": "dynamicOutputs", "id": 3, "name": "0", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "raw"], {"blocking": false, "group": "", "id": 2, "name": "raw", "queueSize": 8, "type": 0, "waitForMessage": false}], [["", "mockIsp"], {"blocking": true, "group": "", "id": 1, "name": "mockIsp", "queueSize": 8, "type": 3, "waitForMessage": false}], [["", "inputControl"], {"blocking": true, "group": "", "id": 0, "name": "inputControl", "queueSize": 3, "type": 3, "waitForMessage": false}]], "logLevel": 3, "name": "Camera", "parentId": -1, "properties": {"boardSocket": 1, "cameraName": "", "fps": 60.0, "imageOrientation": -1, "initialControl": {"aeLockMode": false, "aeMaxExposureTimeUs": 100663297, "aeRegion": {"height": 0, "priority": 2288778576, "width": 0, "x": 4163, "y": 1}, "afRegion": {"height": 0, "priority": 0, "width": 0, "x": 23910, "y": 0}, "antiBandingMode": 107, "autoFocusMode": 3, "awbLockMode": false, "awbMode": 152, "brightness": 11, "captureIntent": 136, "chromaDenoise": 0, "cmdMask": 0, "contrast": 50, "controlMode": 102, "effectMode": 93, "enableHdr": false, "expCompensation": -34, "expManual": {"exposureTimeUs": 23910, "frameDurationUs": 23910, "sensitivityIso": 2288778684}, "frameSyncMode": 0, "lensPosAutoInfinity": 208, "lensPosAutoMacro": 253, "lensPosition": 0, "lensPositionRaw": 0.0, "lowPowerNumFramesBurst": 0, "lowPowerNumFramesDiscard": 0, "lumaDenoise": 0, "miscControls": [], "saturation": 104, "sceneMode": 253, "sharpness": 0, "strobeConfig": {"activeLevel": 248, "enable": 0, "gpioNumber": 3}, "strobeTimings": {"durationUs": 24, "exposureBeginOffsetUs": 23910, "exposureEndOffsetUs": 17}, "wbColorTemp": 0}, "isp3aFps": 0, "mockIspHeight": -1, "mockIspWidth": -1, "numFramesPoolIsp": 3, "numFramesPoolPreview": 4, "numFramesPoolRaw": 3, "numFramesPoolStill": 4, "numFramesPoolVideo": 4, "outputRequests": [{"enableUndistortion": null, "fps": {"value": null}, "resizeMode": 0, "size": {"value": {"index": 0, "value": [640, 400]}}, "type": null}], "resolutionHeight": -1, "resolutionWidth": -1}}]]}}
```

## Source code

#### Python

```python
import signal
import time
import depthai as dai
from rerun_node import RerunNode
# Create pipeline

with dai.Pipeline() as p:
    fps = 60
    width = 640
    height = 400
    # Define sources and outputs
    left = p.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B, sensorFps=fps)
    right = p.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C, sensorFps=fps)
    imu = p.create(dai.node.IMU)
    odom = p.create(dai.node.BasaltVIO)

    rerunViewer = p.create(RerunNode)
    imu.enableIMUSensor([dai.IMUSensor.ACCELEROMETER_RAW, dai.IMUSensor.GYROSCOPE_RAW], 200)
    imu.setBatchReportThreshold(1)
    imu.setMaxBatchReports(10)

    # Linking
    left.requestOutput((width, height)).link(odom.left)
    right.requestOutput((width, height)).link(odom.right)
    imu.out.link(odom.imu)
    odom.passthrough.link(rerunViewer.inputImg)
    odom.transform.link(rerunViewer.inputTrans)
    p.start()
    while p.isRunning():
        time.sleep(0.01)
```

#### C++

```cpp
#include "depthai/depthai.hpp"
#include "rerun_node.hpp"

int main() {
    using namespace std;

    // Create pipeline
    dai::Pipeline pipeline;
    int fps = 60;
    int width = 640;
    int height = 400;
    // Define sources and outputs
    auto left = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_B, std::nullopt, fps);
    auto right = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_C, std::nullopt, fps);
    auto imu = pipeline.create<dai::node::IMU>();
    auto odom = pipeline.create<dai::node::BasaltVIO>();

    auto rerun = pipeline.create<RerunNode>();
    imu->enableIMUSensor({dai::IMUSensor::ACCELEROMETER_RAW, dai::IMUSensor::GYROSCOPE_RAW}, 200);
    imu->setBatchReportThreshold(1);
    imu->setMaxBatchReports(10);

    // Linking
    left->requestOutput(std::make_pair(width, height))->link(odom->left);
    right->requestOutput(std::make_pair(width, height))->link(odom->right);
    imu->out.link(odom->imu);
    odom->transform.link(rerun->inputTrans);
    odom->passthrough.link(rerun->inputImg);

    pipeline.start();
    pipeline.wait();
}
```

### Need assistance?

Head over to [Discussion Forum](https://discuss.luxonis.com/) for technical support or any other questions you might have.
