element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
EZ-EV Challenge
  • Challenges & Projects
  • Design Challenges
  • EZ-EV Challenge
  • More
  • Cancel
EZ-EV Challenge
Forum hall-w-EV - Post 5 - Chase ball
  • News
  • Projects
  • Forum
  • DC
  • Leaderboard
  • Files
  • Members
  • More
  • Cancel
  • New
Join EZ-EV Challenge to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 0 replies
  • Subscribers 59 subscribers
  • Views 15 views
  • Users 0 members are here
  • yolo
  • YOLOX-Nano
  • uno q
  • Ball chase
Related

hall-w-EV - Post 5 - Chase ball

tamadillo
tamadillo 2 hours ago

Hi again, it’s Hambreros and Tamadillo. Last post gave it eyes. This one gives it something to do with them: place a tennis ball Tennis in front of it and the robot drives itself towards it, no hands.

What we’ve actually built

A Tennis CHASE toggle next to the joystick. Flip it on, and:

  • The robot looks for a ball in the camera feed.
  • Off-center → it turns towards it.
  • Small (far away) → it drives forward. Big enough (close) → it eases off and stops.
  • Ball out of frame → it just stops, same as letting go of the joystick.
  • Manual controls (joystick, keyboard, per-wheel sliders) go greyed-out and unresponsive while this is on, so nothing’s fighting the robot for the wheel. The ⏻ MOTOR ON/OFF buttons still work regardless — always an independent kill switch, whoever’s driving.

Finding the right brick

Same move as every other feature so far: before writing a line of code, went and read arduino/app-bricks-py to see what already exists. Turns out there’s a whole family of vision bricks — gesture_recognition, mood_detector, image_classification, object_detection, visual_anomaly_detection — and the one that actually fits is video_objectdetection: continuous detection off a live camera stream, with per-label callbacks carrying a confidence score and a bounding box.

Its brick_config.yaml lists:

model_by_boards:
    - platform: ventunoq
      model: yolox-qnn-object-detection
    - platform: unoq
      model: yolox-object-detection

UNO Q — this exact board. Not a VENTUNO-only NPU thing, unlike the neural TTS detour a couple posts back. Genuinely usable here.

No training required — just check the label list

The obvious worry: does a generic pretrained model know what a tennis ball is? Didn’t want to assume, so went and checked models/models-list.yaml in the same repo before writing any detection code — it’s a YOLOX-Nano model trained on COCO’s 80 classes, and the label list includes, verbatim:

- sports ball

That’s the actual class name (there’s no separate “tennis ball” class in COCO, but “sports ball” covers it — it’s the canonical example object for that class in the dataset). So: zero custom training, zero Edge Impulse model work. Just register a callback for a class that’s already in the box.

from arduino.app_bricks.video_objectdetection import VideoObjectDetection

detector = VideoObjectDetection(camera=shared_camera, confidence=0.5)
detector.on_detect("sports ball", on_ball_detected)
detector.start()

One camera, two features fighting over it

video_objectdetection wants its own Camera to forward frames to the detection sidecar. We already have one open, for last post’s live feed. Tried to hand-wave past this and it immediately mattered: Camera claims its physical device the moment it’s constructed — there’s an actual registry in the framework’s own source specifically so auto-selection doesn’t grab something already in use — so a second, independent Camera("usb:0", ...) for the same webcam wouldn’t just contend for bandwidth, it’d fail outright.

Good thing VideoObjectDetection(camera=...) takes an existing instance instead of always making its own. Added a small accessor to camera.py:

def get_camera():
    """Blocks until the startup attempt above has settled, then returns the
    shared Camera instance — or None if it never started successfully."""
    _ready.wait()
    return _camera

vision.py calls that instead of constructing its own, so both features share the one physical connection to the one webcam instead of racing for it.

Steering is just proportional control

No path planning, no PID tuning, nothing fancy — just “how far off-center is it” and “how big is it,” recomputed fresh on every detection message:

PID - Proportional Kp, Integral Ki, and Derivative Kd, only recently saw this video from Electronoobs and it looks complicated 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

def _steer_towards(bbox):
    x1, y1, x2, y2 = bbox
    frame_w, frame_h = camera.RESOLUTION
    center_x = (x1 + x2) / 2
    box_h    = max(1, y2 - y1)

    offset     = (center_x - frame_w / 2) / (frame_w / 2)  # -1 .. +1
    size_ratio = box_h / frame_h                             # 0 .. 1

    turn     = max(-100, min(100, offset * TURN_GAIN))
    throttle = max(0, min(MAX_THROTTLE,
                          (TARGET_SIZE_RATIO - size_ratio) / TARGET_SIZE_RATIO * MAX_THROTTLE))
    return turn, throttle

turn/throttle go through the exact same mix_drive() the joystick posts through from two posts ago — one function, one place that knows how a turn+throttle pair becomes two wheel speeds, whether a human or a neural network produced them. MAX_THROTTLE is capped well under full speed on purpose — this thing drives itself with nothing watching for obstacles, no reason to let it move at joystick speeds.

What actually broke on real hardware

First real test went nowhere: App.run() never scheduled VideoObjectDetection’s background loops, since the brick got built (on its own thread, after App.run() had already started) too late for the scheduler to notice — confirmed by the sidecar sitting there waiting for a connection that never came. Fixed by just running those two loops ourselves in plain daemon threads instead.

Seeing what it’s actually seeing

Once frames were flowing, the ball’s box kept flickering against other objects (a bed, a cup) even on a dead-static scene — turned out to be real per-frame confidence noise, not a “one object at a time” limitation (it’s a genuine multi-object detector, and no, it can’t be restricted to only look for balls — fixed 80-class model, no filter option). Fix: draw a box for everything it sees, not just the ball, and fade them out over a few seconds instead of hard-cutting the instant one frame doesn’t reconfirm them.

The “lost the ball” behavior that didn’t need writing

Didn’t need a lost-ball timeout — Post 1’s STM32 watchdog already stops the wheels when commands stop arriving, same as a dropped wifi connection, for free.

It worked — and then drove straight past the ball

Reacting to every single detection message overshot the ball almost every time — no braking distance. Fixed by pulsing instead: one short move, stop, pause, then decide again from a fresh look — and VideoObjectDetection’s own per-label lock already discards anything that arrives mid-pause, so no new state machine was needed to make that stick.

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

What’s next

Well that’s kind of it. Thrilled at how far we got to an actual auto driving EV.

The codes

  • https://github.com/tamadillo/hall-w-EV

— Hambreros (and Tamadillo)

  • Sign in to reply
  • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube