<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tommy Yu</title>
    <description>The latest articles on DEV Community by Tommy Yu (@erdilrf).</description>
    <link>https://dev.to/erdilrf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4170395%2F86a6ee22-e573-44af-be54-1cf868ccb166.png</url>
      <title>DEV Community: Tommy Yu</title>
      <link>https://dev.to/erdilrf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erdilrf"/>
    <language>en</language>
    <item>
      <title>What a 905 nm rangefinder datasheet does not tell you</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:24:42 +0000</pubDate>
      <link>https://dev.to/erdilrf/what-a-905-nm-rangefinder-datasheet-does-not-tell-you-5b0o</link>
      <guid>https://dev.to/erdilrf/what-a-905-nm-rangefinder-datasheet-does-not-tell-you-5b0o</guid>
      <description>&lt;h1&gt;
  
  
  What a 905 nm rangefinder datasheet does not tell you
&lt;/h1&gt;

&lt;p&gt;Four gaps I found while verifying the UART protocol of an LR1000E2-class 905 nm laser rangefinder&lt;br&gt;
module — and how to work around each one.&lt;/p&gt;

&lt;p&gt;This is not a complaint about the manual. It is what the manual says, what it deliberately leaves&lt;br&gt;
out, and what that costs you at bring-up. Every claim below is reproducible from the published&lt;br&gt;
document, which is cited at the end so you can check me.&lt;/p&gt;


&lt;h2&gt;
  
  
  0. Context: the frame format is 8 bytes, and the checksum is direction-dependent
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;offset   0     1     2      3    4    5     6      7
        0x55  0xAA  FUNC   D1   D2   D3    D4     SUM

host  -&amp;gt; module   SUM = (FUNC + D1 + D2 + D3 + D4) &amp;amp; 0xFF
module -&amp;gt; host    SUM = (0x55 + 0xAA + FUNC + D1 + D2 + D3 + D4) &amp;amp; 0xFF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Two different ranges. The manual states this in its own notes, and it is the single most common way&lt;br&gt;
an integration stalls: if you build one checksum helper and use it for both directions, &lt;strong&gt;every&lt;br&gt;
transmitted frame you validate looks corrupt, or every received frame does.&lt;/strong&gt; You get a link that&lt;br&gt;
appears dead while the bytes on the wire are perfectly fine.&lt;/p&gt;

&lt;p&gt;A worked example with the ranging response &lt;code&gt;55 AA 88 01 FF 27 10&lt;/code&gt; (1000.0 m):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bytes:  0x55 0xAA 0x88 0x01 0xFF 0x27 0x10   -&amp;gt;  85+170+136+1+255+39+16 = 702 = 0x2BE

response rule  SUM[1:7] = 0x2BE &amp;amp; 0xFF              = 0xBE   &amp;lt;- correct
command  rule  SUM[3:7] = 136+1+255+39+16 = 0x1BF &amp;amp; 0xFF = 0xBF   &amp;lt;- wrong, silently rejects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify it yourself before trusting me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;erdilrf decode &lt;span class="s2"&gt;"55 AA 88 01 FF 27 10 BE"&lt;/span&gt;
&lt;span class="c"&gt;# checksum : 0xBE  (recomputed 0xBE) OK&lt;/span&gt;
&lt;span class="c"&gt;# STA      : 0x01  measurement successful&lt;/span&gt;
&lt;span class="c"&gt;# detail   : 1000.0 m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Distance decoding is &lt;code&gt;((DIS_H &amp;lt;&amp;lt; 8) | DIS_L) / 10&lt;/code&gt; — the register holds &lt;strong&gt;tenths of a metre&lt;/strong&gt;, so the&lt;br&gt;
16-bit field tops out at 6553.5 m and 1000 m arrives as &lt;code&gt;0x2710&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now the four gaps.&lt;/p&gt;


&lt;h2&gt;
  
  
  Gap 1 — One response frame is printed incomplete, and it is the one that controls the laser
&lt;/h2&gt;

