<?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: Adeline</title>
    <description>The latest articles on DEV Community by Adeline (@salgadous).</description>
    <link>https://dev.to/salgadous</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%2F4202728%2Fc212280c-a257-4536-abb6-97de10bb074c.jpg</url>
      <title>DEV Community: Adeline</title>
      <link>https://dev.to/salgadous</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salgadous"/>
    <language>en</language>
    <item>
      <title>How much of your pool does the robot actually clean? A coverage simulator in 60 lines of Python</title>
      <dc:creator>Adeline</dc:creator>
      <pubDate>Fri, 13 Nov 2026 14:18:22 +0000</pubDate>
      <link>https://dev.to/salgadous/how-much-of-your-pool-does-the-robot-actually-clean-a-coverage-simulator-in-60-lines-of-python-389e</link>
      <guid>https://dev.to/salgadous/how-much-of-your-pool-does-the-robot-actually-clean-a-coverage-simulator-in-60-lines-of-python-389e</guid>
      <description>&lt;p&gt;A distributor forwarded me a customer email last month. Two lines:&lt;br&gt;
"The robot runs for 40 minutes and the floor still looks striped. Is it broken?"  stonebotclean.com&lt;br&gt;
The honest answer is that I didn't know. Every spec sheet in this category quotes a runtime, a swath width and a suction power. None of them quote coverage, because coverage is not a spec you can print — it is what happens when a path meets a rectangle with walls on four sides.&lt;br&gt;
So I stopped reading brochures and wrote a simulator. Rasterise the pool at 2 cm, stamp the brush along the path, count how many cells never get touched.&lt;br&gt;
Here is what came out, and the three things I got wrong on the first pass.&lt;br&gt;
** &lt;br&gt;
The model&lt;br&gt;
Nothing fancy. A 12 × 6 m pool (72 m², a normal residential rectangle), a 42 cm effective swath, 0.28 m/s while scrubbing, 6 s for a 180° lane change, 15 cm of standoff so the brush housing clears the wall, and a 150 minute battery.&lt;br&gt;
Four serpentine variants, differing only in lane pitch:&lt;br&gt;
pitch = 1.00 × swath (0.42 m): the textbook answer, lanes exactly tangent&lt;br&gt;
pitch = 0.85 × swath (0.36 m): 15% overlap&lt;br&gt;
pitch = 0.70 × swath (0.29 m): 30% overlap&lt;br&gt;
pitch = 1.30 × swath (0.55 m): what happens when someone tunes the lane spacing up to "finish faster"&lt;br&gt;
Plus one control: a random-bounce run with no planning at all — drive until you hit a wall, deflect, keep going, change heading roughly every 8 seconds. That is what a $300 hobby unit does, and it is the baseline every lidar-equipped robot is implicitly being compared against.&lt;br&gt;
The measurement is a disk stamp: at every 4 cm along the path, mark every 2 cm cell within 10.5 cm of the centre as cleaned. Then count.&lt;br&gt;
def boustrophedon(pitch, pool, bot):&lt;br&gt;
    L, W = pool["length"], pool["width"]&lt;br&gt;
    stand, w = bot["standoff"], bot["width"]&lt;br&gt;
    x0, x1 = stand, L - stand&lt;br&gt;
    y0, y1 = stand, W - stand&lt;br&gt;
    lane_y, y = [], y0 + w / 2&lt;br&gt;
    while y &amp;lt;= y1 - w / 2 + 1e-9:&lt;br&gt;
        lane_y.append(y)&lt;br&gt;
        y += pitch&lt;br&gt;
    if lane_y[-1] &amp;lt; y1 - w / 2 - 1e-6:   # edge pass&lt;br&gt;
        lane_y.append(y1 - w / 2)&lt;br&gt;
    ...&lt;/p&gt;

