<?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>Three 1535 nm rangefinders, three ranges: the sentence that makes them comparable</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Mon, 26 Oct 2026 05:42:53 +0000</pubDate>
      <link>https://dev.to/erdilrf/three-1535-nm-rangefinders-three-ranges-the-sentence-that-makes-them-comparable-pmp</link>
      <guid>https://dev.to/erdilrf/three-1535-nm-rangefinders-three-ranges-the-sentence-that-makes-them-comparable-pmp</guid>
      <description>&lt;p&gt;Three datasheets, three ranges: 23 km, 15 km, 8 km. All three call themselves "1535 nm laser rangefinder modules". None of those numbers can be compared, because none of them says what the laser was pointed at.&lt;/p&gt;

&lt;p&gt;Here are three figures from our own catalogue, with the sentence that ships next to each one:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Published range&lt;/th&gt;
&lt;th&gt;Condition, as published&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LRF1829C&lt;/td&gt;
&lt;td&gt;23,000 m&lt;/td&gt;
&lt;td&gt;line of sight, visibility not less than 26 km, humidity not greater than 50 % at 30 °C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LRF0610C&lt;/td&gt;
&lt;td&gt;6,000 m&lt;/td&gt;
&lt;td&gt;≥6,000 m against a 2.3 × 2.3 m reference target; ≥1,500 m against a human-size 0.5 × 1.7 m target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LRF0105C&lt;/td&gt;
&lt;td&gt;3,000 m&lt;/td&gt;
&lt;td&gt;≥3,000 m against 2.3 × 2.3 m at 30 % reflectance and ≥5 km visibility&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look at the third row. Against the same reference target it claims 3 km; the 23 km row claims 23 km. Both are 1535 nm, both carry the same eye-safety argument, both talk over a serial link. What separates them is aperture, pulse energy, mass — and the condition each figure was measured under.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the condition is the only thing worth comparing first
&lt;/h2&gt;

&lt;p&gt;At 1535 nm the transmitter is erbium glass and the receiver is InGaAs. Because the light is absorbed in the cornea before it reaches the retina, the allowable pulse energy is far higher than at 905 nm — which is exactly why 1535 nm modules exist at all in the kilometre range.&lt;/p&gt;

&lt;p&gt;But "high pulse energy" does not mean "long range". Range depends on the target's reflectivity, its size, and how much daylight is in the receiver. A 23 km module against a 10 % reflective target in bad visibility is not a 23 km module. That is not a marketing problem, it is arithmetic.&lt;/p&gt;

&lt;p&gt;Three questions resolve it faster than any datasheet:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What target size and reflectance was the figure measured against?&lt;/li&gt;
&lt;li&gt;What visibility?&lt;/li&gt;
&lt;li&gt;Is the accuracy figure absolute (metres) or proportional (a percentage above some distance)?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What we did about it
&lt;/h2&gt;

&lt;p&gt;We put the whole 1535 nm band on one page — every model, every published range, and the condition sitting next to it, unedited:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://specs.erdilrf.com/1535nm-laser-rangefinder-module/" rel="noopener noreferrer"&gt;1535 nm laser rangefinder module — the band in one page&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And the raw rows, if you would rather run your own filter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON / CSV: &lt;a href="https://specs.erdilrf.com/data/" rel="noopener noreferrer"&gt;specs.erdilrf.com/data&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Versioned mirror: &lt;a href="https://github.com/erdilrf-afk/erdi-lrf-specs" rel="noopener noreferrer"&gt;github.com/erdilrf-afk/erdi-lrf-specs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Citable copy with a DOI: &lt;a href="https://doi.org/10.5281/zenodo.23655337" rel="noopener noreferrer"&gt;10.5281/zenodo.23655337&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have a datasheet in front of you that quotes a range with no condition, that is the first thing worth asking about — before the price, before the lead time.&lt;/p&gt;

</description>
      <category>lidar</category>
      <category>hardware</category>
      <category>datasheet</category>
      <category>optics</category>
    </item>
    <item>
      <title>A rangefinder dataset you can diff: 59 models, with the test condition attached</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Mon, 26 Oct 2026 03:42:56 +0000</pubDate>
      <link>https://dev.to/erdilrf/a-rangefinder-dataset-you-can-diff-59-models-with-the-test-condition-attached-n4m</link>
      <guid>https://dev.to/erdilrf/a-rangefinder-dataset-you-can-diff-59-models-with-the-test-condition-attached-n4m</guid>
      <description>&lt;p&gt;A datasheet that says "20 km" is not telling you 20 km. It is telling you 20 km against some target, at some reflectance, in some visibility — and those three numbers are usually left out or buried in a footnote.&lt;/p&gt;

