RVC Mode (Robot Vacuum Cleaner Mode)

RVC mode is a simplified UART streaming protocol that provides basic orientation and motion data without requiring the full SH-2 command interface. This mode is ideal for resource-constrained systems that only need yaw/pitch/roll and linear acceleration.

Why Use RVC Mode?

  • No Command Parsing: Sensor outputs data continuously once powered
  • Lower Overhead: Simplified protocol reduces processing requirements
  • Resource Efficient: Perfect for systems with limited CPU/memory
  • Simple Integration: Fixed frame format, no configuration needed

Frame Format

Each RVC frame is 19 bytes with the following structure:

Offset Bytes Description
0 2 Sync bytes 0xAA 0xAA
2 1 index sequence counter
3 2 yaw (little endian, 0.01°/LSB)
5 2 pitch (little endian, 0.01°/LSB)
7 2 roll (little endian, 0.01°/LSB)
9 2 acc_x (little endian, 0.001 g/LSB)
11 2 acc_y (little endian, 0.001 g/LSB)
13 2 acc_z (little endian, 0.001 g/LSB)
15 1 mi Motion Intent
16 1 mr Motion Request
17 1 Checksum of bytes 2-17

Checksum: Simple unsigned sum of bytes 2 through 17 modulo 256.

Motion Intent and Motion Request

The mi (Motion Intent) and mr (Motion Request) fields indicate sensor state:

Motion Intent Values

1
2
3
4
MI_UNKNOWN                      0
MI_STATIONARY_WITHOUT_VIBRATION 1
MI_STATIONARY_WITH_VIBRATION    2
MI_IN_MOTION                    3

Motion Request Values

1
2
3
4
5
MR_NO_CONSTRAINT                0
MR_STAY_STATIONARY_REQUIRED     1
MR_NON_URGENT_STAY_STATIONARY   3
MR_URGENT_STATIONARY            4
MR_TIMER_STATIONARY             5

Entering RVC Mode

RVC mode is selected at boot time via hardware pins:

  • PS0 = 1, PS1 = 0: UART RVC mode
  • Sensor must be reset after setting pins
  • Once in RVC mode, sensor continuously streams frames at 115200 bps (8N1)

Implementation

Step 1: Implement IRvcHal Interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "src/rvc/RvcHal.hpp"

class MyRvcHal : public IRvcHal {
public:
    bool open() override {
        // Initialize UART at 115200 bps, 8N1
        return true;
    }
    
    void close() override {
        // Close UART
    }
    
    int read(uint8_t* data, size_t length) override {
        // Read bytes from UART
        return uart_read_bytes(uart_port, data, length, 0);
    }
    
    uint32_t getTimeUs() override {
        // Return current time in microseconds
        return esp_timer_get_time();
    }
};

Step 2: Use BNO085 RVC Methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "bno08x.hpp"

MyComm comm;
bno08x::BNO085<MyComm> imu(comm);

MyRvcHal rvc_hal;

// Begin RVC mode
if (imu.BeginRvc(&rvc_hal)) {
    // Set callback for decoded frames
    imu.SetRvcCallback([](const rvc_SensorValue_t& val) {
        printf("Yaw: %.2f°, Pitch: %.2f°, Roll: %.2f°\n",
               val.yaw_deg, val.pitch_deg, val.roll_deg);
        printf("Accel: X=%.3f, Y=%.3f, Z=%.3f g\n",
               val.acc_x_g, val.acc_y_g, val.acc_z_g);
    });
    
    // Service loop
    while (true) {
        imu.ServiceRvc();  // Decode incoming frames
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    
    // Close when done
    imu.CloseRvc();
}

Step 3: Alternative - Use Rvc Class Directly

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "src/rvc/Rvc.hpp"

MyRvcHal hal;
Rvc rvc(hal);

rvc.setCallback([](const rvc_SensorValue_t& val) {
    printf("Yaw: %.2f°\n", val.yaw_deg);
});

if (rvc.open()) {
    while (true) {
        rvc.service();  // Decode frames
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    rvc.close();
}

Complete Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "bno08x.hpp"
#include "src/rvc/RvcHal.hpp"

class Esp32RvcHal : public IRvcHal {
private:
    uart_port_t uart_port_;
    
public:
    Esp32RvcHal(uart_port_t port) : uart_port_(port) {}
    
    bool open() override {
        uart_config_t config = {};
        config.baud_rate = 115200;
        config.data_bits = UART_DATA_8_BITS;
        config.parity = UART_PARITY_DISABLE;
        config.stop_bits = UART_STOP_BITS_1;
        config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
        
        uart_param_config(uart_port_, &config);
        uart_set_pin(uart_port_, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE,
                     UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
        uart_driver_install(uart_port_, 1024, 0, 0, NULL, 0);
        return true;
    }
    
    void close() override {
        uart_driver_delete(uart_port_);
    }
    
    int read(uint8_t* data, size_t length) override {
        int len = uart_read_bytes(uart_port_, data, length, pdMS_TO_TICKS(100));
        return (len > 0) ? len : 0;
    }
    
    uint32_t getTimeUs() override {
        return esp_timer_get_time();
    }
};

void app_main() {
    Esp32RvcHal hal(UART_NUM_1);
    Esp32Bno08xBus comm(/* config */);
    bno08x::BNO085<Esp32Bno08xBus> imu(comm);
    
    if (imu.BeginRvc(&hal)) {
        imu.SetRvcCallback([](const rvc_SensorValue_t& val) {
            printf("Yaw: %.2f°, Pitch: %.2f°, Roll: %.2f°\n",
                   val.yaw_deg, val.pitch_deg, val.roll_deg);
        });
        
        while (true) {
            imu.ServiceRvc();
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    }
}

UART Configuration

  • Baud Rate: 115200 bps (typical, check datasheet for your device)
  • Data Bits: 8
  • Parity: None
  • Stop Bits: 1
  • Flow Control: None

Data Units

  • Yaw/Pitch/Roll: Degrees (0.01° per LSB)
  • Acceleration: g (0.001 g per LSB)
  • Time: Microseconds

Limitations

  • Fixed Data: Only yaw/pitch/roll and linear acceleration
  • No Configuration: Cannot change report rates or enable other sensors
  • UART Only: Requires UART interface (not I²C or SPI)
  • Boot-Time Selection: Must be selected at boot via pins

When to Use RVC Mode

Use RVC Mode When:

  • You only need basic orientation data
  • System resources are limited
  • Simple integration is preferred
  • UART interface is available

Use Full SH-2 Mode When:

  • You need multiple sensor types
  • You need configurable report rates
  • You need gesture detection or step counting
  • You need I²C or SPI interface

Next Steps


Navigation ⬅️ Examples | Next: DFU ➡️ | Back to Index