&lt;p&gt;That edge pass line is the first thing I got wrong. Without it, the loop stops as soon as the next lane would cross the top wall, and the last 28 cm of the pool simply never gets driven. On the 15% overlap run that was 4.9% of the floor — invisible in a spec sheet, visible to anyone standing at the shallow end.&lt;br&gt;
What the numbers said&lt;br&gt;
Strategy&lt;br&gt;
Lane pitch&lt;br&gt;
Floor reached&lt;br&gt;
Time&lt;br&gt;
Swept area / floor&lt;br&gt;
Lane changes&lt;br&gt;
Tangent lanes&lt;br&gt;
0.42 m&lt;br&gt;
99.66%&lt;br&gt;
11.9 min&lt;br&gt;
1.03×&lt;br&gt;
13&lt;br&gt;
15% overlap&lt;br&gt;
0.36 m&lt;br&gt;
100.00%&lt;br&gt;
13.4 min&lt;br&gt;
1.17×&lt;br&gt;
15&lt;br&gt;
30% overlap&lt;br&gt;
0.29 m&lt;br&gt;
100.00%&lt;br&gt;
15.8 min&lt;br&gt;
1.37×&lt;br&gt;
18&lt;br&gt;
Over-spaced&lt;br&gt;
0.55 m&lt;br&gt;
80.69%&lt;br&gt;
9.5 min&lt;br&gt;
0.83×&lt;br&gt;
10&lt;br&gt;
Random bounce, 1 charge&lt;br&gt;
—&lt;br&gt;
100.00%&lt;br&gt;
150 min&lt;br&gt;
13.68×&lt;br&gt;
1,507&lt;br&gt;
Random bounce, 3 charges&lt;br&gt;
—&lt;br&gt;
100.00%&lt;br&gt;
450 min&lt;br&gt;
41.20×&lt;br&gt;
4,277&lt;/p&gt;

&lt;p&gt;** &lt;br&gt;
Finding one: tangent lanes lose 0.34% of the floor to pinholes.&lt;br&gt;
99.66% sounds like rounding. It isn't. When lane centres sit exactly one swath apart, the brushes are tangent, and any raster cell on the boundary line between two lanes has a fighting chance of being missed. In the picture that shows up as a hairline of uncleaned floor every 42 cm — the "striped" look, at one-pixel width. In a real pool, a 1 cm strip is not a defect you can see. In a real pool with 3° of yaw drift and a slightly conical brush, it is.&lt;br&gt;
Finding two: 15% overlap costs 1.5 minutes and buys the last 0.34%.&lt;br&gt;
200.7 m of path instead of 177.3 m, 15 lane changes instead of 13, 13.4 minutes instead of 11.9. Sweep ratio goes from 1.03× to 1.17× — 17% more brush passes over the same floor. That is a cheap insurance policy against yaw drift, brush wear and a slightly out-of-square pool. 30% overlap buys nothing the 15% run didn't already have, and costs 2.4 more minutes plus 17% more brush passes over the floor. If you have to pick one number for a lane pitch, it is around 0.85 × swath, not 1.0.&lt;br&gt;
Finding three: over-spaced lanes are the only strategy that fails visibly, and it fails fast.&lt;br&gt;
0.55 m pitch finishes in 9.5 minutes — the fastest run in the table, 29% quicker than the 15% overlap case. It also misses 19.3% of the reachable floor in 19 cm stripes. This is the exact trade a manufacturer makes when the marketing number is "cleans your pool in 10 minutes", and it is why customers write emails about stripes. Fast, and visibly wrong.&lt;br&gt;
Finding four: random bounce reaches 100%, which is the least useful 100% in the table.&lt;br&gt;
The unplanned run covers every cell inside one 150-minute charge. It also sweeps 13.7 times the floor area to do it — 2,344 m driven, 1,507 wall nudges — which is 11× the runtime of a planned 13.4 minute run. So "coverage" alone cannot rank these strategies. Two numbers, not one: how much of the floor, and how much work per square metre. A lidar robot that plans lanes is not selling coverage. Coverage was never the hard part. It is selling the 1.17×.&lt;br&gt;
Bonus, because it surprised me: turning is 11% of the runtime.&lt;br&gt;
At 6 s per lane change, the 15% overlap run spends 90 of its 804 seconds rotating. On a 6 m width that is fine. Halve the pool width and the lane count barely changes; double it and you are spending a fifth of your battery on pirouettes. Lane pitch affects runtime twice — once through path length, once through lane count.&lt;br&gt;
Where the model lies&lt;br&gt;
I would rather list this than have someone in the comments list it for me.&lt;br&gt;
The drive is lossless. No slip, no wheel scrub on the tiles, no slowdown in the shallow end, no current. Real units lose 5–15% of nominal speed and lose most of it on turns.&lt;br&gt;
The swath is a perfect disk. Real suction mouths lose width at the edges and lose more when the filter is half-full. Effective width drops through a cycle.&lt;br&gt;
No dirt model. "Covered" means "the brush passed over it". Whether one pass removes algae film is a chemistry question I have no data for.&lt;br&gt;
Flat floor only. No slope, no steps, no main drain, no ladder. Wall climbing and waterline scrubbing are outside the raster entirely.&lt;br&gt;
The random run is friendly. 8 seconds between heading changes, no stalling in corners, no getting stuck on the drain cover. Real chaotic navigation is worse than this, so 13.7× is closer to a floor than a ceiling.&lt;br&gt;
One cycle, one direction. No multi-cycle accumulation, no slope-driven drift in the serpentine.&lt;br&gt;
Everything above is a constant at the top of the file. Change BOT["width"] to 0.28 and the whole table shifts; that is the point of writing it down instead of arguing about it.&lt;br&gt;
What I would add next&lt;br&gt;
Two things, in this order.&lt;br&gt;
First, yaw drift. Model the robot leaving each lane 2–3° off axis and let the error compound; that turns the pinhole problem from a raster artefact into a real stripe generator, and it will tell you whether 15% overlap is enough or whether you need 25%.&lt;br&gt;
Second, dirt-weighted coverage. Right now every square centimetre is worth the same. In reality the shallow end and the steps collect most of the debris, and a planner that spends its extra passes there is worth more than one that spends them evenly. That needs a weight map, which needs real pool data, which I do not have yet.&lt;br&gt;
Code, figures and the JSON output are all in one file, roughly 280 lines, numpy and matplotlib only:&lt;br&gt;
python pool_coverage_sim.py    # writes results.json + figures/&lt;/p&gt;