&lt;p&gt;That omission is why two suppliers can both quote "20 km" and mean completely different things, and why procurement arguments about range so often end with nobody able to prove anything.&lt;/p&gt;

&lt;p&gt;So we published the table we use internally, with the footnote kept.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is in it
&lt;/h2&gt;

&lt;p&gt;59 records, one per model, 29 fields. 38 rangefinder modules, 12 laser sources, 9 single-point lidar sensors. Wavelengths 905 nm, 940 nm and 1535 nm; ranges from 9 m to 23,000 m.&lt;/p&gt;

&lt;p&gt;The field that matters is &lt;code&gt;range_condition&lt;/code&gt;. It holds the manufacturer's own sentence — target size, reflectance, visibility — copied verbatim, not normalised and not extrapolated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LRF0815C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wavelength_nm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1535&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"range_max_m"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8000.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"range_min_m"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"range_condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=8,000 m to a 2.3 m x 2.3 m target, 30% reflectance, visibility &amp;gt;23 km"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where no condition is published, the field is empty. It is not filled with a guess, because a guessed condition is worse than a missing one: it looks like data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things it will not do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It will not give you a "typical range".&lt;/strong&gt; Averaging a 23 km row against a 12 km row produces a number that describes no product. Compare conditions, then compare ranges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It will not normalise accuracy.&lt;/strong&gt; Some models publish a fixed figure in metres, some publish a proportional one (D &amp;gt; 100 m, or a percentage). Where that happens the raw string ships alongside the scalar, and the raw string is authoritative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It will not price anything.&lt;/strong&gt; No prices anywhere in the dataset. Commercial terms are quoted per inquiry, because the right price depends on the interface, the housing and the volume, not on a table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why publish it at all
&lt;/h2&gt;

&lt;p&gt;Two reasons, neither of them charitable.&lt;/p&gt;

&lt;p&gt;First, a specification you can only get by emailing a sales address is a specification nobody checks. If the numbers are public, they can be diffed — including our own numbers, against our own earlier versions.&lt;/p&gt;

&lt;p&gt;Second, it changes the conversation. Most supplier comparisons collapse because the two sides are quoting different measurements. When both sides publish the condition, the argument becomes about the actual decision: whether a 1535 nm module at this mass and this interface does the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Interactive page, with the field list and the known limits: &lt;a href="https://specs.erdilrf.com/data/" rel="noopener noreferrer"&gt;specs.erdilrf.com/data&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;JSON and CSV, same rows, mirrored and versioned: &lt;a href="https://github.com/erdilrf-afk/erdi-lrf-specs" rel="noopener noreferrer"&gt;github.com/erdilrf-afk/erdi-lrf-specs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Archived copy with a DOI, so it can be cited in a purchasing document or a paper: &lt;a href="https://doi.org/10.5281/zenodo.23655337" rel="noopener noreferrer"&gt;10.5281/zenodo.23655337&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Licence is CC BY 4.0. Use it, quote it, build on it.&lt;/p&gt;

&lt;p&gt;If you find a row that is wrong, the errata address is on the dataset page. We would rather correct a row than defend it.&lt;/p&gt;

</description>
      <category>lidar</category>
      <category>hardware</category>
      <category>datasheet</category>
      <category>opensource</category>
    </item>
    <item>
      <title>What a first article inspection for a rangefinder actually contains</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Mon, 26 Oct 2026 02:21:42 +0000</pubDate>
      <link>https://dev.to/erdilrf/what-a-first-article-inspection-for-a-rangefinder-actually-contains-49k8</link>
      <guid>https://dev.to/erdilrf/what-a-first-article-inspection-for-a-rangefinder-actually-contains-49k8</guid>
      <description>&lt;p&gt;Two suppliers quote the same range. One of them can prove it; the other has a PDF. The difference shows up six months later, when the first batch arrives and nobody agrees what "conforming" means.&lt;/p&gt;

&lt;p&gt;First article inspection is the moment that ambiguity gets closed. Most buyers have never seen one for a rangefinder, so here is what it should contain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a sample test is not enough
&lt;/h2&gt;

