Skip to Content
BonicBot A2DevelopmentArtificial IntelligenceLesson 1: Teaching BonicBot to See

Lesson 1: Teaching Your Robot to See

Learning Objective

Connect to your BonicBot, turn on its camera, and get the robot to detect and report one object it currently sees using the built-in YOLO detector.

Introduction

Every BonicBot program starts the same way: connect to the robot, wake up its camera, and ask it what it sees. In this lesson, you’ll write the shortest possible program that does exactly that — using the robot’s built-in YOLO object detector, a computer vision model that recognizes 80 everyday object categories like “person,” “chair,” and “bottle,” without you training anything yourself. Object detection is the foundation of almost every CV project in this course: robots that follow people, sort objects, or react to their surroundings all start with a call like the one you’re about to make. By the end of this lesson, your BonicBot will look at the world and hand you back one concrete piece of information about what’s in front of it.

Setup: Installing Packages

Before running the code, make sure your computer has the required Python packages installed. Open a terminal and run:

pip install bonicbot-bridge opencv-python numpy

What each package does

PackagePurpose
bonicbot-bridgeThe official BonicBot SDK. Provides the BonicBot class used to connect to the robot, control its camera, and read detection results.
opencv-pythonImported as cv2. Used here to draw bounding boxes on frames, display the live video window, and listen for the q keypress to quit.
numpyImported as np. Used for array/image handling that opencv-python and bonicbot-bridge rely on internally.

If pip install fails, try pip3 install ... instead, or use a virtual environment:

python3 -m venv bonicbot-env source bonicbot-env/bin/activate # On Windows: bonicbot-env\Scripts\activate pip install bonicbot-bridge opencv-python numpy

Don’t have a physical BonicBot? Try it in simulation (optional)

If you don’t have physical access to a BonicBot, you can still work through this lesson using the ROS 2 simulation environment instead of a real robot:
  1. Launch the BonicBot simulation:

    ros2 launch my_bot robot_system.launch.py use_sim_time:=true world:=obsworld.sdf use_real_camera:=True
    • use_real_camera:=True — the camera feed comes from your laptop’s webcam, while the robot’s body and motion are still simulated. This is the easiest way to test detection, since you can just hold whatever you want detected up to your laptop camera.
    • use_real_camera:=False — the camera feed comes from Gazebo instead (i.e. whatever the simulated camera sees inside the simulated world).
  2. Once the simulation is running, use localhost as the host instead of a physical IP address:

    with BonicBot(host="localhost") as bot:
  3. Everything else in the code — enabling face detection, drawing boxes, reading bot.get_faces() — works the same way, since the simulation exposes the same interface as a real robot. This path is mainly useful for exploring the lesson without hardware on hand; if you have a real BonicBot, connecting to its actual IP address is the recommended way to go through this lesson.

Code

Click to view the complete program

import time import cv2 import numpy as np from bonicbot_bridge import BonicBot def draw_detections(frame, detections): h_px, w_px = frame.shape[:2] for det in detections: bbox = det.get("bbox") if not bbox or len(bbox) < 4: continue # Pipeline publishes normalised [cx, cy, w, h] (0-1) cx_n, cy_n, bw_n, bh_n = bbox x1 = max(0, int((cx_n - bw_n / 2) * w_px)) y1 = max(0, int((cy_n - bh_n / 2) * h_px)) x2 = min(w_px - 1, int((cx_n + bw_n / 2) * w_px)) y2 = min(h_px - 1, int((cy_n + bh_n / 2) * h_px)) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) label = f"{det.get('class', '?')} {det.get('confidence', 0.0):.0%}" cv2.putText(frame, label, (x1 + 2, y1 - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) return frame with BonicBot(host='[IP_ADDRESS]') as bot: print("📷 Starting camera and streaming...") bot.system.start_camera() bot.start_camera() bot.camera.wait_for_image(timeout=5.0) print("🚀 Starting YOLO detection mode...") bot.enable_detection("yolo") # Wait for RPi to load the model and confirm YOLO is active while not bot.vision.yolo_enabled: time.sleep(0.1) print("✅ Live Stream Active. Press 'q' to quit.") while True: frame = bot.get_image() if frame is not None: detections = bot.vision.get_detections() display = draw_detections(frame.copy(), detections) cv2.imshow("BonicBot Vision", display) if cv2.waitKey(1) & 0xFF == ord("q"): break cv2.destroyAllWindows() bot.disable_detection() bot.stop_camera() bot.system.stop_camera()