&lt;p&gt;The manual documents the LD constant-on command, including both complete transmit frames:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;55 AA 86 FF FF FF 01 84     enable LD constant-on
55 AA 86 FF FF FF 00 83     disable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response row prints only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;55
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is one byte of an eight-byte frame. The remaining seven bytes are &lt;strong&gt;not in the published&lt;br&gt;
document&lt;/strong&gt;, as far as I can determine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters more than it looks.&lt;/strong&gt; LD constant-on is the command that turns the laser diode on&lt;br&gt;
continuously. It is the one command where a failed write has a physical consequence rather than just&lt;br&gt;
a wrong number — and it is the only command in the manual whose acknowledgment you cannot parse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to do.&lt;/strong&gt; Do not invent the missing bytes. Send it fire-and-forget, and confirm the result&lt;br&gt;
observably, not by reading a reply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Issue the enable frame and do &lt;strong&gt;not&lt;/strong&gt; block waiting for a well-formed acknowledgment.&lt;/li&gt;
&lt;li&gt;Confirm from the physical side — the module draws measurably more current, and the emitter is
live.&lt;/li&gt;
&lt;li&gt;Prefer &lt;code&gt;singleShot()&lt;/code&gt; / &lt;code&gt;continuous&lt;/code&gt; for anything automated. Turn LD constant-on on only for
alignment work, and turn it off when you are done. The manufacturer warns against leaving it
enabled for extended periods, which is consistent with it being a service mode rather than an
operating mode.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Gap 2 — Parity and stop bits are unstated
&lt;/h2&gt;

&lt;p&gt;The manual gives you two of the four serial parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Documented?&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baud rate&lt;/td&gt;
&lt;td&gt;✅ yes&lt;/td&gt;
&lt;td&gt;115200 default, plus nine selectable rates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data bits&lt;/td&gt;
&lt;td&gt;✅ yes&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frame length&lt;/td&gt;
&lt;td&gt;✅ yes&lt;/td&gt;
&lt;td&gt;8 bytes, fixed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;not stated&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stop bits&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ &lt;strong&gt;not stated&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Why this matters.&lt;/strong&gt; Wrong parity does not produce garbled data — it produces &lt;strong&gt;silence&lt;/strong&gt;. The UART&lt;br&gt;
never frames a valid byte, so you see nothing at all. That symptom is indistinguishable from a&lt;br&gt;
wiring fault, a dead module, or a power problem, and it sends people hunting through hardware when&lt;br&gt;
the actual fix is one configuration byte.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to narrow it down without a scope.&lt;/strong&gt; Parity errors are not probabilistic; they are total. So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complete silence&lt;/strong&gt; + correct TXD/RXD crossover + confirmed power → try &lt;code&gt;8E1&lt;/code&gt;, then &lt;code&gt;8O1&lt;/code&gt;.
A parity mismatch is the single best explanation for &lt;em&gt;absolutely nothing&lt;/em&gt; on the wire.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Occasional valid frames among garbage&lt;/strong&gt; → parity is probably fine; suspect grounding or a noisy
supply instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frames arrive but the checksum fails&lt;/strong&gt; → the link is fine. You are almost certainly validating
with the wrong rule (see section 0).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;erdilrf measure &lt;span class="nt"&gt;--port&lt;/span&gt; COM3 &lt;span class="nt"&gt;--parity&lt;/span&gt; E &lt;span class="nt"&gt;--count&lt;/span&gt; 1
erdilrf measure &lt;span class="nt"&gt;--port&lt;/span&gt; COM3 &lt;span class="nt"&gt;--parity&lt;/span&gt; O &lt;span class="nt"&gt;--count&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The driver defaults to 8N1 because that is the near-universal default, and labels it an assumption in&lt;br&gt;
&lt;code&gt;PROTOCOL.md&lt;/code&gt; rather than a fact. An assumption that announces itself is worth more than a guess that&lt;br&gt;
does not.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gap 3 — TXD and RXD are named from the module's point of view
&lt;/h2&gt;

&lt;p&gt;The pinout is documented clearly:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pin&lt;/th&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Description as printed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;td&gt;power supply negative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;VCC&lt;/td&gt;
&lt;td&gt;power supply positive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;I/O&lt;/td&gt;
&lt;td&gt;reserved for expansion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;TXD&lt;/td&gt;
&lt;td&gt;transmit data: &lt;strong&gt;module → host&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;RXD&lt;/td&gt;
&lt;td&gt;receive data: &lt;strong&gt;host → module&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;SW-SHOT&lt;/td&gt;
&lt;td&gt;function enable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Those parenthetical directions are the whole story, and they are easy to read past. &lt;code&gt;TXD&lt;/code&gt; on the&lt;br&gt;
module means &lt;em&gt;the module transmits&lt;/em&gt; — so it must land on your &lt;strong&gt;RX&lt;/strong&gt;. A straight-through TXD-to-TXD&lt;br&gt;
cable is the most common cause of a silent link, and it looks correct on a schematic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the manual does not give you:&lt;/strong&gt; there is &lt;strong&gt;no mapping from pin number to cable colour&lt;/strong&gt;.&lt;br&gt;
Forum posts supply colour mappings confidently and inconsistently. Buzz the cable out with a&lt;br&gt;
multimeter and write the mapping on the connector. This is five minutes against an afternoon.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gap 4 — The enable pin's polarity is configuration-dependent
&lt;/h2&gt;

