Skip to main content

Command Palette

Search for a command to run...

Giving My Robot Its First Sense: HC-SR04 Ultrasonic on Arduino UNO Q

Part 2 of "Building an Eldercare Robot" — HC-SR04 ultrasonic distance sensing via the MCU-MPU Bridge

Published
6 min read
Giving My Robot Its First Sense: HC-SR04 Ultrasonic on Arduino UNO Q
A

I'm Ashish Disawal, a DevOps Trainer and Consultant with over 17 years of experience building and optimizing infrastructure across Healthcare, Digital Media, IT, and Analytics industries. I help organizations worldwide transform their development and deployment practices through automation, security, and cloud-native technologies.

Currently working as a freelance consultant, I specialize in designing secure, scalable infrastructure solutions using Kubernetes, Docker, AWS, Python, and Infrastructure as Code tools. My recent projects include implementing multi-tenant ML processing infrastructures, automating incident management workflows between ServiceNow and PagerDuty, and migrating Python-based SaaS applications to Kubernetes on AWS EKS.

Throughout my career, I've led high-performing teams and achieved significant results—from reducing Azure infrastructure costs by over 50% to building 20-member support teams from scratch. I'm particularly passionate about Slack administration and SaaS integrations, having developed custom workflows, bots, and apps that streamline team collaboration.

I hold multiple certifications including AWS Certified Developer - Associate, Certified Kubernetes Security Specialist, and ITIL Foundation. I've played pivotal roles in achieving and maintaining SOC2, HIPAA, and ISO 27001 compliance for organizations, implementing comprehensive security stacks and CI/CD pipelines with integrated security scanning.

Beyond consulting, I'm committed to knowledge sharing through my technical blog at PraHari.net, where I write about FastAPI, Kubernetes, AWS, and DevOps best practices. I believe in fostering collaborative environments, mentoring aspiring DevOps professionals, and aligning technical solutions with business objectives to deliver exceptional results.

In the last post, I got the Arduino UNO Q working from the command line — blink LED, SSH, deploy apps.

Now it's time to give the board its first real input: distance sensing with an HC-SR04 ultrasonic sensor. This is the sensor that will eventually let my eldercare robot detect walls, furniture, and doorways as it patrols a home.

But first — can pulseIn() even work on Zephyr RTOS?

Why This Matters

HomeGuard Parivaar needs to navigate rooms autonomously. That means obstacle detection. The HC-SR04 is the cheapest, most reliable way to measure distance — if it works on the UNO Q's STM32 MCU running Zephyr.

The interesting part isn't the sensor itself (it's well-documented everywhere). It's the pattern:

  • The MCU reads the sensor in its own tight loop

  • The Python side on the MPU polls for data via Bridge whenever it needs it

  • Neither side blocks the other

This decoupled architecture is how all of the robot's sensors will work.

What We're Building

By the end of this post, you'll have:

  • An HC-SR04 wired to the UNO Q's MCU pins

  • A sketch that reads distance continuously and exposes it via Bridge

  • A Python script that polls and prints distance readings

  • Confidence that timing-sensitive Arduino functions work under Zephyr

Hardware You'll Need

Component Notes
Arduino UNO Q CLI setup complete (see Part 1)
HC-SR04 ultrasonic sensor ~$2, widely available
4x jumper wires (F-M) VCC, GND, TRIG, ECHO

I used a breadboard to keep the wiring tidy.

Wiring

HC-SR04 Pin UNO Q Pin
VCC 5V
GND GND
TRIG D2
ECHO D3

No voltage divider needed. The STM32U585's digital pins are 5V tolerant (except A0/A1 — a detail from Lab 1.1 that saved me a resistor here).

The App Structure

Same pattern as the blink app from Part 1 — an app.yaml, a sketch folder, and a Python folder:

q-sonar/
├── app.yaml
├── sketch/
│   ├── sketch.ino
│   └── sketch.yaml
└── python/
    ├── main.py
    └── requirements.txt

The MCU Sketch

The MCU does two things:

  • Reads the sensor in loop() every 100ms

  • Exposes the last reading via a Bridge function

#include "Arduino_RouterBridge.h"

const int TRIG_PIN = 2;
const int ECHO_PIN = 3;

float last_distance_cm = -1.0;

