<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[ERDILRF Engineering Notes]]></title><description><![CDATA[ERDI TECH LTD technical notes on laser rangefinder integration, model documentation and UART software. Articles identify their source and version, separate gene]]></description><link>https://erdilrf.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ac739ab2a55ec4019b03c72/4ae6a785-167c-47de-a503-de6375fee0c2.png</url><title>ERDILRF Engineering Notes</title><link>https://erdilrf.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 23 Oct 2026 10:32:25 GMT</lastBuildDate><atom:link href="https://erdilrf.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Before connecting UART, keep three separate records]]></title><description><![CDATA[Keep supply, TX/RX limits and protocol settings separate. A model-specific worksheet based on ErdiLRF 0.1.1, with documented source gaps.]]></description><link>https://erdilrf.hashnode.dev/before-connecting-uart-keep-three-separate-records</link><guid isPermaLink="true">https://erdilrf.hashnode.dev/before-connecting-uart-keep-three-separate-records</guid><category><![CDATA[arduino]]></category><category><![CDATA[embedded systems]]></category><dc:creator><![CDATA[Tommy Yu]]></dc:creator><pubDate>Sat, 17 Oct 2026 14:18:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ac739ab2a55ec4019b03c72/b08d5d60-b8ea-4832-b618-b9a25a863e62.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A supply rating belongs in the power section of an integration note. It does not tell you what can be connected to TX/RX, or how received bytes should become a distance.</p>
<p>We are the ERDILRF technical resource team at ERDI TECH LTD. This note uses the published ErdiLRF 0.1.1 source and its documented limits to organize the information needed before wiring a module.</p>
<p>The library accepts an Arduino <code>Stream</code>. That describes its software transport; the host's UART capabilities and the delivered module interface still need checking. Start a connection record with the exact model, delivered configuration and controlled manual revision. Then keep the following entries separate.</p>
<table>
<thead>
<tr>
<th>Record</th>
<th>Information to confirm</th>
<th>Evidence to keep</th>
</tr>
</thead>
<tbody><tr>
<td>Supply</td>
<td>Operating supply and power pinout</td>
<td>The delivered model's power specification and connector drawing</td>
</tr>
<tr>
<td>Logic level</td>
<td>Delivered signal interface and TX/RX limits</td>
<td>The matching electrical-interface specification</td>
</tr>
<tr>
<td>Protocol</td>
<td>Baud, frame rules, commands and distance unit</td>
<td>The controlled protocol manual and driver version</td>
</tr>
</tbody></table>
<h2>Supply</h2>
<p>Identify the power pins from the correct connector drawing and record the documented operating supply. A supply value is not a TX/RX logic-level specification. Keep the pinout reference alongside it, so the voltage and the connector drawing refer to the same delivered configuration.</p>
<p>This worksheet deliberately supplies no voltage value. The available source says to confirm the selected configuration; it does not establish one electrical specification for every library model.</p>
<h2>Logic level</h2>
<p>Write down the delivered signal interface and the documented limits for its transmit and receive pins. Do the same for the host interface. If an adapter is part of the intended connection, record its interface and limits too. That is a documentation check to complete for the proposed connection, not evidence that an adapter has been tested here.</p>
<p>The library's model list cannot fill these fields for you. Its installation guide explicitly separates software model entries from supply voltage, TX/RX logic levels, connector pinout and available interface. Leave an unresolved field marked as unresolved until the matching documentation supplies it.</p>
<h2>Protocol</h2>
<p>Record the selected model, baud and frame rules before choosing commands or interpreting a distance field. The published README warns that a shared frame header does not establish common units, baud, checksum interpretation or electrical details.</p>
<p>Keep the driver version in this record. A repository's current branch and a published package can be different artifacts. Also check that the host serial implementation supports the documented configuration; accepting a <code>Stream</code> object is not a test of that host.</p>
<p>The known source gaps belong in the record as well. ErdiLRF 0.1.1 retains an LRF50VB command-table/checksum discrepancy, while <code>SPD1200D03</code> has conflicting baud statements and undocumented distance scaling. A successful compile does not resolve those questions.</p>
<p>The result is a connection note whose fields have specific sources. When you later record a physical test, retain that configuration, the driver version, raw receive bytes and returned status with the result. This worksheet itself records no powered connection or hardware test.</p>
<p>The <a href="https://downloads.arduino.cc/libraries/github.com/yu911517778-a11y/ErdiLRF-0.1.1.zip">published 0.1.1 source archive</a> includes the library and its MIT license. The <a href="https://erdilrf.gitbook.io/erdilrf-docs/installation-and-model-specific-units">ERDILRF software reference</a> explains the installation scope and links to status handling and known limits.</p>
]]></content:encoded></item><item><title><![CDATA[Test a UART rangefinder parser before connecting hardware]]></title><description><![CDATA[Test ErdiLRF 0.1.1 with a synthetic Stream to check model-specific units and checksum rejection before connecting rangefinder hardware.]]></description><link>https://erdilrf.hashnode.dev/test-uart-rangefinder-parser-synthetic-stream</link><guid isPermaLink="true">https://erdilrf.hashnode.dev/test-uart-rangefinder-parser-synthetic-stream</guid><category><![CDATA[arduino]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Tommy Yu]]></dc:creator><pubDate>Thu, 15 Oct 2026 17:08:29 GMT</pubDate><content:encoded><![CDATA[<p>A frame can pass its checksum and still turn into a distance that is wrong by a factor of ten. The missing piece is often the exact model's unit, rather than the serial transport.</p>
<p>We feed the same synthetic bytes into two model definitions in the published <strong>ErdiLRF 0.1.1 Arduino library</strong>, then corrupt the checksum to check that invalid input does not become a measurement. No sensor, target or module UART is needed.</p>
<p><strong>Disclosure:</strong> We are the ERDILRF team at ERDI TECH LTD, the manufacturer associated with the library. The examples use generated bytes. They are software checks, not physical range, accuracy or compatibility tests.</p>
<h2>What the check covers</h2>
<p>The library accepts an Arduino <code>Stream</code>. A small in-memory stream can therefore supply input bytes without connecting a rangefinder. Writes from the driver are consumed by the test helper and do not reach a module.</p>
<p>We use the library's <code>ERDI_LRF50H</code> and <code>ERDI_LRF50VB</code> definitions. In version 0.1.1, their distance conversion divides the raw count by 100 and 1,000 respectively. This is a comparison of the published software definitions; use the delivered unit's controlled manual to confirm a real integration.</p>
<p>The chosen input is <code>5C 02 11 EC</code>. The two distance bytes represent the synthetic raw count 4,354. The helper <code>erdiCheckSumB()</code> produces <code>EC</code> from <code>02 11</code>. Changing that last byte leaves the input without a valid frame.</p>
<h2>Install the published library</h2>
<p>In Arduino IDE, open Library Manager, search for <strong>ErdiLRF</strong>, and select <strong>0.1.1</strong>. The same version is listed in the <a href="https://downloads.arduino.cc/libraries/library_index.json.gz">Arduino library index</a> and <a href="https://registry.platformio.org/libraries/erdi-tech/ErdiLRF">PlatformIO Registry</a>.</p>
<p>For Arduino CLI:</p>
<pre><code class="language-sh">arduino-cli lib update-index
arduino-cli lib install "ErdiLRF@0.1.1"
</code></pre>
<p>The version number matters: these checks describe 0.1.1. A later library release may change its implementation or documented limits.</p>
<h2>Add an in-memory input stream</h2>
<p>Create a sketch named <code>SyntheticUARTChecks</code>. Add a tab/file named <code>SyntheticFrame.h</code> with the following code:</p>
<pre><code class="language-cpp">#ifndef ERDI_SYNTHETIC_FRAME_H
#define ERDI_SYNTHETIC_FRAME_H