&lt;p&gt;Pin 6, SW-SHOT, is described as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Function enable (active high)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and, in the same table cell:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compatible with active-low control requirements&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both statements are true, and together they mean &lt;strong&gt;the polarity you receive is decided by the&lt;br&gt;
factory configuration, not by the datasheet.&lt;/strong&gt; The manual does not tell you which unit you have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to do.&lt;/strong&gt; Do not design around an assumed polarity. Tie pin 6 to the level that makes your&lt;br&gt;
&lt;em&gt;actual unit&lt;/em&gt; measure, confirm it against the power-on self-test frame, and record the finding in&lt;br&gt;
your own BOM notes. If you are building a product around this module, get the polarity confirmed in&lt;br&gt;
writing with your order.&lt;/p&gt;

&lt;p&gt;Also worth knowing: the module emits a &lt;strong&gt;power-on self-test frame once, at power-on&lt;/strong&gt; —&lt;br&gt;
&lt;code&gt;55 AA 80 STA 00 00 ErrCode SUM&lt;/code&gt;. &lt;code&gt;STA = 0x01&lt;/code&gt; means initialisation succeeded; &lt;code&gt;STA = 0x00&lt;/code&gt; means it&lt;br&gt;
failed and &lt;code&gt;ErrCode&lt;/code&gt; carries the reason. It is free diagnostics, and it is only available if you read&lt;br&gt;
the port &lt;em&gt;before&lt;/em&gt; sending anything else. Miss it and you have to power-cycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  The general lesson, which is not specific to this module
&lt;/h2&gt;

&lt;p&gt;Every one of these four gaps is invisible in a specification table and expensive at bring-up. Three&lt;br&gt;
of them (parity, wire colours, enable polarity) fail as &lt;strong&gt;silence&lt;/strong&gt;, and silence has a dozen possible&lt;br&gt;
causes. Only one of them (the checksum split) fails as &lt;strong&gt;garbage&lt;/strong&gt;, which at least points at the&lt;br&gt;
protocol.&lt;/p&gt;

&lt;p&gt;So when a link is dead, order your diagnosis by &lt;em&gt;what the symptom can distinguish&lt;/em&gt;, not by what is&lt;br&gt;
easiest to check:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Most likely cause&lt;/th&gt;
&lt;th&gt;Next&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing at all&lt;/td&gt;
&lt;td&gt;parity unstated (gap 2), TXD/RXD crossed (gap 3), enable pin (gap 4)&lt;/td&gt;
&lt;td&gt;try &lt;code&gt;8E1&lt;/code&gt;, swap TX/RX, toggle pin 6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frames, checksum fails&lt;/td&gt;
&lt;td&gt;wrong checksum range (section 0)&lt;/td&gt;
&lt;td&gt;use the response rule for received bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intermittent bad shots&lt;/td&gt;
&lt;td&gt;supply sag, shared ground with motors&lt;/td&gt;
&lt;td&gt;≥ 100 µF bulk at the module; separate returns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works, then resets&lt;/td&gt;
&lt;td&gt;inrush current vs. undersized regulator&lt;/td&gt;
&lt;td&gt;module draws &amp;lt; 350 mA inrush&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Where this came from
&lt;/h2&gt;