&lt;p&gt;A sample tells you one unit worked once. A first article tells you &lt;em&gt;both sides agreed what the part is&lt;/em&gt;, which is what makes later disagreements mechanical instead of emotional. Once signed, a returned unit is compared against a document rather than argued about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The twelve records
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Identity.&lt;/strong&gt; Serial number, firmware version, hardware revision, recorded against the drawing revision. Without the revision this document is worthless six months later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Dimensional.&lt;/strong&gt; Housing, mounting holes, optical window position — measured, with the instrument named.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Mass.&lt;/strong&gt; Measured against the declared value, tolerance stated. Sounds trivial; it is the number that quietly breaks gimbal designs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Optical axis.&lt;/strong&gt; Boresight offset between transmit and receive axes relative to the mechanical datum, in mrad. For an integrated sight this is the number that decides whether the reticle and the beam agree at 2 km.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Range verification.&lt;/strong&gt; Measured range against a stated target at a stated distance in stated visibility — with the reference instrument named. "16 km" alone is not a record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Accuracy.&lt;/strong&gt; Constant and proportional error, measured at three or more distances. A ±2 m figure with an unstated per-kilometre term is not a specification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Repetition rate.&lt;/strong&gt; Achieved rate in continuous mode, plus the missed-return count over a fixed number of shots. The second number is the one that predicts field behaviour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Interface.&lt;/strong&gt; Every command in the protocol document exercised once, replies recorded. This is where an integration either starts clean or starts with a two-week debug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Power.&lt;/strong&gt; Current draw at idle, single-shot and continuous, at both supply limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Environmental.&lt;/strong&gt; Temperature cycling result, and whether the unit was operated at both extremes or merely stored there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Sealing.&lt;/strong&gt; IP test method and result — or an explicit statement that it was not performed. An omission stated is information; an omission hidden is a surprise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. Safety.&lt;/strong&gt; Accessible emission measured at the aperture, with instrument and standard cited. Note this classifies &lt;em&gt;that build&lt;/em&gt;, not your product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do with it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make it a &lt;strong&gt;line item in the quotation&lt;/strong&gt;, not a favour. If it cannot be priced, it cannot be delivered.&lt;/li&gt;
&lt;li&gt;Ask for it &lt;strong&gt;once&lt;/strong&gt;, on the first article, and keep it. Later units are judged against it.&lt;/li&gt;
&lt;li&gt;If a supplier cannot produce one, that is a data point about how the next twelve months will go — not a reason to negotiate harder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The twelve fields, as a checklist you can send directly, are &lt;a href="https://specs.erdilrf.com/docs/first-article-inspection" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The range test report template that pairs with it is &lt;a href="https://specs.erdilrf.com/docs/range-test-report-template" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I keep an open dataset of 59 rangefinder and single-point lidar modules at &lt;a href="https://specs.erdilrf.com" rel="noopener noreferrer"&gt;specs.erdilrf.com&lt;/a&gt; — every range figure carrying the manufacturer's own test condition, plus interface and optics tables. JSON and CSV, CC BY 4.0, no signup.&lt;/p&gt;

&lt;p&gt;If you have a first-article horror story — a dimension that was "measured" without an instrument, a firmware revision nobody wrote down — I would like to hear it. Those are the ones worth writing about.&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>manufacturing</category>
      <category>embedded</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Why "eye safe" is a wavelength argument, not a marketing claim</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:58:57 +0000</pubDate>
      <link>https://dev.to/erdilrf/why-eye-safe-is-a-wavelength-argument-not-a-marketing-claim-43b6</link>
      <guid>https://dev.to/erdilrf/why-eye-safe-is-a-wavelength-argument-not-a-marketing-claim-43b6</guid>
      <description>&lt;p&gt;"Eye safe" is not a property of a laser. It is a property of a &lt;em&gt;number of joules at a given wavelength reaching a given aperture&lt;/em&gt; — and the wavelength decides how many joules that is.&lt;/p&gt;

&lt;p&gt;This matters when you are choosing a rangefinder for something that points at people: a drone payload, a handheld sight, a perimeter scanner.&lt;/p&gt;

&lt;h2&gt;
  
  
  The physical reason
&lt;/h2&gt;

&lt;p&gt;At 905 nm and 940 nm the eye focuses the beam onto the retina. The hazard is retinal, and the allowed exposure is tiny: a few hundred nanojoules for a nanosecond-class pulse.&lt;/p&gt;

&lt;p&gt;At 1535 nm the beam is absorbed by water in the cornea and lens &lt;em&gt;before&lt;/em&gt; it reaches the retina. The hazard becomes corneal, and the allowed exposure is roughly five orders of magnitude higher for the same tissue effect.&lt;/p&gt;

&lt;p&gt;That is the whole trick. It is not marketing, and it is not that 1535 nm is "safer light" — it is that the energy stops at the front of the eye instead of the back.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it buys you
&lt;/h2&gt;