&lt;p&gt;If you build pool robots, the number I would like from you is not swath width. It is lane pitch, lane-change time, and whether the planner does an edge pass.&lt;/p&gt;

</description>
      <category>coding</category>
      <category>python</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Inside a Smart Cleaning Robot: Navigation, Sensors and App Control</title>
      <dc:creator>Adeline</dc:creator>
      <pubDate>Fri, 23 Oct 2026 13:41:25 +0000</pubDate>
      <link>https://dev.to/salgadous/inside-a-smart-cleaning-robot-navigation-sensors-and-app-control-3fno</link>
      <guid>https://dev.to/salgadous/inside-a-smart-cleaning-robot-navigation-sensors-and-app-control-3fno</guid>
      <description>&lt;p&gt;A robot that climbs a window, maps a pool or scrubs a floor looks like a single black box from the outside. From the inside, it is a small embedded system built from four layers — sensing, navigation, execution and communication — plus the safety and power systems that hold them together. This is a developer's breakdown of how those layers work, and why the engineering choices in each one are what separate a robot that gets used from one that gets shelved.&lt;br&gt;
A note on scope and security. This post covers general engineering principles only. None of the code or diagrams below are real product implementations — there are no real protocols, API endpoints, keys, firmware details, or security configurations here, and it is not a guide to controlling any specific device. It is written for developers who build or evaluate such systems. (The author works with stonebotclean, a cleaning-robot manufacturer; the hardware references are general and illustrative.)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The sensing layer: how the robot knows where it is
A cleaning robot cannot do anything useful until it knows its surroundings. The sensing stack is usually a combination of:
Edge / drop sensors — short-range infrared or ToF sensors pointing at the surface the robot rides on. For a window robot, this detects the pane edge and stops the unit from driving off the glass. For a floor robot, it prevents a fall down stairs.
IMU (gyroscope + accelerometer) — orientation and tilt. Essential for a window robot to know it is still flat against the glass, and for a pool robot to know it has not flipped over.
Laser / ToF ranging — measures distance to a wall, an obstacle or a pane frame, for edge detection and mapping.
Odometry from wheel encoders — measures how far each drive has travelled, so the robot can estimate position between sensor updates.
The budget trade-off is real: cheap robots often ship only edge sensors and a gyro, which forces a random-bounce strategy. Adding a ToF or LiDAR sensor is what unlocks mapping.&lt;/li&gt;
&lt;li&gt;Navigation: from random bounce to a cleaning plan
Navigation is where the "smart" happens, and the spectrum is wide:
Random bounce — bounce off walls until the coverage seems done. Simple, cheap, no map, but it wastes time and misses corners.
Systematic sweep (boustrophedon) — travel in parallel lanes, turn at the edge, move to the next lane. Deterministic and effective for simple, flat surfaces. A window pane is a great fit for this:
# Generic textbook algorithm (illustrative only — not product code)
def boustrophedon(width, lane_step):
x = 0
direction = 1
path = []
while x &amp;lt; width:
    path.append((x, direction))     # one full pass across the pane
    x += lane_step
    direction *= -1                  # reverse on the next lane