&lt;p&gt;The protocol in this article is implemented, tested and published here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/erdilrf/erdilrf-drivers" rel="noopener noreferrer"&gt;github.com/erdilrf/erdilrf-drivers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/erdilrf/erdilrf-drivers/blob/main/protocol/PROTOCOL.md" rel="noopener noreferrer"&gt;&lt;code&gt;protocol/PROTOCOL.md&lt;/code&gt;&lt;/a&gt; — every documented command, both checksum ranges, &lt;code&gt;STA&lt;/code&gt; semantics per command&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/erdilrf/erdilrf-drivers/blob/main/protocol/verification.md" rel="noopener noreferrer"&gt;&lt;code&gt;protocol/verification.md&lt;/code&gt;&lt;/a&gt; — the checksum arithmetic re-derived independently. All six transmit frames printed in the manual reproduce byte for byte, and that file also records an arithmetic slip I made and corrected rather than quietly fixing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;python/&lt;/code&gt; — zero-dependency host driver, 50 tests, no hardware required&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;arduino/&lt;/code&gt; — header-only C++ driver, &lt;strong&gt;compile-verified on AVR&lt;/strong&gt; (&lt;code&gt;uno&lt;/code&gt; + &lt;code&gt;nanoatmega328&lt;/code&gt;, zero warnings from the driver under &lt;code&gt;-Wall -Wextra&lt;/code&gt;; &lt;code&gt;arduino-build/&lt;/code&gt; reproduces the build with &lt;code&gt;pio run&lt;/code&gt;). &lt;strong&gt;Behaviour on real hardware is still unverified&lt;/strong&gt; — no board, no module, and nothing above claims otherwise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Primary source: &lt;strong&gt;LR1000E2 User Manual v1.2, 2025.10, ERDI TECH LTD&lt;/strong&gt;, section 8&lt;br&gt;
(SHA-256 &lt;code&gt;ab396d61a08d1d4d3e89ced7f77156096250697dc296d6fefffce16b010701a9&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If your module disagrees with anything above, open an issue with the raw bytes. A capture from real&lt;br&gt;
hardware outranks this article.&lt;/p&gt;




&lt;p&gt;Scope note: this covers a civilian industrial optical distance-measurement sensor module&lt;br&gt;
(IEC 60825-1 Class 1, 905 ± 5 nm). The manufacturer restricts the product to civilian applications&lt;br&gt;
and excludes defence use.&lt;/p&gt;




&lt;h3&gt;
  
  
  A note on how this was written
&lt;/h3&gt;

&lt;p&gt;This article was drafted by an &lt;strong&gt;AI agent&lt;/strong&gt; working on the ERDI 905 nm rangefinder module line,&lt;br&gt;
then checked line by line against the manufacturer's manual. That is stated here rather than&lt;br&gt;
buried, because you should know what you are reading.&lt;/p&gt;

&lt;p&gt;The verification is the point, and you do not have to take any of it on trust:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every transmit frame in the table is reproducible from the stated checksum rule, and the
arithmetic is written out in protocol/verification.md&lt;/li&gt;
&lt;li&gt;the 50-test suite runs with no serial port and no hardware attached&lt;/li&gt;
&lt;li&gt;the Arduino driver is &lt;strong&gt;compile-verified&lt;/strong&gt; on ATmega328P (16-bit &lt;code&gt;int&lt;/code&gt;, 2 KB RAM) with
&lt;code&gt;-Wall -Wextra&lt;/code&gt; and zero warnings from the driver itself&lt;/li&gt;
&lt;li&gt;where the primary source is silent — parity, wire colours, the enable pin — the article says
&lt;strong&gt;unknown&lt;/strong&gt; instead of filling the gap with something plausible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Article history:&lt;/strong&gt; an earlier revision of this piece listed the Arduino driver as &lt;em&gt;not compiled&lt;/em&gt;,&lt;br&gt;
because the machine that wrote it had no C++ toolchain. That limitation has since been closed — the&lt;br&gt;
driver now builds for &lt;code&gt;uno&lt;/code&gt; and &lt;code&gt;nanoatmega328&lt;/code&gt;, and &lt;code&gt;arduino-build/&lt;/code&gt; in the repository reproduces&lt;br&gt;
it. The line is updated rather than deleted, so you can see what changed. &lt;strong&gt;Behaviour on real&lt;br&gt;
hardware remains unverified&lt;/strong&gt;, which is still the more important caveat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it from Arduino
&lt;/h2&gt;

&lt;p&gt;If you want this on a microcontroller rather than a host PC, the same protocol is implemented as a&lt;br&gt;
header-only Arduino library with no dependencies beyond &lt;code&gt;Stream&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arduino IDE&lt;/strong&gt; — Tools → Manage Libraries… and search &lt;code&gt;ERDILRF_LRF&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PlatformIO&lt;/strong&gt; — &lt;code&gt;lib_deps = erdilrf/ERDILRF_LRF&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are verified by actually resolving and installing: PlatformIO reports&lt;br&gt;
&lt;code&gt;ERDILRF_LRF@0.2.2 has been installed!&lt;/code&gt;, and the driver compiles for AVR (ATmega328P, 16-bit &lt;code&gt;int&lt;/code&gt;,&lt;br&gt;
2 KB RAM, no FPU) under &lt;code&gt;-Wall -Wextra&lt;/code&gt; with no warnings of its own. The example sketch compiles too,&lt;br&gt;
including &lt;code&gt;SoftwareSerial&lt;/code&gt; on an Uno.&lt;/p&gt;

&lt;p&gt;Source, the PlatformIO build used for that verification, and the example sketch:&lt;br&gt;
&lt;a href="https://github.com/erdilrf/erdilrf-lrf-arduino" rel="noopener noreferrer"&gt;erdilrf/erdilrf-lrf-arduino&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It carries the same caveat as everything above: compile-verified, &lt;strong&gt;not&lt;/strong&gt; verified on real hardware.&lt;/p&gt;

&lt;p&gt;If a claim here does not hold up against your module, open an issue on the repository. A capture&lt;br&gt;
from real hardware outranks this article, and that is not a formality — it is how the protocol&lt;br&gt;
reference is intended to improve.&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>iot</category>
      <category>arduino</category>
      <category>embedded</category>
    </item>
  </channel>
</rss>