&lt;p&gt;For a rangefinder, range scales with pulse energy (among other things). If the allowed energy is far higher at 1535 nm, the same Class 1 limit permits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more joules per pulse → longer range against the same target&lt;/li&gt;
&lt;li&gt;and, just as importantly, the same range with a &lt;em&gt;narrower&lt;/em&gt; beam, which concentrates energy and makes the return stronger&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why the long-range end of the market is almost entirely 1535 nm, and why the 905 nm parts are the short-range, high-rate, low-mass ends of the same catalogue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not buy you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It does not make the module Class 1 by itself.&lt;/strong&gt; A 1535 nm source at high energy can still exceed the corneal limit. The class is a measurement of the assembled product at its aperture, not a property of the wavelength.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not transfer to your product.&lt;/strong&gt; The module's label applies to the module as supplied. Add a lens, a window, a different housing, or a second emitter, and the accessible emission changes. The finished product needs its own assessment and its own label. This is the part that integrators most often get wrong — and the part that a customer's safety officer will ask about first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not mean invisible.&lt;/strong&gt; 1535 nm is well outside the visible band, which is convenient operationally, but "invisible" is not "harmless"; the classification exists precisely because it is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to ask a supplier
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Which wavelength, and is the class statement made at the module aperture or at the source?&lt;/li&gt;
&lt;li&gt;Under which standard and revision was the class determined?&lt;/li&gt;
&lt;li&gt;What is the pulse energy, pulse width and repetition rate at the stated class?&lt;/li&gt;
&lt;li&gt;Does the class statement survive the intended optical configuration, or does it need re-assessment?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A supplier who answers these four precisely is telling you they have been through a customer's safety review before.&lt;/p&gt;

&lt;p&gt;I keep an open dataset of rangefinder and single-point lidar modules at &lt;a href="https://specs.erdilrf.com" rel="noopener noreferrer"&gt;specs.erdilrf.com&lt;/a&gt; — 59 modules, 905 / 940 / 1535 nm, every range figure carrying the manufacturer's own test condition, plus an &lt;a href="https://specs.erdilrf.com/data/interfaces" rel="noopener noreferrer"&gt;interface table&lt;/a&gt; and the &lt;a href="https://specs.erdilrf.com/guide/laser-safety-for-integrators" rel="noopener noreferrer"&gt;safety guide for integrators&lt;/a&gt;. JSON and CSV, CC BY 4.0.&lt;/p&gt;

&lt;p&gt;If you have had a class statement fail at the product level, I would like to hear how it happened — it is the most useful kind of anecdote in this field.&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>embedded</category>
      <category>robotics</category>
      <category>safety</category>
    </item>
    <item>
      <title>Five things in a rangefinder protocol document that cost two weeks each</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:55:37 +0000</pubDate>
      <link>https://dev.to/erdilrf/five-things-in-a-rangefinder-protocol-document-that-cost-two-weeks-each-1bl9</link>
      <guid>https://dev.to/erdilrf/five-things-in-a-rangefinder-protocol-document-that-cost-two-weeks-each-1bl9</guid>
      <description>&lt;p&gt;Two weeks of field debugging, then a one-line fix in the protocol document. That is the usual ratio when a rangefinder integration goes wrong. The laser is rarely the problem — the bytes around it are.&lt;/p&gt;

&lt;p&gt;Here are the five things that break integrations, in the order they usually bite.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Endianness, and the number that is silently wrong
&lt;/h2&gt;

&lt;p&gt;A range value spans two or four bytes. If the document says "distance, 2 bytes" and stops, the host and the module can disagree about byte order and still produce &lt;em&gt;a&lt;/em&gt; number — just a wrong one. 0x0B B8 is 3000 in big-endian and 0xB80B (47115) in little-endian. Both are legal integers. One is 3 metres, the other is 47 kilometres.&lt;/p&gt;

&lt;p&gt;Symptom: ranges that jump by a factor of ~15.6 when the low byte happens to be large.&lt;/p&gt;

&lt;p&gt;Fix: demand the byte order in writing, and test with a known short distance where the two readings differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Checksum coverage: which bytes, exactly
&lt;/h2&gt;

&lt;p&gt;"Checksum over the message" is not a specification. It has to state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the algorithm (sum, XOR, CRC-8/16, which polynomial)&lt;/li&gt;
&lt;li&gt;the seed / initial value&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;whether the checksum byte itself and the start bytes are covered&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;whether it is computed before or after byte-stuffing, if stuffing exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Off-by-one in coverage produces a link that works for one command length and fails for another — the worst kind of bug, because it looks like an intermittent hardware fault.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. What happens mid-measurement
&lt;/h2&gt;

&lt;p&gt;A command that arrives while the module is still integrating has three plausible behaviours: it is queued, it is dropped, or it aborts the measurement and replies with something. If the document does not say which, the host software will be written against the wrong one.&lt;/p&gt;