#include &lt;ErdiLRF.h&gt;

// MIT. Synthetic test helper; no module UART is opened.
class SyntheticStream : public Stream {
 public:
  SyntheticStream(const uint8_t *data, size_t size)
      : data_(data), size_(size), position_(0) {}

  int available() override { return (int)(size_ - position_); }
  int read() override {
    return position_ &lt; size_ ? data_[position_++] : -1;
  }
  int peek() override {
    return position_ &lt; size_ ? data_[position_] : -1;
  }
  void flush() override {}
  size_t write(uint8_t) override { return 1; }

 private:
  const uint8_t *data_;
  size_t size_;
  size_t position_;
};

inline ErdiStatus decodeSynthetic(ErdiModel model, const uint8_t frame[4],
                                ErdiMeasurement *measurement) {
  SyntheticStream stream(frame, 4);
  ErdiLRF driver(stream, model);
  driver.setTimeout(10);
  return driver.measure(measurement);
}

#endif
</code></pre>
<p>The helper implements only a finite input buffer and an output sink. Its timeout keeps a corrupt or incomplete input from waiting indefinitely. It does not simulate electrical levels, UART timing or a real device's response to commands.</p>
<h2>Run the three cases</h2>
<p>Put this in <code>SyntheticUARTChecks.ino</code>:</p>
<pre><code class="language-cpp">#include "SyntheticFrame.h"