return path&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SLAM (Simultaneous Localization and Mapping) — build a map while localising within it, usually with LiDAR or vision. This is how a floor robot covers a whole home without repeating rooms, and it is what makes "no-miss coverage" claims possible.&lt;br&gt;
For a pool robot, navigation is closer to the sweep model plus wall-tracking: climb the walls, scrub the waterline, then cover the floor in lanes. The hard part is not path planning but localising in water — odometry and pressure sensing matter more than lidar.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The execution layer: climbing, scrubbing and moving
The actuators turn the plan into clean:
Negative-pressure suction is what lets a window robot climb vertical glass. The motor draws air between the pad and the pane; the pressure differential holds the unit on. The rating in pascals matters — a higher rating means the robot can hold on through more load and larger panes.
Scrubbing — a rotating brush or roller, a spray of water or solution, and a vacuum or pump to lift the dirty water back out. Wet-dry vacuums and upholstery cleaners share this spray-and-suction architecture.
Drive motors — two driven wheels (differential drive) for steering, plus a pump or propeller on pool robots.
The execution layer is also where dirt actually leaves the surface, which is why suction and brush design do more for real-world results than the navigation spec.&lt;/li&gt;
&lt;li&gt;Communication and app control
Modern robots talk to a phone through Wi-Fi or BLE, and the app layer is where a lot of the product experience lives — pairing, schedules, cleaning maps, battery, OTA updates.
We deliberately do not show any real control frames or wire format here. In broad terms, app control works through the interfaces the manufacturer exposes and supports — typically a cloud channel over Wi-Fi (often MQTT or a REST/WebSocket API) with a local BLE fallback so the robot still works without internet. The exact protocols, endpoints and authentication mechanisms are outside the scope of this post and are not public material.
From a developer's standpoint, the interesting engineering is in the state machine rather than the wire format — scheduling, low-power sleep, safe cancellation of a cleaning cycle mid-run, and how the app reflects the robot's real state instead of a guess. Authentication and secure pairing belong to the manufacturer's platform, not to a public engineering overview.&lt;/li&gt;
&lt;li&gt;Safety and power
Two systems keep a cleaning robot usable rather than alarming:
Safety — a physical tether on high-rise window robots, drop/edge sensors, IP ratings for water exposure (essential on pool robots and wet vacuums), and overload detection on the motors.
Power — battery management plus an auto-dock. A robot that returns to a charge dock and starts again on its own is far more likely to be used weekly than one that needs manual recharging. For pool robots, cordless autonomy is the trend — a full cycle on one charge is now the baseline buyers expect.&lt;/li&gt;
&lt;li&gt;Why it matters when you source or build one
These four layers are why two products that look alike can differ completely in real use. When we build cleaning robots for wholesale and OEM customers, the decisions that matter are the same ones above: which sensors to spend on, whether the navigation is mapping or sweep, how the app reflects real robot state, and how safely the unit handles an edge, a puddle or a fall. A robot that nails execution and safety — even with simple navigation — beats one with a fancy map and weak suction every time.
Wrap up
A smart cleaning robot is an embedded system wearing a cleaning product's body. Understand the sensing, navigation, execution, communication, safety and power layers, and you can tell at a glance whether a spec sheet is marketing or engineering.
If you are building or sourcing one, the questions worth asking are the same in every category: how does it detect edges, does it map or sweep, how does the app talk to it, and what happens when it runs into something it was not expecting.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
