{"id":15142506,"url":"https://github.com/ludovatech/lidar-ld19-tutorial","last_synced_at":"2026-01-19T08:01:51.855Z","repository":{"id":248435844,"uuid":"827955139","full_name":"LudovaTech/lidar-LD19-tutorial","owner":"LudovaTech","description":"Tutorial on lidar LD19 : How to retrieve data from this LiDAR sensor using a microcontroller","archived":false,"fork":false,"pushed_at":"2025-06-10T10:31:15.000Z","size":815,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-10T11:34:40.668Z","etag":null,"topics":["ld19","ld19-lidar","lidar","tutorial"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LudovaTech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-12T18:42:12.000Z","updated_at":"2025-06-10T10:31:19.000Z","dependencies_parsed_at":"2024-10-09T23:01:15.570Z","dependency_job_id":"75c0ee53-d026-47be-808c-7df04967cf4e","html_url":"https://github.com/LudovaTech/lidar-LD19-tutorial","commit_stats":{"total_commits":18,"total_committers":1,"mean_commits":18.0,"dds":0.0,"last_synced_commit":"8699e6af4d08a213c1bc7abb22f4cd50787420b5"},"previous_names":["ludovatech/lidar-ld19-tutorial"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LudovaTech/lidar-LD19-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LudovaTech%2Flidar-LD19-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LudovaTech%2Flidar-LD19-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LudovaTech%2Flidar-LD19-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LudovaTech%2Flidar-LD19-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LudovaTech","download_url":"https://codeload.github.com/LudovaTech/lidar-LD19-tutorial/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LudovaTech%2Flidar-LD19-tutorial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28563217,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T03:31:16.861Z","status":"ssl_error","status_checked_at":"2026-01-19T03:31:15.069Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ld19","ld19-lidar","lidar","tutorial"],"created_at":"2024-09-26T09:41:56.174Z","updated_at":"2026-01-19T08:01:51.848Z","avatar_url":"https://github.com/LudovaTech.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tutorial on LiDAR LD19\n\n[version en français](./README.fr.md)\n\nLD19 is a low cost LiDAR that we (LudovaTech team) used for the Robocup Junior competition. We find out that it works very well for our requirements but that there was no proper documentation or tutorial on the web. We succeeded to make it work after long days of work. Here is how we did it!\n\n\u003e [!TIP]\n\u003e This tutorial aims to guide you in retrieving LiDAR data from a microcontroller in a format that enables immediate processing onboard. If you just need to check that your LiDAR is working, [these documents](#links) provide instructions on using their software to view the data on your computer.\n\n\u003e [!NOTE]\n\u003e This is not an official documentation.\n\u003e\n\u003e All this documentation and code are licensed under CC BY-SA 4.0, with the exception of images and other files.\n\nIf you notice something missing or have any ideas, please feel free to open a [GitHub issue](https://github.com/LudovaTech/lidar-LD19-tutorial/issues/new).\n\n## Overview\n\n![LiDAR LD19](./images/lidar-LD19.jpg)\n\nThe LD19 LiDAR uses Direct Time-of-Flight (DTOF) technology, which measures the time interval between emitting and receiving a signal. According to the manufacturer’s documentation, the LD19 can perform up to 5,000 measurements per second.\n\n\u003e [!NOTE]\n\u003e In our application, we observed that one complete rotation of the LiDAR takes approximately 130 milliseconds, resulting in around 600 measurement points per loop.\n\n## Communication interface\n\nYou can use a `JST ZH 4-pin` connector to link the LiDAR to other components, enabling both power supply and data reception. The interface details are outlined in the table below:\n\nFrom left to right, holding the LiDAR with the circular part facing upwards.\n\n| Name and Type |  Voltage  |   Comments   |\n| :------------ | :-------: | :----------- |\n| **Tx** (output UART), LiDAR data output at `230400` baud rate | 0V - 3.5V \u003c/br\u003e typical: 3.3V | This LiDAR only sends data and does not receive any, hence the absence of an Rx port. |\n| **PWM** (input), controls the speed of the built-in motor. Current LiDAR speed is indicated in the data sent | 0V - 3.3V | If manual control of the LiDAR speed is not required, the designated pin can be set to ground (GND) upon initiation of the LiDAR device and maintained in this state throughout its operation. (More informations on *manual* speed control in the [real documentation](#links))|\n| **Ground** (power supply) | 0V | - |\n| **5V** (power supply) | 4.5V - 5.5V \u003c/br\u003e typical: 5V | - |\n\nThe LD19 uses UART protocol for data communication with the following settings:\n\n- **Baud Rate:** 230400\n- **Data Length:** 8 bits\n- **Stop Bit:** 1\n- **Parity:** None\n- **Flow Control:** None\n\n\u003e [!TIP]\n\u003e For Arduino users, simply set the baud rate to `230400`. The other parameters are set to the correct values by default.\n\n\u003e [!IMPORTANT]\n\u003e The LD19 LiDAR starts transmitting measurement data as soon as its rotation stabilizes, which typically takes two to three seconds. There is no need to send any commands to initiate this process. In fact, you cannot send any commands to do so.\n\n## Data protocol\n\n### Data packet format\n\nThe LD19 uses one-way communication. Once it is operating stably, it begins to send measurement data packets automatically, without requiring any commands. There is 12 points per packet. The format of these measurement packets is illustrated in the table below.\n\n|  Name  | Length | Type or Value | Description |\n| :----: | :----: | :-----------: | :---------- |\n| Header | 1 Byte | Always `0x54` | Indicating the start of the data packet |\n| VerLen | 1 Byte | Always `0x2C` | The upper three bits of the byte specify the packet type, which is currently set to 1. The lower five bits represent the number of measurement points in a packet, which is fixed at 12. |\n| Speed  | 2 Bytes | [least significant bit][LSB] before, \u003c/br\u003e *unit: degrees per second* | Indicate the speed of the LiDAR |\n| Start Angle | 2 Bytes | [least significant bit][LSB] before, \u003c/br\u003e *unit: 0.01 degrees* | Indicate the starting angle of the data packet point |\n| **Data** | 3 * 12 Bytes | ... | Please refer to the [next section](#understanding-data-packet) for further details. |\n| End angle | 2 Bytes | [least significant bit][LSB] before, \u003c/br\u003e *unit: 0.01 degrees* | Indicate the end angle of the data packet point |\n| Timestamp | 2 Bytes | [least significant bit][LSB] before, \u003c/br\u003e *unit: milliseconds*, \u003c/br\u003e Reset to zero upon reaching `30000` | Indicating the timestamp value of the data packet |\n| CRC check | 1 Bytes | Verification of all previous data *except itself* | Verifies data transfer for accuracy and completeness, ensuring error-free results. |\n\n\u003e [!IMPORTANT]\n\u003e We receive initial and final angles for every set of 12 points. The documentation advises using linear interpolation to determine the angles for each individual point. For detailed implementation steps, refer to the [Implementation section](#implementation). (Do not worry, it is very simple.)\n\n### Understanding data packet\n\nEach of the 12 mesurement points per packet is composed of 2 values :\n\n|   Name   | Length  | Type or Value | Description |\n| :------: | :-----: | :-----------: | :---------- |\n| Distance | 2 Bytes | [least significant bit][LSB] before, \u003c/br\u003e *unit: mm* | The distance to the detected point |\n| Intensity | 1 Byte | reflects the light reflection intensity | Light intensity is positively correlated to the signal's intensity value. For a white object within 6 meters, the typical signal strength value is approximately 200. |\n\n\u003e [!NOTE]\n\u003e The LD19 employs a left-handed coordinate system with the rotation center at the origin. The front of the sensor is designated as the zero-degree direction, and the rotation angle increases clockwise, as illustrated in the figure below. \u003c/br\u003e\n\u003e ![Lidar Coordinate System](./images/lidar-coordinate-system.jpg)\n\n## Implementation\n\n### Linear Interpolation\n\nLinear interpolation is in this case a method of estimating values that lie between two known values. Here, it assumes that all points are at the same distance from each other.\nAll you need to do is:\n\n- Calculate the distance `angleStep` between each point: `(endAngle - startAngle) / nbr_points`. `nbr_points` is always equal to 12 with this LiDAR.\n- Calculate the angle for point `n` : `startAngle + (angleStep * n)`\n- The calculations are actually slightly more complex than indicated in the documentation, particularly to handle the transition from 359° to 0°.\n\nHere is our C++ implementation, which includes the 359° - 0° transition :\n\n```c++\n// Calculates the step size between startAngle and endAngle (in tenths of a degree),\n// divided by lenMinusOne, which represents the number of steps minus one.\n// Assumes angles are within 0 to 3599 (representing 0.0° to 359.9°).\nuint16_t angleStep(uint16_t startAngle, uint16_t endAngle, unsigned int lenMinusOne) {\n  if (startAngle \u003c= endAngle) {\n    return (endAngle - startAngle) / lenMinusOne;\n  } else {\n    return (36000 + endAngle - startAngle) / lenMinusOne;\n  }\n}\n\n// Calculates the angle (in tenths of a degree) corresponding to a given step index,\n// starting from startAngle, with each step being step tenths of a degree.\n// Returns the angle wrapped within 0 to 3599 (representing 0.0° to 359.9°).\nuint16_t angleFromStep(uint16_t startAngle, uint16_t step, unsigned int indice) {\n  return (startAngle + (step * indice)) % 36000;\n}\n```\n\n### Read a 2-Bytes value with least significant bit before\n\nHere's how to interpret a 2-byte value (LSB/MSB) using an array called `buffer` that holds the bytes, with `index` indicating the position of the least significant bit (LSB, the first one).\n\n```c++\nuint16_t _get2BytesLsbMsb(byte buffer[], int index) {\n  return (buffer[index + 1] \u003c\u003c 8) | buffer[index];\n}\n```\n\n### Implementing CRC check\n\nHere is how to implement the CRC check to check data validity :\n`p` is an array containing bytes retrieved from the lidar.\n`lenWithoutCRCCheckValue` represents the total length of data sent by the LiDAR excluding the CRC check. For this lidar, it equals 44 bytes.\n\n```c++\nstatic const uint8_t crcTable[256] = {\n    0x00, 0x4d, 0x9a, 0xd7, 0x79, 0x34, 0xe3,\n    0xae, 0xf2, 0xbf, 0x68, 0x25, 0x8b, 0xc6, 0x11, 0x5c, 0xa9, 0xe4, 0x33,\n    0x7e, 0xd0, 0x9d, 0x4a, 0x07, 0x5b, 0x16, 0xc1, 0x8c, 0x22, 0x6f, 0xb8,\n    0xf5, 0x1f, 0x52, 0x85, 0xc8, 0x66, 0x2b, 0xfc, 0xb1, 0xed, 0xa0, 0x77,\n    0x3a, 0x94, 0xd9, 0x0e, 0x43, 0xb6, 0xfb, 0x2c, 0x61, 0xcf, 0x82, 0x55,\n    0x18, 0x44, 0x09, 0xde, 0x93, 0x3d, 0x70, 0xa7, 0xea, 0x3e, 0x73, 0xa4,\n    0xe9, 0x47, 0x0a, 0xdd, 0x90, 0xcc, 0x81, 0x56, 0x1b, 0xb5, 0xf8, 0x2f,\n    0x62, 0x97, 0xda, 0x0d, 0x40, 0xee, 0xa3, 0x74, 0x39, 0x65, 0x28, 0xff,\n    0xb2, 0x1c, 0x51, 0x86, 0xcb, 0x21, 0x6c, 0xbb, 0xf6, 0x58, 0x15, 0xc2,\n    0x8f, 0xd3, 0x9e, 0x49, 0x04, 0xaa, 0xe7, 0x30, 0x7d, 0x88, 0xc5, 0x12,\n    0x5f, 0xf1, 0xbc, 0x6b, 0x26, 0x7a, 0x37, 0xe0, 0xad, 0x03, 0x4e, 0x99,\n    0xd4, 0x7c, 0x31, 0xe6, 0xab, 0x05, 0x48, 0x9f, 0xd2, 0x8e, 0xc3, 0x14,\n    0x59, 0xf7, 0xba, 0x6d, 0x20, 0xd5, 0x98, 0x4f, 0x02, 0xac, 0xe1, 0x36,\n    0x7b, 0x27, 0x6a, 0xbd, 0xf0, 0x5e, 0x13, 0xc4, 0x89, 0x63, 0x2e, 0xf9,\n    0xb4, 0x1a, 0x57, 0x80, 0xcd, 0x91, 0xdc, 0x0b, 0x46, 0xe8, 0xa5, 0x72,\n    0x3f, 0xca, 0x87, 0x50, 0x1d, 0xb3, 0xfe, 0x29, 0x64, 0x38, 0x75, 0xa2,\n    0xef, 0x41, 0x0c, 0xdb, 0x96, 0x42, 0x0f, 0xd8, 0x95, 0x3b, 0x76, 0xa1,\n    0xec, 0xb0, 0xfd, 0x2a, 0x67, 0xc9, 0x84, 0x53, 0x1e, 0xeb, 0xa6, 0x71,\n    0x3c, 0x92, 0xdf, 0x08, 0x45, 0x19, 0x54, 0x83, 0xce, 0x60, 0x2d, 0xfa,\n    0xb7, 0x5d, 0x10, 0xc7, 0x8a, 0x24, 0x69, 0xbe, 0xf3, 0xaf, 0xe2, 0x35,\n    0x78, 0xd6, 0x9b, 0x4c, 0x01, 0xf4, 0xb9, 0x6e, 0x23, 0x8d, 0xc0, 0x17,\n    0x5a, 0x06, 0x4b, 0x9c, 0xd1, 0x7f, 0x32, 0xe5, 0xa8};\n\nuint8_t _calCRC8FromBuffer(uint8_t* p, uint8_t lenWithoutCRCCheckValue) {\n  uint8_t crc = 0xD8;                                       // pre-calculated header and verlen values (crc = crcTable[(crc ^ 0x54) \u0026 0xff];crc = crcTable[(crc ^ 0x2C) \u0026 0xff];)\n  for (uint16_t i = 0; i \u003c lenWithoutCRCCheckValue; i++) {  // ignores the last value of the p array (which contains the crc check value)\n    crc = crcTable[(crc ^ *p++) \u0026 0xff];\n  }\n  return crc;\n}\n```\n\nTo determine if the values are valid, just compare the output of this function with the data received from the lidar.\n\n\u003e [!CAUTION]\n\u003e In some LD19 LiDAR documentation documents, the crcTable is incomplete, resulting in its malfunctioning. This version includes all required lines of code.\n\n### The complete C++ implementation for understanding data received from the lidar\n\n`lidar_reader.h`\n\n```c++\n#ifndef LIDAR_H\n#define LIDAR_H\n\n#include \u003cArduino.h\u003e\n\nclass LidarPoint {\n public:\n  LidarPoint(uint16_t distance, uint8_t intensity, float angle);\n\n  LidarPoint \u0026operator=(const LidarPoint \u0026) = delete;\n\n  inline uint16_t distance() const { return _distance; }  // distance from the center of the lidar\n  inline uint8_t intensity() const { return _intensity; }\n  inline float angle() const { return _angle; }\n\n  String toString() const;\n\n private:\n  const uint16_t _distance;\n  const uint8_t _intensity;\n  const float _angle;\n};\n\nstatic const uint8_t crcTable[256] = {\n    0x00, 0x4d, 0x9a, 0xd7, 0x79, 0x34, 0xe3,\n    0xae, 0xf2, 0xbf, 0x68, 0x25, 0x8b, 0xc6, 0x11, 0x5c, 0xa9, 0xe4, 0x33,\n    0x7e, 0xd0, 0x9d, 0x4a, 0x07, 0x5b, 0x16, 0xc1, 0x8c, 0x22, 0x6f, 0xb8,\n    0xf5, 0x1f, 0x52, 0x85, 0xc8, 0x66, 0x2b, 0xfc, 0xb1, 0xed, 0xa0, 0x77,\n    0x3a, 0x94, 0xd9, 0x0e, 0x43, 0xb6, 0xfb, 0x2c, 0x61, 0xcf, 0x82, 0x55,\n    0x18, 0x44, 0x09, 0xde, 0x93, 0x3d, 0x70, 0xa7, 0xea, 0x3e, 0x73, 0xa4,\n    0xe9, 0x47, 0x0a, 0xdd, 0x90, 0xcc, 0x81, 0x56, 0x1b, 0xb5, 0xf8, 0x2f,\n    0x62, 0x97, 0xda, 0x0d, 0x40, 0xee, 0xa3, 0x74, 0x39, 0x65, 0x28, 0xff,\n    0xb2, 0x1c, 0x51, 0x86, 0xcb, 0x21, 0x6c, 0xbb, 0xf6, 0x58, 0x15, 0xc2,\n    0x8f, 0xd3, 0x9e, 0x49, 0x04, 0xaa, 0xe7, 0x30, 0x7d, 0x88, 0xc5, 0x12,\n    0x5f, 0xf1, 0xbc, 0x6b, 0x26, 0x7a, 0x37, 0xe0, 0xad, 0x03, 0x4e, 0x99,\n    0xd4, 0x7c, 0x31, 0xe6, 0xab, 0x05, 0x48, 0x9f, 0xd2, 0x8e, 0xc3, 0x14,\n    0x59, 0xf7, 0xba, 0x6d, 0x20, 0xd5, 0x98, 0x4f, 0x02, 0xac, 0xe1, 0x36,\n    0x7b, 0x27, 0x6a, 0xbd, 0xf0, 0x5e, 0x13, 0xc4, 0x89, 0x63, 0x2e, 0xf9,\n    0xb4, 0x1a, 0x57, 0x80, 0xcd, 0x91, 0xdc, 0x0b, 0x46, 0xe8, 0xa5, 0x72,\n    0x3f, 0xca, 0x87, 0x50, 0x1d, 0xb3, 0xfe, 0x29, 0x64, 0x38, 0x75, 0xa2,\n    0xef, 0x41, 0x0c, 0xdb, 0x96, 0x42, 0x0f, 0xd8, 0x95, 0x3b, 0x76, 0xa1,\n    0xec, 0xb0, 0xfd, 0x2a, 0x67, 0xc9, 0x84, 0x53, 0x1e, 0xeb, 0xa6, 0x71,\n    0x3c, 0x92, 0xdf, 0x08, 0x45, 0x19, 0x54, 0x83, 0xce, 0x60, 0x2d, 0xfa,\n    0xb7, 0x5d, 0x10, 0xc7, 0x8a, 0x24, 0x69, 0xbe, 0xf3, 0xaf, 0xe2, 0x35,\n    0x78, 0xd6, 0x9b, 0x4c, 0x01, 0xf4, 0xb9, 0x6e, 0x23, 0x8d, 0xc0, 0x17,\n    0x5a, 0x06, 0x4b, 0x9c, 0xd1, 0x7f, 0x32, 0xe5, 0xa8};\n\nstd::vector\u003cLidarPoint\u003e getPoints();\n\nuint8_t _calCRC8FromBuffer(uint8_t *p, uint8_t lenWithoutCRCCheckValue);\nuint16_t _get2BytesLsbMsb(byte buffer[], int index);\n\nuint16_t angleStep(uint16_t startAngle, uint16_t endAngle, unsigned int lenMinusOne = 11);\nuint16_t angleFromStep(uint16_t startAngle, uint16_t step, unsigned int indice);\n\n#endif\n```\n\n`lidar_reader.cpp`\n\n```c++\n#include \"lidar_reader.hpp\"\n\n//////LIDARPOINT\n\nLidarPoint::LidarPoint(uint16_t distance, uint8_t intensity, float angle)\n    : _distance(distance), _intensity(intensity), _angle(angle) {}\n\nString LidarPoint::toString() const {\n  String result = \"(distance=\";\n  result += String(_distance);\n  result += \", intensity=\";\n  result += String(_intensity);\n  result += \", angle=\";\n  result += String(_angle);\n  result += \")\";\n  return result;\n}\n\n//////FUNCTIONS\n\nstd::vector\u003cLidarPoint\u003e getPoints() {\n  std::vector\u003cLidarPoint\u003e points;\n  if (!SerialLidar.find(\"T,\")) {  // equivalent en char de 84 44 (decimal)\n    Serial.println(\"lidar_reader.getPoints : error, no header-verlen found in RX for the LiDAR LD19\");\n  } else {\n    // The previous instruction (find) jumped to the beginning of the information\n    // Now the stream is aligned\n    byte buffer[45];\n    size_t nbrBytesReceived = SerialLidar.readBytes(buffer, 45);\n    if (nbrBytesReceived != 45) {\n      Serial.println(\"lidar_reader.getPoints : error, wrong number of bytes received (\" + String((uint32_t) nbrBytesReceived) + \")\");\n    } else {\n      uint16_t speed = _get2BytesLsbMsb(buffer, 0);\n      uint16_t startAngle = _get2BytesLsbMsb(buffer, 2);\n\n      LidarPoint data[] = {// no for loop possible due to 'const' in LidarPoint class\n                            LidarPoint(_get2BytesLsbMsb(buffer, 4), buffer[6], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 7), buffer[9], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 10), buffer[12], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 13), buffer[15], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 16), buffer[18], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 19), buffer[21], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 22), buffer[24], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 25), buffer[27], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 28), buffer[30], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 31), buffer[33], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 34), buffer[36], 0),\n                            LidarPoint(_get2BytesLsbMsb(buffer, 37), buffer[39], 0)};\n\n      uint16_t endAngle = _get2BytesLsbMsb(buffer, 40);\n      uint16_t timestamp = _get2BytesLsbMsb(buffer, 42);\n      uint8_t crcCheck = buffer[44];\n\n      if (_calCRC8FromBuffer(buffer, 44) == crcCheck) {\n        uint16_t step = angleStep(startAngle, endAngle);\n        for (unsigned int i = 0; i \u003c 12; i++) {\n          points.push_back(\n              LidarPoint(\n                  data[i].distance(),\n                  data[i].intensity(),\n                  angleFromStep(startAngle, step, i)));\n        }\n      }\n    }\n  }\n  return points;\n}\n\nuint8_t _calCRC8FromBuffer(uint8_t* p, uint8_t lenWithoutCRCCheckValue) {\n  uint8_t crc = 0xD8;                                       // pre-calculated header and verlen values (crc = crcTable[(crc ^ 0x54) \u0026 0xff];crc = crcTable[(crc ^ 0x2C) \u0026 0xff];)\n  for (uint16_t i = 0; i \u003c lenWithoutCRCCheckValue; i++) {  // ignores the last value of the p array (which contains the crc check value)\n    crc = crcTable[(crc ^ *p++) \u0026 0xff];\n  }\n  return crc;\n}\n\nuint16_t _get2BytesLsbMsb(byte buffer[], int index) {\n  return (buffer[index + 1] \u003c\u003c 8) | buffer[index];\n}\n\nuint16_t angleStep(uint16_t startAngle, uint16_t endAngle, unsigned int lenMinusOne) {\n  if (startAngle \u003c= endAngle) {\n    return (endAngle - startAngle) / lenMinusOne;\n  } else {\n    return (36000 + endAngle - startAngle) / lenMinusOne;\n  }\n}\n\nuint16_t angleFromStep(uint16_t startAngle, uint16_t step, unsigned int indice) {\n  return (startAngle + (step * indice)) % 36000;\n}\n```\n\nTo use the LD19 LiDAR with your board and this code, simply define `SerialLidar` (with `#define`) as the appropriate Serial object for your board. Then, call the `getPoints` function to receive a `std::vector` containing all detected points from the lidar.\n\nYou can find all our source code available at [this location](https://github.com/LudovaTech/robot-prog-public).\n\n## Links\n\n- [What seems to be the official documentation](https://wiki.youyeetoo.com/en/Lidar/D300) ***Contains errors***\n- [A better documentation.](https://www.elecrow.com/download/product/SLD06360F/LD19_Development%20Manual_V2.3.pdf) ([local version](./documents/LD19_Development_Manual_v2.5.pdf) if the website removes the document)\n\n\u003cp xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dct=\"http://purl.org/dc/terms/\"\u003e\u003ca property=\"dct:title\" rel=\"cc:attributionURL\" href=\"https://github.com/LudovaTech/lidar-LD19-tutorial\"\u003elidar-LD19-tutorial\u003c/a\u003e (only the text and code of this document, not the images or the other files) by \u003ca rel=\"cc:attributionURL dct:creator\" property=\"cc:attributionName\" href=\"https://github.com/LudovaTech\"\u003eLudovaTech (D'Artagnant)\u003c/a\u003e is licensed under \u003ca href=\"https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1\" target=\"_blank\" rel=\"license noopener noreferrer\" style=\"display:inline-block;\"\u003eCC BY-SA 4.0\u003cimg style=\"height:22px!important;margin-left:3px;vertical-align:text-bottom;\" src=\"https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1\" alt=\"\"\u003e\u003cimg style=\"height:22px!important;margin-left:3px;vertical-align:text-bottom;\" src=\"https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1\" alt=\"\"\u003e\u003cimg style=\"height:22px!important;margin-left:3px;vertical-align:text-bottom;\" src=\"https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1\" alt=\"\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n[LSB]: https://en.wikipedia.org/wiki/Bit_numbering\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fludovatech%2Flidar-ld19-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fludovatech%2Flidar-ld19-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fludovatech%2Flidar-ld19-tutorial/lists"}