void showSynthetic(const char *label, ErdiModel model, const uint8_t frame[4]) {
  ErdiMeasurement measurement;
  ErdiStatus status = decodeSynthetic(model, frame, &amp;measurement);
  Serial.print(label);
  Serial.print(" status=");
  Serial.print((int)status);
  if (status == ERDI_OK &amp;&amp; measurement.valid) {
    Serial.print(" raw=");
    Serial.print(measurement.raw);
    Serial.print(" metres=");
    Serial.print(measurement.metres, 3);
  }
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("SYNTHETIC INPUT - no sensor measurement");

  uint8_t frame[4] = {0x5C, 0x02, 0x11, 0x00};
  frame[3] = erdiCheckSumB(&amp;frame[1], 2);
  showSynthetic("LRF50H", ERDI_LRF50H, frame);
  showSynthetic("LRF50VB", ERDI_LRF50VB, frame);

  frame[3] ^= 0x01;
  showSynthetic("CORRUPT", ERDI_LRF50H, frame);
}

void loop() {}
</code></pre>
<p>The sketch uses <code>Serial</code> only for its console output at 115200. That is the console setting, not a statement about either sensor's delivered UART setting. Keep rangefinder hardware disconnected for this test.</p>
<p>To compile for an Arduino Uno with its AVR core installed:</p>
<pre><code class="language-sh">arduino-cli compile --fqbn arduino:avr:uno SyntheticUARTChecks
</code></pre>
<p>Our verification build used Arduino CLI 1.5.1, AVR core 1.8.8 and a native ARM64 AVR-GCC 14.2.0 toolchain on macOS. It used 6,724 bytes of program storage and 308 bytes of static RAM. The sketch was compiled, not uploaded to a board.</p>
<p>Select the board you actually use when building a different target. A successful compile establishes that source/compiler/target combination; it does not establish electrical or hardware compatibility with a module.</p>
<h2>Read the result correctly</h2>
<p>Our host-side execution of <code>decodeSynthetic()</code> with the exact published 0.1.1 C++ source produced:</p>
<pre><code class="language-text">SYNTHETIC LRF50H status=0 raw=4354 metres=43.540
SYNTHETIC LRF50VB status=0 raw=4354 metres=4.354
SYNTHETIC CORRUPT status=1 valid=0
</code></pre>
<p>These numbers came from generated bytes, not measurements. The valid cases demonstrate the model-specific conversion. In the corrupt case, the driver discards the invalid frame and waits for another one. Because the finite stream contains no valid replacement, it returns <code>ERDI_ERR_TIMEOUT</code>, whose value in this release is <code>1</code>.</p>
<p>Check the returned status before using <code>measurement.metres</code>. A timeout does not by itself distinguish a disconnected wire, a baud mismatch, incomplete input or discarded bad frames.</p>
<h2>What remains to check on real hardware</h2>
<p>Before replacing the synthetic stream with a board UART, confirm the exact model, controlled manual revision, delivered interface, supply, TX/RX logic levels, baud setting and grounding. Retain raw receive bytes and the model/configuration used to interpret them.</p>
<p>The library documents unresolved source discrepancies, including an LRF50VB command-table/checksum mismatch. This in-memory exercise neither sends those commands to hardware nor resolves that discrepancy. It also does not establish ROS 2, PX4, ArduPilot, all-board or all-model compatibility.</p>
<p>The source and examples are available in <a href="https://github.com/ErdiTech/ErdiLRF">ErdiTech/ErdiLRF</a>. The library is MIT licensed; keep its license when redistributing it. The small test helper and sketch in this article are also provided under MIT.</p>
<p>For model documents or configuration questions, use the <a href="https://erdilrf.com/models/">ERDILRF catalog</a> or <a href="https://erdilrf.com/contact/">contact page</a>. Technical contact: <a href="mailto:tommy@erdimail.com">tommy@erdimail.com</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Open-source starting points for laser ranging and LiDAR integration]]></title><description><![CDATA[A categorised list of repositories that are actually useful when you are integrating a laser rangefinder or LiDAR into something. Single-point DToF…]]></description><link>https://erdilrf.hashnode.dev/open-source-starting-points-for-laser-ranging-and-lidar-integration</link><guid isPermaLink="true">https://erdilrf.hashnode.dev/open-source-starting-points-for-laser-ranging-and-lidar-integration</guid><dc:creator><![CDATA[Tommy Yu]]></dc:creator><pubDate>Thu, 08 Oct 2026 06:40:25 GMT</pubDate><content:encoded><![CDATA[<p>A categorised list of repositories that are actually useful when you are integrating a laser</p>
<p>rangefinder or LiDAR into something. Single-point DToF modules, 2D scanners, flight stacks, and the</p>
<p>message standards that connect them.</p>
<p>**Every link in this file was checked and returns HTTP 200** before publication. An earlier draft of</p>
<p>this list contained three repositories that did not exist — plausible-looking names I had</p>
<p>misremembered. They were removed. A list that sends you to a 404 wastes the only thing you were</p>
<p>going to give it, which is thirty seconds of trust.</p>
<p>**Disclosure:** I maintain entry 1.1. It is marked as such. Everything else here is other people's</p>
<p>work and none of it is affiliated with me.</p>
<p>---</p>
<p>## 1. Single-point DToF ranging modules</p>
<p>These are the closest cousins of an industrial 905 nm ranging module: one beam, one distance, a</p>
<p>serial or I²C interface.</p>
<p>### 1.1 `erdilrf/erdilrf-drivers` — *maintained by the author of this list*</p>
<p><a href="https://github.com/erdilrf/erdilrf-drivers">https://github.com/erdilrf/erdilrf-drivers</a></p>
<p>Host driver (Python, zero dependencies) and a header-only Arduino/C++ driver for the **LR1000E2 8-byte</p>
<p>UART protocol family**, plus a full protocol reference and a `decode` CLI that parses a captured frame</p>
<p>with no hardware attached. 50 tests, none requiring a serial port.</p>
<p>Worth reading even if you use a different module: [`protocol/verification.md`](<a href="https://github.com/erdilrf/erdilrf-drivers/blob/main/protocol/verification.md">https://github.com/erdilrf/erdilrf-drivers/blob/main/protocol/verification.md</a>)</p>
<p>re-derives a manufacturer's checksums from the stated rule rather than trusting the printed values,</p>
<p>and [`docs/what-the-datasheet-does-not-say.md`](<a href="https://github.com/erdilrf/erdilrf-drivers/blob/main/docs/what-the-datasheet-does-not-say.md">https://github.com/erdilrf/erdilrf-drivers/blob/main/docs/what-the-datasheet-does-not-say.md</a>)</p>
<p>documents four gaps in a published datasheet. The method transfers; the constants do not.</p>
<p>### 1.2 `budryerson/TFMINI-Plus`</p>
<p><a href="https://github.com/budryerson/TFMINI-Plus">https://github.com/budryerson/TFMINI-Plus</a></p>
<p>Arduino library for the **Benewake TFMini-Plus and TFMini-S** LiDAR distance sensors. The de-facto</p>
<p>community library for these modules, and the reference for how to structure a driver that has to cope</p>
<p>with two firmware variants of the same product.</p>
<p>Also see [`budryerson/TFMini-Plus-I2C`](<a href="https://github.com/budryerson/TFMini-Plus-I2C">https://github.com/budryerson/TFMini-Plus-I2C</a>) for the I²C</p>
<p>variant — useful because it shows the same device behind two different physical layers.</p>
<p>### 1.3 `garmin/LIDARLite_v3_Arduino_Library`</p>
<p><a href="https://github.com/garmin/LIDARLite%5C_v3%5C_Arduino%5C_Library">https://github.com/garmin/LIDARLite\_v3\_Arduino\_Library</a></p>
<p>First-party Arduino library for the **Garmin LIDAR-Lite v3**. A vendor publishing its own driver is</p>
<p>rarer than it should be, and this one is a decent model for what a vendor driver ought to contain.</p>
<p>### 1.4 VL53L0X / VL53L1X — the ST ToF family</p>
<p>Short-range ToF sensors with the widest ecosystem of any ranging part, which makes them the fastest</p>
<p>way to get *any* working distance pipeline before you commit to a long-range module.</p>
<p>| Repository | Note |</p>
<p>|---|---|</p>
<p>| <a href="https://github.com/stm32duino/VL53L1X">https://github.com/stm32duino/VL53L1X</a> | ST's own Arduino core library for VL53L1X |</p>
<p>| <a href="https://github.com/pololu/vl53l0x-arduino">https://github.com/pololu/vl53l0x-arduino</a> | Pololu's VL53L0X library — exceptionally clear register-level code |</p>
<p>| <a href="https://github.com/adafruit/Adafruit%5C_VL53L0X">https://github.com/adafruit/Adafruit\_VL53L0X</a> | Adafruit's, with the usual tutorial support |</p>
<p>| <a href="https://github.com/DFRobot/DFRobot%5C_VL53L0X">https://github.com/DFRobot/DFRobot\_VL53L0X</a> | DFRobot's, for their breakout boards |</p>
<p>Range is centimetres to a few metres, not hundreds. Use them to validate your I²C plumbing and your</p>
<p>data path; do not use them to validate a long-range optical design.</p>
<p>---</p>
<p>## 2. 2D scanning LiDAR</p>
<p>If you need a scan plane rather than a point.</p>
<p>| Repository | What it is |</p>
<p>|---|---|</p>
<p>| <a href="https://github.com/Slamtec/rplidar%5C_sdk">https://github.com/Slamtec/rplidar\_sdk</a> | Slamtec RPLIDAR SDK — the most widely deployed low-cost 2D LiDAR |</p>
<p>| <a href="https://github.com/ldrobotSensorTeam/ldlidar%5C_stl%5C_ros2">https://github.com/ldrobotSensorTeam/ldlidar\_stl\_ros2</a> | LD06/LD19 ROS 2 driver — very common on small robots |</p>
<p>| <a href="https://github.com/YDLIDAR/ydlidar%5C_ros2%5C_driver">https://github.com/YDLIDAR/ydlidar\_ros2\_driver</a> | YDLIDAR ROS 2 driver |</p>
<p>These are scanning mechanisms: a spinning or rotating assembly producing a point cloud, not a single</p>
<p>range. If your problem is "how far to that one thing", a single-point module will be smaller, cheaper,</p>
<p>faster and far easier to power.</p>
<p>---</p>
<p>## 3. 3D and automotive-grade</p>
<p>Heavier, and mostly relevant if you are building perception rather than measurement.</p>
<p>| Repository | What it is |</p>
<p>|---|---|</p>
<p>| <a href="https://github.com/Livox-SDK/Livox-SDK2">https://github.com/Livox-SDK/Livox-SDK2</a> | Livox non-repetitive-scanning LiDAR SDK |</p>
<p>| <a href="https://github.com/ouster-lidar/ouster-ros">https://github.com/ouster-lidar/ouster-ros</a> | Ouster ROS driver |</p>
<p>| <a href="https://github.com/ros-drivers/velodyne">https://github.com/ros-drivers/velodyne</a> | Velodyne ROS driver — long-lived, still worth reading for ROS conventions |</p>
<p>---</p>
<p>## 4. Flight stacks — where rangefinders actually get used</p>
<p>If you are putting a ranging module on an aircraft, do not write the integration from scratch. Both</p>
<p>major open-source stacks already have a rangefinder abstraction, and both have absorbed years of</p>
<p>hardware-specific failure modes.</p>
<p>| Repository | Note |</p>
<p>|---|---|</p>
<p>| <a href="https://github.com/PX4/PX4-Autopilot">https://github.com/PX4/PX4-Autopilot</a> | `src/drivers/distance_sensor/` — many modules, one interface |</p>
<p>| <a href="https://github.com/ArduPilot/ardupilot">https://github.com/ArduPilot/ardupilot</a> | `libraries/AP_RangeFinder/` — the same idea, different abstractions |</p>
<p>| <a href="https://github.com/mavlink/mavlink">https://github.com/mavlink/mavlink</a> | The `DISTANCE_SENSOR` message — how a rangefinder's output reaches a ground station |</p>
<p>Reading two independent implementations of the same abstraction is a fast way to learn which parts of</p>
<p>*your* interface are real constraints and which are habits.</p>
<p>---</p>
<p>## 5. How to read a ranging module driver</p>
<p>Across all of the above, the same four questions decide whether a driver is usable:</p>
<p>1. **Does it distinguish "no answer" from "measurement failed"?** These have completely different</p>
<p>causes — a cable versus a target — and a driver that returns one error code for both costs you an</p>
<p>afternoon every time.</p>
<p>2. **Does it resynchronise on a corrupted frame, or does one bad byte poison the stream?** Look for a</p>
<p>header-scan or a rolling buffer.</p>
<p>3. **Does it state its physical-layer assumptions, or silently guess them?** Parity, stop bits and</p>
<p>logic levels are the usual silent guesses.</p>
<p>4. **Does it say what it does not know?** A driver whose documentation admits a gap is more reliable</p>
<p>than one that reads as complete, because completeness in a hardware driver is usually a sign that</p>
<p>something was assumed rather than measured.</p>
<p>Point 4 is the one that separates the good ones. Hardware documentation that never says "unknown" has</p>
<p>either tested everything or is hiding something, and in open source it is usually the latter.</p>
<p>---</p>
<p>## Contributing</p>
<p>Corrections are the most valuable contribution: if a link here has died, or a repository has been</p>
<p>superseded, open an issue on</p>
<p>[`erdilrf/erdilrf-drivers`](<a href="https://github.com/erdilrf/erdilrf-drivers/issues">https://github.com/erdilrf/erdilrf-drivers/issues</a>). Broken links and</p>
<p>wrong characterisations both count as bugs.</p>
]]></content:encoded></item></channel></rss>