&lt;p&gt;Related: the minimum interval between commands. Modules that need 200 ms of integration will not answer faster than that, and sending faster does not produce errors — it produces stale or missing answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Resynchronisation after a dropped byte
&lt;/h2&gt;

&lt;p&gt;A UART link loses bytes. What does the host do when a frame arrives short? If the protocol has no reliable frame boundary (a start byte pair, or a length field plus terminator), the parser cannot tell a truncated frame from a valid short one, and the stream stays misaligned until the host is restarted.&lt;/p&gt;

&lt;p&gt;The document must state the resync rule explicitly: flush until the next start marker, discard the partial frame, resume.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Error codes that nobody can act on
&lt;/h2&gt;

&lt;p&gt;"Error 0x03" with no cause attached is not an error code, it is a puzzle. Useful error sets distinguish at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no return detected&lt;/li&gt;
&lt;li&gt;return detected but ambiguous (two echoes, e.g. through glass or vegetation)&lt;/li&gt;
&lt;li&gt;target too close&lt;/li&gt;
&lt;li&gt;target too far&lt;/li&gt;
&lt;li&gt;supply out of range&lt;/li&gt;
&lt;li&gt;internal temperature out of range&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last two matter more than they look: a module that quietly returns garbage below −20 °C will be blamed for a positioning bug months later.&lt;/p&gt;

&lt;h2&gt;
  
  
  An example exchange, and why it belongs in the document
&lt;/h2&gt;

&lt;p&gt;Nothing in a protocol document saves as much integration time as one complete transcript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TX  55 AA 04 01 00 05          start, len, cmd=measure, arg=0, checksum
RX  55 AA 07 81 0B B8 00 12     start, len, cmd|0x80, distance=0x0BB8, status=0x00, checksum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nine bytes of example explain more than three pages of prose, because it forces the author to state the frame layout unambiguously.&lt;/p&gt;

&lt;p&gt;I put the full list of twelve items a protocol document must state into a &lt;a href="https://specs.erdilrf.com/docs/serial-protocol-checklist" rel="noopener noreferrer"&gt;checklist&lt;/a&gt;. Send it to any supplier before you write a driver — the ones who can answer all twelve have shipped to integrators before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general rule
&lt;/h2&gt;

&lt;p&gt;Every ambiguity in a protocol document becomes an experiment in your lab. An experiment costs a day; a sentence in the document costs nothing. If a supplier cannot produce the sentence, treat that as information about how the rest of the project will go.&lt;/p&gt;

&lt;p&gt;I keep an open dataset of rangefinder and single-point lidar modules at &lt;a href="https://specs.erdilrf.com" rel="noopener noreferrer"&gt;specs.erdilrf.com&lt;/a&gt; — 59 modules with the manufacturer's test conditions attached to every range figure, plus the interface and optics tables. JSON and CSV, CC BY 4.0, no signup. The &lt;a href="https://specs.erdilrf.com/answers/" rel="noopener noreferrer"&gt;answers section&lt;/a&gt; covers the buyer questions that keep coming up.&lt;/p&gt;

&lt;p&gt;If any of the five above has bitten you with a specific module, I would like to hear which one — the failure modes are the interesting part.&lt;/p&gt;

</description>
      <category>embedded</category>
      <category>arduino</category>
      <category>hardware</category>
      <category>c</category>
    </item>
    <item>
      <title>Your lidar says 40 m and reaches 9 m: the four numbers that decide a real range</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:53:52 +0000</pubDate>
      <link>https://dev.to/erdilrf/your-lidar-says-40-m-and-reaches-9-m-the-four-numbers-that-decide-a-real-range-7o4</link>
      <guid>https://dev.to/erdilrf/your-lidar-says-40-m-and-reaches-9-m-the-four-numbers-that-decide-a-real-range-7o4</guid>
      <description>&lt;p&gt;Your lidar says 40 m. Outdoors it stops at 9 m. Nothing is broken — the datasheet was measured under conditions nobody wrote down.&lt;/p&gt;

&lt;p&gt;I maintain an open dataset of laser rangefinder and single-point lidar modules (&lt;a href="https://specs.erdilrf.com" rel="noopener noreferrer"&gt;specs.erdilrf.com&lt;/a&gt;), and the most common support question is some variant of &lt;em&gt;"why is my range so much worse than the datasheet?"&lt;/em&gt; It is almost always one of four numbers, and the datasheet usually gives you one of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four numbers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Target reflectance.&lt;/strong&gt; Most modules quote a range against a 90 % reflective target — a retro-reflector or a white board. Real targets are not that. A matte grey wall is around 10–20 %; black anodised aluminium is under 5 %; foliage is worse and it moves. Returned power falls with reflectance, and range falls with the fourth root of returned power, so a 10× drop in reflectance costs you a meaningful fraction of your range before anything else goes wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Background illumination.&lt;/strong&gt; Indoor compatibility is often quoted in klx. Direct sun on a white target is on the order of 100 klx. If the module's stated ambient immunity is 10 klx, outdoor daylight is outside its specification. Narrowband filtering helps — one reason 905 nm and 940 nm parts behave differently in sunlight — but it does not perform miracles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Atmosphere.&lt;/strong&gt; Visibility in km is the usual figure. At 10 km visibility the atmosphere already eats a few percent per hundred metres; in fog or heavy rain the return can vanish entirely. Long-range modules quote their headline numbers at &lt;em&gt;good&lt;/em&gt; visibility, which is a condition, not a guarantee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Integration time and rate.&lt;/strong&gt; A 200 Hz stream cannot integrate as long as a 1 Hz single shot. The same optics produce quite different ranges depending on how long they look. This is why the fastest modules and the longest-range modules are usually not the same product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;Ask for the condition behind every range figure. In the dataset I keep, each row carries the manufacturer's own sentence — target size, reflectance, visibility — verbatim, because paraphrasing it destroys the only comparable part of the number:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Measuring range 12 km for target 5 × 15 m, reflectivity 0.3, visibility 23 km"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a completely different claim from "12 km", and the only form in which the number means anything. Two modules quoting the same headline range can differ by 3–4× in practice, simply because one condition says &lt;em&gt;large vehicle at 23 km visibility&lt;/em&gt; and the other says &lt;em&gt;small drone in haze&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 20-minute test that settles it
&lt;/h2&gt;

&lt;p&gt;You do not need a lab. You need to record the four numbers above, then take a few hundred shots at each distance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Put the target at a measured distance; note material and size.&lt;/li&gt;
&lt;li&gt;Note the light: direct sun, shade, or dark. Measure illuminance if you can.&lt;/li&gt;
&lt;li&gt;Note the weather and roughly the visibility.&lt;/li&gt;
&lt;li&gt;Take at least 100 shots per distance; record the &lt;strong&gt;median and the spread&lt;/strong&gt;, and count the misses.&lt;/li&gt;
&lt;li&gt;Report the distance at which you start losing returns. That is the honest range; everything before it is a nice-to-have.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The misses matter more than the hits: the failure boundary decides whether the product works on a bad day. If you want the full field list, I published a &lt;a href="https://specs.erdilrf.com/docs/range-test-report-template" rel="noopener noreferrer"&gt;range test report template&lt;/a&gt; with the twelve fields that make a result checkable by someone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two things to check before committing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interface documentation.&lt;/strong&gt; Framing, endianness and checksum coverage are where integrations die, and none of it is in a brochure. There is a &lt;a href="https://specs.erdilrf.com/docs/serial-protocol-checklist" rel="noopener noreferrer"&gt;protocol checklist&lt;/a&gt; of the twelve items a protocol document must state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update rate vs accuracy.&lt;/strong&gt; A fast stream with centimetre resolution is a good control input and a poor measuring instrument. Decide which one you are building before comparing parts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The dataset
&lt;/h2&gt;

&lt;p&gt;If it is useful: &lt;a href="https://specs.erdilrf.com/data" rel="noopener noreferrer"&gt;specs.erdilrf.com/data&lt;/a&gt; — 59 modules, 905 / 940 / 1535 nm, with the manufacturer's range condition attached to every row, plus interface, optics and selection-by-application tables. JSON and CSV, CC BY 4.0, no signup.&lt;/p&gt;

&lt;p&gt;If a row is wrong, tell me and it gets fixed. An errata is cheaper than a design review built on a bad number.&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>embedded</category>
      <category>iot</category>
      <category>arduino</category>
    </item>
    <item>
      <title>What a laser rangefinder module actually costs: 59 published prices</title>
      <dc:creator>Tommy Yu</dc:creator>
      <pubDate>Thu, 22 Oct 2026 03:59:53 +0000</pubDate>
      <link>https://dev.to/erdilrf/what-a-laser-rangefinder-module-actually-costs-59-published-prices-2bfg</link>
      <guid>https://dev.to/erdilrf/what-a-laser-rangefinder-module-actually-costs-59-published-prices-2bfg</guid>
      <description>&lt;h1&gt;
  
  
  What a laser rangefinder module actually costs: 59 published prices
&lt;/h1&gt;

