SkillAgentSearch skills...

Cullinan

A Lidar based on Roborock LDS(Laser Distance Sensor) for STEM

Install / Use

/learn @Roborock-OpenSource/Cullinan
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Cullinan

Preface

Developing a LIDAR for STEM applications based on the Roborock Laser Distance Sensor (LDS)

Since the launch of the first Roborock robot vacuum, many college students and budding engineers from around the world have reached out to Roborock asking for more information about its LDS system. Some people even purchased Roborock robot vacuums and disassembled them to gain access to the LDS system because the price of the robot is significantly less than many other LIDAR systems on the market.

However, the LDS unit was not designed for use on its own making it is difficult to use. It has a limited IO, and it requires you to make your own PWM signal for motor speed control. This is why Roborock is now developing a STEM friendly version available at a low price, or potentially for free, to students and for research purposes.

If you have a comment you would like to offer about this system or have feature suggestions, feel free to get in touch.

image image

Features

  • 360-degree 2D laser scanner
  • 150mm~6000mm detection distance
  • 1.8kHz sampling rate
  • 3-axis gyroscope
  • 3-axis accelerometer
  • A Type-C integrated signal and power supply

image

Introduction

The Cullinan system is made up of two parts, an LDS range finder, and an IMU. The LDS system is able to scan and measure an environment in 360° to an accuracy of 6cm~15cm. It captures 360 samples each rotation, at a scanning frequency of 5Hz, corresponding to approximately a sample every 1°. As with other IMUs, the Cullinan IMU captures real-time motion data, such as acceleration and angular velocity. The IMU is able to interact with external applications through a USB port, providing an easy access point for customized implementations.

LDS distance measurement system

Specification

Parameter|Value|Unit ---------|-----|---- Distance Rang (D)|0.15~6|Meter (m) Angular Range (A)|0~360|Degree Angular Resolution (Ar)|1|Degree Sample Duration|0.5|Millisecond (ms) Sample Frequency|1800|Hz Scan Rate|5|Hz

LDS serial data

Serial communication format

LDS measurement system sends distance data through serial port. The serial format is set to 115200 baud rate, 8 data bits, 1 stop bit, no parity bit, no flow control.

Serial data format

There are two kinds of data from LDS. One is property information, the other is distance information. The property information is sent only before rotation, and the interval is 500 ms. When LDS starts to rotate, it stops to send property information and starts to send distance sample.

Property data format

Field Name|Size / byte|Description ----------|-----------|----------- LDS_INFO_START|1|synchronization character, fixed 0xAA. If the property packet contains synchronization character (0xAA), it must be escaped before sending. 0xAA is replaced by 0xA901, and 0xA9 is replaced by 0xA900. Note: 1. MSB is sent first in escape sequence. 2. When sending, calculate the checksum first, then perform the escaping operation; When receiving, perform the escaping operation first, then calculate the checksum. PACKET_SIZE|2|paceket size in byte except for LDS_INFO_START, set to 84 SOFTWARE_VERSION|2|firmware version, bit[15:12] = major versio, bit[11:0] = minor version. Example: 0x1001 is interpreted as V1.1 UID_SIZE|2|UID size, set to 18 UID|18|UID value RSVD|58|Reserved CHECK_SUM|2|packet checksum, see The checksum algorithm for property packet

The checksum algorithm for property packet
uint16_t checksum = 0;
 for(i = 0; i < size; i++){ // size is 41
  checksum += *(lds_info_data + i);  // lds_info_data is declared as uint16_t* pointer and points to property packet buffer.
 }

Measurement data format

Note: Measurement packet does not contain escape character.

Field Name|Size / byte|Description ----|----|---- Start|1|synchronization character, fixed 0xFA Index|1|sample index, from 0xA0 to 0xF9. There are 4 samples in a measurement packet, and 90 packets for one round. Speed|2|little endian, real speed value * 64, in rpm Data 0|4|sample data 0, see Sample data format Data 1|4|sample data 1, see Sample data format Data 2|4|sample data 2, see Sample data format Data 3|4|sample data 3, see Sample data format Checksum|2|packe checksum, see The checksum algorithm for measurement packet

Sample data format

Offset|Description ----|---- 0|distance[7:0] 1|bit7 = data invalid flag, bit6 = strength warning flag, bit[5:0] = distance[13:8] 2|strength[7:0] 3|strength[15:8]

The checksum algorithm for measurement packet
uint32_t i, checksum = 0;

for (i = 0; i < 20; i += 2)
{
    checksum = (checksum << 1) + *(uint16_t *)&lds_buf[i];
}
checksum = (checksum + (checksum >> 15)) & 0x7FFF;

Inertial measurement Unit (IMU)

Introduction

IMU is based on Bosch BMI160 6-axis MEMS sensor which integrates 16-bit 3-axis accelerometer with ultra-low-power 3-axis gyroscope. The BMI160 is available in a compact 14-pin 2.5 × 3.0 × 0.83 mm<sup>3</sup> LGA package. When accelerometer and gyroscope are in full operation mode, power consumption is typically 925 μA, enabling always-on applications in battery driven devices.

BMI160 API

Register operation API

BMI160_ReadReg

Prototype:int32_t BMI160_ReadReg(uint8_t RegAddr, uint8_t *RegData)
Description: Read a register
Parameter:RegAddr- register address
       RegData- register data pointer
Return:STATE_OK- state OK
    STATE_PENDING- state pending

BMI160_ReadRegSeq

Prototype:int32_t BMI160_ReadRegSeq(uint8_t RegAddr, uint8_t *RegData, uint8_t len)
Description: Read multiple registers
Parameter:RegAddr- register start addrss
       RegData- register data pointer
       len- the number of register to be read
Return:STATE_OK- state OK
    STATE_PENDING- state pending

BMI160_WriteReg

Prototype:int32_t BMI160_WriteReg(uint8_t RegAddr, uint8_t RegData)
Description: Write a register
Parameter:RegAddr- register address
       RegData- register data
Return:STATE_OK- state OK
    STATE_PENDING- state pending

BMI160_WriteRegSeq

Prototype:int32_t BMI160_WriteRegSeq(uint8_t RegAddr, uint8_t *RegData, uint8_t len)
Description: Write multiple registers
Parameter:RegAddr- register start addrss
       RegData- register data pointer
       len- the number of register to be written
Return:STATE_OK- state OK
    STATE_PENDING- state pending

BMI160 API

BMI160_SetAccelNormal

Prototype:int32_t BMI160_SetAccelNormal(void)
Description: Set accelerometer sensor in normal power mode
Parameter: None
Return:STATE_OK- state OK
    STATE_PENDING- state pending

BMI160_SetGyroNormal

Prototype:int32_t BMI160_SetGyroNormal(void)
Description: Set gyroscope sensor in normal power mode
Parameter: None
Return:STATE_OK- state OK
    STATE_PENDING- state pending

BMI160 API example

    /* Select the Output data rate, range of accelerometer sensor */
    BMI160_REG.ACC_CONF.acc_odr = BMI160_ACCEL_ODR_100HZ;
    BMI160_REG.ACC_CONF.acc_bwp = BMI160_ACCEL_BW_NORMAL_AVG4;
    BMI160_REG.ACC_CONF.acc_us = 0;
    BMI160_REG.ACC_RANGE.acc_range = BMI160_ACCEL_RANGE_2G;
    while (BMI160_WriteRegSeq(REG(ACC_CONF), (uint8_t *)&BMI160_REG.ACC_CONF, 2) == STATE_PENDING) ;
    while (BMI160_SetAccelNormal() == STATE_PENDING) ; // set normal power mode
    
    /* Select the Output data rate, range of Gyroscope sensor */
    BMI160_REG.GYR_CONF.gyr_odr = BMI160_GYRO_ODR_100HZ;
    BMI160_REG.GYR_CONF.gyr_bwp = BMI160_GYRO_BW_NORMAL_MODE;
    BMI160_REG.GYR_RANGE.gyr_range = BMI160_GYRO_RANGE_2000_DPS;
    while (BMI160_WriteRegSeq(REG(GYR_CONF), (uint8_t *)&BMI160_REG.GYR_CONF, 2) == STATE_PENDING) ;
    while (BMI160_SetGyroNormal() == STATE_PENDING) ; // set normal power mode

Inertial measurement interface

Serial communication format

Inertial measurement unit sends raw data to external application through an USB VCP. The serial format is not important.

Data format

Offset|Name|Size / byte|Description ------|----|-----------|---- 0|GYR_X[7:0]|1|Low byte of gyroscope x-axis data 1|GYR_X[15:8]|1|High byte of gyroscope x-axis data 2|GYR_Y[7:0]|1|Low byte of gyroscope y-axis data 3|GYR_Y[15:8]|1|High byte of gyroscope y-axis data 4|GYR_Z[7:0]|1|Low byte of gyroscope z-axis data 5|GYR_Z[15:8]|1|High byte of gyroscope z-axis data 6|ACC_X[7:0]|1|Low byte of accelerometer x-axis data 7|ACC_X[15:8]|1|High byte of accelerometer x-axis data 8|ACC_Y[7:0]|1|Low byte of accelerometer y-axis data 9|ACC_Y[15:8]|1|High byte of accelerometer y-axis data 10|ACC_Z[7:0]|1|Low byte of accelerometer z-axis data 11|ACC_Z[15:8]|1|High byte of accelerometer z-axis data 12|SENSORTIME[7:0]|1|Low byte of sensor time stamp 13|SENSORTIME[15:8]|1|Median byte of sensor time stamp 14|SENSORTIME[23:16]|1|High byte of

View on GitHub
GitHub Stars75
CategoryDevelopment
Updated13d ago
Forks8

Languages

C

Security Score

80/100

Audited on Mar 18, 2026

No findings