Replace [IP_ADDRESS] with the IP address of your own BonicBot. Every BonicBot may have a different IP address depending on your network configuration.

📌 Example:

with BonicBot(host="172.20.10.2") as bot:

Replace 172.20.10.2 with the IP address assigned to your BonicBot.

Code Walkthrough

Line-by-line explanation

  • Importstime is used to pause briefly while waiting for YOLO to load; cv2 (OpenCV) handles drawing and displaying video; numpy supports the underlying image arrays; BonicBot is the SDK class that talks to the robot.
  • draw_detections(frame, detections) — Takes a raw camera frame and the list of detections, then draws a green rectangle and a text label (class name + confidence percentage) for each detected object. Coordinates arrive normalized (0–1), so the function converts them to actual pixel positions using the frame’s width and height before drawing.
  • with BonicBot(host='[IP_ADDRESS]') as bot: — Opens a connection to your robot. Using with ensures the connection is cleanly closed even if the program crashes or is interrupted.
  • bot.system.start_camera() / bot.start_camera() / bot.camera.wait_for_image(timeout=5.0) — Purpose of this block: Initializes the robot connection context, powers on the camera hardware, starts streaming live video frames over the bridge, and waits up to 5 seconds for the first valid image frame before moving forward.
  • bot.enable_detection("yolo") — Tells the robot to load and activate its YOLO object-detection model.
  • while not bot.vision.yolo_enabled: time.sleep(0.1) — Loops in short 0.1-second waits until the robot confirms the YOLO model has finished loading and is active.
  • Main while True loop — Continuously grabs the latest frame, fetches the current list of detections, draws boxes/labels on a copy of the frame, and shows it in a window named “BonicBot Vision”.
  • cv2.waitKey(1) & 0xFF == ord("q") — Checks every loop iteration whether the q key was pressed; if so, the loop breaks and the program moves to cleanup.
  • Cleanup (cv2.destroyAllWindows(), bot.disable_detection(), bot.stop_camera(), bot.system.stop_camera()) — Closes the video window, turns off YOLO detection, and shuts down the camera stream so the robot isn’t left running unnecessarily.

Expected Output

Click to see expected output

Visual Output:

Terminal Output:

{'class': 'person', 'confidence': 0.91, 'bbox': [0.52, 0.44, 0.18, 0.36]}

Your exact numbers will differ based on what’s in front of the camera. bbox is normalized [cx, cy, w, h] (0–1 range), so [0.52, 0.44, 0.18, 0.36] means roughly centered, slightly right and up. If nothing is in frame, you’ll see Nothing detected yet instead.

🔧 Under the Hood

How does object detection actually work?

YOLO (“You Only Look Once”) is a family of models that scan an entire image in a single pass through a convolutional neural network, rather than sliding a window across the image and checking each spot separately. The network divides the image into a grid, and for each grid cell it predicts candidate bounding boxes, a confidence score, and class probabilities all at once. Overlapping boxes for the same object are then cleaned up with a step called non-max suppression, which keeps only the highest-confidence box and discards duplicates. YOLO models are typically trained on the COCO dataset, which is where the 80 object classes come from.

This explains the general, publicly documented YOLO architecture — it does not describe bonicbot-bridge’s exact internal pipeline (thresholds, pre/post-processing choices, etc.), which isn’t publicly documented beyond the model='yolov8n' default parameter you can pass to enable_detection().

Student Challenge

bot.get_detections() accepts an optional class_filter argument. Change the code to bot.get_detections(class_filter='person') so the robot only reports people, ignoring every other object class. Run it while pointing the camera at different objects — when does the printed message change?

Hint

class_filter takes a string matching one of the 80 COCO class names — try 'person', 'chair', or 'bottle'.

Reflection Question

Your program printed a confidence score along with the detected class. Why might a robot need a confidence number instead of a simple yes/no answer for “is this a person”? What could go wrong if the robot acted on every detection, even ones with very low confidence?

Last updated on