&lt;p&gt;Every laser rangefinder supplier answers a price question with a form. We published the unit price for&lt;br&gt;
all 59 modules in our catalogue instead — &lt;strong&gt;$70 to $5,000&lt;/strong&gt;, on the model page, before anyone asks for&lt;br&gt;
an email address.&lt;/p&gt;

&lt;p&gt;This post is the engineering reading of that price list: what the money buys, where the discontinuities&lt;br&gt;
are, and how to compare a quote that arrives with a much lower number than the one you budgeted.&lt;/p&gt;

&lt;p&gt;Nothing below is a quotation. These are catalogue values, captured from the datasheet each model ships&lt;br&gt;
with, and they are the same numbers a buyer can check on any model page.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The price bands, and what changes as you climb
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Band&lt;/th&gt;
&lt;th&gt;Representative models&lt;/th&gt;
&lt;th&gt;What you are buying&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Under $100&lt;/td&gt;
&lt;td&gt;ER100 $70 · LR1000E2 / LR1000E4 $80 · LRF10VB $80 · LR1200E2 / E4 $90 · LRF1200A1 $90 · LRF22VB $90 · SPD1200N3 $94.5&lt;/td&gt;
&lt;td&gt;Short-range DToF, 1 km UART modules, first integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$100 – $200&lt;/td&gt;
&lt;td&gt;LR1000D23 $110 · LR2000E2 / E4 $120 · LR1200D23 $130 · LR1500D23 $140 · LRF50VB $140 · LRF50H $160 · LRF3000A1 $200 · SPD1200ZG $200&lt;/td&gt;
&lt;td&gt;1–2 km ranging, 50 m industrial sensing, 3 km long range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$200 – $400&lt;/td&gt;
&lt;td&gt;ER400 $230 · LRF100H $230 · LRF200H $250 · LRF300H $280 · LRF0105C / 0305C / 0306C / 0310C $300 · LRF600H $350 · LRF1500H $400&lt;/td&gt;
&lt;td&gt;200–600 m industrial, entry into 1535 nm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$800 and up&lt;/td&gt;
&lt;td&gt;LRF0609C / 0610C $800 · LRF0815C / 0818C $900 · ER800 $1,050 · LRF0816C $1,200 · LRF1017C $1,300 · ER2000 $1,500 · ER8000 $3,000 · LRF1525C $3,000 · LRF1830C $3,500 · ER10000 $5,000&lt;/td&gt;
&lt;td&gt;Multi-kilometre eye-safe ranging, 1.54 µm sources&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things are visible in that table that a per-unit quote never shows you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 905 nm line is not uniformly cheaper.&lt;/strong&gt; A 3 km 905 nm module sits at $200; the cheapest long-range&lt;br&gt;
1535 nm module starts at $300. The cheap end of the spectrum is short range, not short wavelength.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The step function is at the detector, not at the range.&lt;/strong&gt; Between $300 and $900 you are no longer&lt;br&gt;
paying for metres. You are paying for indium gallium arsenide instead of silicon, and for an&lt;br&gt;
erbium-doped source instead of a diode stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Why 1535 nm costs 4× for the same aperture
&lt;/h2&gt;

&lt;p&gt;At 905 nm the light focuses on the retina. That caps the energy you may emit per pulse, and the cap&lt;br&gt;
caps your range: hundreds of metres to about three kilometres in a small aperture.&lt;/p&gt;

&lt;p&gt;At 1535 nm the water in the cornea and lens absorbs the light before it reaches the retina. The permitted&lt;br&gt;
energy is far higher, so the same aperture reaches 8, 12, 18 km — and the returns that come with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an InGaAs detector instead of silicon,&lt;/li&gt;
&lt;li&gt;a 1.54 µm source,&lt;/li&gt;
&lt;li&gt;a thermal path that is no longer optional at high pulse energy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the whole $300 → $900+ jump. There is no version of this where the longer-range module is cheap.&lt;/p&gt;

&lt;p&gt;The comparison I would actually put in a design review:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;905 nm&lt;/th&gt;
&lt;th&gt;1535 nm / 1.54 µm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Entry price&lt;/td&gt;
&lt;td&gt;From $80&lt;/td&gt;
&lt;td&gt;From $300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Range in a small aperture&lt;/td&gt;
&lt;td&gt;Hundreds of m to ~3 km&lt;/td&gt;
&lt;td&gt;Kilometres to 18 km&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detector&lt;/td&gt;
&lt;td&gt;Silicon&lt;/td&gt;
&lt;td&gt;InGaAs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eye-safety budget&lt;/td&gt;
&lt;td&gt;Tight&lt;/td&gt;
&lt;td&gt;Far larger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visible to a silicon camera at night&lt;/td&gt;
&lt;td&gt;Faintly&lt;/td&gt;
&lt;td&gt;Effectively no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your requirement is under a few hundred metres, 905 nm is not the budget option — it is the correct&lt;br&gt;
option. People over-specify wavelength for the same reason they over-specify range: the datasheet's&lt;br&gt;
largest number is the easiest thing to compare and the least informative.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The two numbers per model that decide the outcome
&lt;/h2&gt;