void setup() {
    pinMode(TRIG_PIN, OUTPUT);
    pinMode(ECHO_PIN, INPUT);
    Bridge.begin();
    Bridge.provide("get_distance", get_distance);
}

void loop() {
    last_distance_cm = read_distance();
    delay(100);
}

float read_distance() {
    digitalWrite(TRIG_PIN, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG_PIN, LOW);

    long duration = pulseIn(ECHO_PIN, HIGH, 30000);  // 30ms timeout
    if (duration == 0) {
        return -1.0;  // No echo — out of range
    }
    return duration * 0.0343 / 2.0;  // cm
}

float get_distance() {
    return last_distance_cm;
}

A few things to note:

  • pulseIn() with a 30ms timeout — this caps the max range at ~5 meters (plenty for indoor rooms) and prevents the sketch from hanging if nothing echoes back.

  • 0.0343 / 2.0 — speed of sound in cm/us, divided by 2 because the pulse travels to the object and back.

  • The loop() is NOT empty this time. Unlike the blink app where the MCU just waited for Bridge calls, here the MCU actively samples the sensor. The Bridge function get_distance() just returns the latest cached reading.

The Python Side

from arduino.app_utils import *
import time

def loop():
    distance = Bridge.call("get_distance")
    if distance < 0:
        print("No echo — out of range")
    else:
        print(f"Distance: {distance:.1f} cm")
    time.sleep(1)

App.run(user_loop=loop)

The Python side polls once per second. The MCU samples 10x per second.

This means the Python side always gets a fresh reading without needing to worry about sensor timing.

Deploy and Run

# Copy app to the board
ssh arduino-2gb 'mkdir -p ~/ArduinoApps/q_sonar'
scp -r q-sonar/* arduino-2gb:~/ArduinoApps/q_sonar/

# Start it
ssh arduino-2gb 'arduino-app-cli app start ~/ArduinoApps/q_sonar'
App compile, flash, and start

Check the logs:

ssh arduino-2gb 'arduino-app-cli app logs ~/ArduinoApps/q_sonar'
Distance: 46.3 cm
Distance: 137.2 cm
Distance: 44.6 cm
Distance: 48.0 cm
Distance: 17.1 cm
Distance: 138.9 cm
App logs showing distance readings

Move your hand in front of the sensor — near readings (17cm) and far readings (137cm to the wall) both respond correctly.

What Surprised Me

1. pulseIn() works perfectly on Zephyr. This was my main concern going in. Timing-sensitive functions can behave unpredictably under an RTOS, but the Arduino Zephyr core handles it cleanly. No jitter, no missed pulses.

2. I wired it wrong first. TRIG and ECHO were swapped. The sketch deployed fine, but every reading came back as "No echo — out of range."

I spent a few minutes reading the code looking for a Zephyr compatibility issue... when it was just two wires in the wrong pins. Check your wiring before debugging your code.

3. No external libraries needed. HC-SR04 only uses digitalRead, digitalWrite, and pulseIn — all built into the Arduino core for Zephyr. The only dependency is Arduino_RouterBridge for the Bridge pattern.

4. The MCU loop + Bridge pattern is the right architecture. The MCU samples at its own pace. The Python side reads when it needs to. Neither blocks the other.

This is exactly how the robot will work — the MCU manages real-time sensor reads, the MPU handles decision logic. One pattern, many sensors.

What's Next

The sensor works. The Bridge pattern works.

Next up: connecting a USB webcam to the MPU's Linux side — giving the robot eyes to go with its sonar. After that, bridging sensor data and camera feeds together for the robot's perception layer.

Follow along as I build an eldercare robot, one sensor at a time.


This is part of my journey building HomeGuard Parivaar — an autonomous eldercare robot for Indian families, built with Arduino UNO Q.

This is a hobby project and I'm learning by building. If you have suggestions, corrections, or criticism — I'd genuinely love to hear it.

Co-authored with Claude Code (Anthropic) — my AI pair-programming partner for this build. Cover image generated with Gemini (Google).

Building an Eldercare Robot

Part 2 of 3

Building HomeGuard Parivaar — an autonomous home health robot for Indian families, powered by Arduino UNO Q and edge AI.

Up next

Arduino UNO Q is NOT a Regular Arduino: What I Learned the Hard Way

Part 1 of "Building an Eldercare Robot" — Setting up the Arduino UNO Q for CLI development