-
Notifications
You must be signed in to change notification settings - Fork 0
Eyes
- Introduction
- Reading the distance
- Asking questions instead
- Out of range
- The median filter
- Timing
- Going lower: the Ultrasonic module
Eyes is the HC-SR04 ultrasonic distance sensor -- the two cylinders that look like eyes. It is a facade over the Ultrasonic module.
long cm = Eyes::distanceCm();The sensor measures the distance to the nearest surface directly in front of Otto. It sees walls, hands, and furniture; it is poor at soft fabric, thin chair legs, and anything at a steep angle, because those scatter the echo away.
void loop() {
long cm = Eyes::distanceCm();
Serial.println(cm);
delay(100);
}The value is in centimetres, already median filtered. Practical range for the HC-SR04 is roughly 3 cm to 200 cm; below about 3 cm the echo returns before the sensor is listening.
Most sketches do not want the number, they want a decision. These read as sentences and are the preferred form:
if (Eyes::closerThanCm(15)) Legs::walkBackward(2);
if (Eyes::fartherThanCm(50)) Legs::walkForward(1);Each call takes its own fresh reading. If you need one reading used in several comparisons -- including for consistency -- read it once:
long cm = Eyes::distanceCm();
if (cm < 15) Mouth::show(Icon::Surprised);
else if (cm < 40) Mouth::show(Icon::Confused);
else Mouth::show(Icon::Happy);When nothing sends back an echo, the reading is Eyes::OUT_OF_RANGE_CM, which is 999.
long cm = Eyes::distanceCm();
if (cm >= Eyes::OUT_OF_RANGE_CM) {
Serial.println(F("nothing in front"));
}This matters for fartherThanCm(): an open room and a disconnected sensor both report "far away". If a wiring fault would be dangerous for your behaviour, compare against OUT_OF_RANGE_CM explicitly.
Ultrasonic sensors produce occasional wild readings -- a stray echo, a reflection off the floor. A single spike can make a robot jump backwards for no reason.
distanceCm() therefore takes several readings and returns the median, which discards outliers without smearing real changes the way an average does. It is on by default with three samples:
OttoConfig cfg;
cfg.ultrasonic.medianFilter = true; // default
cfg.ultrasonic.samples = 5; // 1..5, steadier but slower
OttoFlow::start(cfg);Setting samples = 1, or medianFilter = false, gives you the raw single reading -- fastest, noisiest.
Every reading is a real physical measurement and takes real time. A ping waits up to config.ultrasonic.timeoutMicros (25 ms by default) when nothing answers, and the filter adds a 5 ms settling delay between samples.
With the defaults, a distanceCm() call costs a few milliseconds when something is nearby and up to about 85 ms when nothing is in range. That is the price of the filter -- turn samples down if your loop needs to be quicker.
Note Movement calls block too. While
Legs::walkForward(2)is running, Otto is not looking at anything. Non-blocking motion is on the Roadmap; until then, alternate short movements with sensor checks.
long raw = Ultrasonic::readSingleCm(); // one unfiltered reading
unsigned long us = Ultrasonic::echoMicros(); // raw pulse width, 0 = timeoutechoMicros() is the honest bottom layer: the pulse width returned by pulseIn(). Centimetres are that value divided by 58. Use it when you want your own filtering, or when debugging a sensor you suspect is miswired -- a permanent 0 means no echo ever comes back.
OttoFlow is licensed under GPL-3.0 and wraps OttoDIYLib. Buy the kits at ottodiy.com.
Prologue
Getting Started
The Basics
Digging Deeper
- Bench Testing
- Serial Console
- Calibration
- Bluetooth and the Otto App
- Modules
- The Driver
- Extending OttoFlow
Reference