&lt;p&gt;Every module publishes two range figures: one at &lt;strong&gt;90 % target reflectivity&lt;/strong&gt;, one at &lt;strong&gt;10 %&lt;/strong&gt;. The gap&lt;br&gt;
is often 3×.&lt;/p&gt;

&lt;p&gt;A warehouse floor is not a white wall. Neither is wet asphalt, dark rubber, black shrink-wrap, or a&lt;br&gt;
person in a dark jacket. On those surfaces the module behaves like the second number, and the first&lt;br&gt;
number was never a lie — it just described a laboratory target.&lt;/p&gt;

&lt;p&gt;The second trap is the &lt;strong&gt;minimum range&lt;/strong&gt;. It is stated, and it is frequently ignored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0.05 m floor on the H and VB series (useful for landing, close obstacle guard, precision docking),&lt;/li&gt;
&lt;li&gt;3 m on SPD1200N3,&lt;/li&gt;
&lt;li&gt;tens of metres on some long-range models.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two suppliers can both quote "1,200 m" while one cannot measure anything closer than 15 m.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Four checks before you compare two quotes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The condition behind the range figure.&lt;/strong&gt; Target size, reflectance, visibility, and whether the
number is a maximum or a repeatable value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The interface.&lt;/strong&gt; UART-TTL, RS232, RS485, I²C — and the frame format with its checksum, not just
"serial output".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The minimum range.&lt;/strong&gt; See above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is in the box.&lt;/strong&gt; Bare module, module with cable, module with housing, module with an
acceptance report. This is where two quotes 30 % apart usually differ.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  5. What volume changes
&lt;/h2&gt;

&lt;p&gt;Published prices are single-unit values. Volume pricing is quoted per order and depends on the model,&lt;br&gt;
the test coverage and the delivery schedule. Concretely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit price&lt;/strong&gt; changes with volume.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acceptance documentation&lt;/strong&gt; changes with volume, and for an integrator it is usually worth more than
a few percent off the unit price — a batch that ships with a test record against the datasheet's own
conditions removes a qualification step from your project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mechanical and firmware variants&lt;/strong&gt; (connector, cable length, mounting, baud rate, output frame) are
engineering changes, not discounts, and they cost lead time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The specification does not change.&lt;/strong&gt; A module specified against a 2.3 × 2.3 m target at 30 %
reflectance is specified to that at any quantity.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Why publish this at all
&lt;/h2&gt;

&lt;p&gt;Because a hidden price is a decision made for you. If the number is public, an engineer can tell in&lt;br&gt;
thirty seconds whether a supplier is in the budget or three times over it, and spend the meeting on the&lt;br&gt;
questions that actually decide the design: minimum range, beam divergence, thermal path, protocol.&lt;/p&gt;

&lt;p&gt;All 59 model pages carry their own price, the measuring condition behind the range, and the interface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Catalogue and model selector: &lt;a href="https://erdilrf.com/models/" rel="noopener noreferrer"&gt;https://erdilrf.com/models/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Price bands in one page: &lt;a href="https://erdilrf.com/laser-rangefinder-module-wholesale/" rel="noopener noreferrer"&gt;https://erdilrf.com/laser-rangefinder-module-wholesale/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The 1535 nm / 1.54 µm line: &lt;a href="https://erdilrf.com/1535nm-laser-rangefinder-module/" rel="noopener noreferrer"&gt;https://erdilrf.com/1535nm-laser-rangefinder-module/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Open drivers (Python, Arduino, ROS 2) and the verified UART protocol: &lt;a href="https://github.com/erdilrf" rel="noopener noreferrer"&gt;https://github.com/erdilrf&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a quotation you received is materially below the figures above for the same specification, the&lt;br&gt;
useful question is not who is cheaper. It is what condition that number was measured under.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Prices are captured catalogue values, not quotations, and can be revised as the catalogue changes.&lt;br&gt;
A written quotation governs an order. Where two source documents conflict on a value — for example on&lt;br&gt;
LRF1200A1, LRF3000A1, LRF50VB or LRF1500H — the model page states the conflict instead of choosing one,&lt;br&gt;
and the current datasheet governs the order.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>embedded</category>
      <category>robotics</category>
      <category>opensource</category>
    </item>
    <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>
