跳到正文
原文
Hacker News 热门(buzzing.cc 中文翻译)· gvuksic·· 2 小时前AI 评分43

JBR-001:基于 Arduino UNO Q 的开源可 3D 打印桌面机器人

Show HN: JBR-001——一款开源的、可3D打印的桌面机器人

AI 导读

JBR-001 是一款基于 Arduino UNO Q 的开源、可 3D 打印桌面陪伴机器人,集摄像头、距离传感器、蜂鸣器、动画显示屏和三个舵机于一体,可支持计算机视觉与边缘 AI 实验。其 STL 文件已开放下载,用户可自行打印、组装和编程扩展。

正文

Projects

Featured

Robotics Hub

Dragonwing Hub

FAQ

  • NEW PROJECT

Image 1: btn-search

Image 2: btn-logo

Image 3: login-logo

Image 4: btn-search

Image 5: btn-logo

Image 6: login-logo

Projects

Featured

Robotics Hub

Dragonwing Hub

FAQ

  • NEW PROJECT

More

JBR-001: A Desktop Companion Robot Powered by Arduino UNO Q

JBR-001 is an open-source desktop companion robot powered by the Arduino® UNO™ Q and built to make robotics, computer vision, edge AI, and physical AI fun to explore.

Jul 19, 2026

• 37724 views

• 5 respects

•

CC0 1+

Embedded

Robots

Internet Of Things

Image 7: Image

Devices & Components

1Image 8

Arduino® UNO™ Q 2GB

1Image 9

Modulino™ Distance

1Image 10

Modulino™ Motors

1Image 11

Modulino™ Buzzer

1Image 12

Arduino USB-C Hub (8 in 1)

Hardware & Tools

1

Desktop 3D Printer

Software & Tools

Image 13

Arduino App Lab

Project description

Introduction

JBR-001 is an open-source, 3D-printable desktop companion robot powered by the Arduino® UNO™ Q.

We designed JBR-001 as a small platform for experimenting with robotics, physical interaction, edge AI, and computer vision. It combines a camera, distance sensing, sound, an animated display, and three servo motors in a compact robot that you can print, assemble, program, and extend yourself.

Image 14: JBR-001 - Desktop Companion Robot

JBR-001 - Desktop Companion Robot

The robot can greet you by moving its arms and head, play sounds, animate its display, sense nearby objects using a distance sensor, and use its camera for computer vision applications running on the Arduino UNO Q.

Video 1

How It Works

At the center of JBR-001 is the Arduino UNO Q. It controls the robot's display, sensors, buzzer, and servo motors, while also providing the computing capabilities needed for more advanced applications such as computer vision.

JBR-001 uses three servo motors to create movement. One controls the head, while the other two control the left and right arms.

A distance sensor located at the back of the head allows JBR-001 to detect nearby objects behind it. The buzzer provides simple audio feedback, while the integrated display gives JBR-001 its animated face and heartbeat.

The camera adds another level of interaction, allowing the robot to go beyond simple distance sensing and respond to what it sees.

The three servo motors use an external power supply rather than drawing their power directly from the Arduino UNO Q. The external power supply and the UNO Q share a common ground, allowing the control signals from the board to reliably control the servos.

The camera and Arduino UNO Q are connected through a USB-C hub.

Image 15: JBR-001 - Wiring and Connections

JBR-001 - Wiring and Connections

Main connections

  1. Head servo - pin 9
  2. Left arm servo - pin 10
  3. Right arm servo - pin 11
  4. Three servos - external power supply
  5. External power supply ground - Arduino UNO Q ground
  6. Modulino Distance - Modulino Buzzer
  7. Modulino Buzzer - Arduino UNO Q
  8. Arduino UNO Q - USB-C hub
  9. Camera - USB-C hub

Important: Do not power all three servo motors directly from the Arduino UNO Q. Use a suitable external power supply for the servos and connect the grounds of the external supply and UNO Q together.

Assembling the JBR-001

One of the goals behind JBR-001 was to make the robot something you could build yourself. The body is made from 3D-printable parts, with the electronics and servos installed directly inside the printed structure.

You will need:

  1. Arduino UNO Q
  2. Camera
  3. Modulino Distance
  4. Modulino Buzzer
  5. Three servo motors
  6. External power supply for the servos
  7. USB-C hub
  8. JBR-001 3D-printed parts
  9. Cables, screws, and mounting hardware
  10. All 3D-printable STL files for JBR-001 can be found $here $.

Start by printing the JBR-001 components and assembling the main body. Install the servo motors as you assemble the head and arms so that their shafts align correctly with the moving parts.

The head servo provides horizontal movement, while one servo inside each side of the body controls an arm.

Once the mechanical parts are assembled, install the Arduino UNO Q and route the servo, sensor, camera, and power cables through the body. Keeping the wiring organized at this stage makes closing the robot considerably easier.

The camera is installed in the head, giving it a forward-facing view of the environment.

The distance sensor is positioned so that JBR-001 can detect someone approaching from the back.

For a complete walkthrough of the mechanical assembly, watch the assembly video below, where Goran and Nenad explain it step by step.

Video 2

Bringing the Head Display to Life

The display is one of the simplest ways to give JBR-001 some personality.

When the robot is idle, it displays a heart that continuously pulses between two sizes. This creates a subtle heartbeat animation and gives the robot a visual indication that it is running even when nothing else is happening.

The animation is created using two small bitmap representations of the heart: a larger heart and a smaller one.

// Small heart - flipped to match display orientation``uint8_t heartSmall[8][13] = {``{0,0,0,0,0,0,0,0,0,0,0,0,0},``{0,0,0,0,0,1,1,1,0,0,0,0,0},``{0,0,0,0,1,1,1,1,1,0,0,0,0},``{0,0,0,1,1,1,1,1,1,1,0,0,0},``{0,0,1,1,1,1,1,1,1,1,1,0,0},``{0,0,1,1,1,1,0,1,1,1,1,0,0},``{0,0,0,1,1,0,0,0,1,1,0,0,0},``{0,0,0,0,0,0,0,0,0,0,0,0,0}``};``// Large heart - flipped to match display orientation``uint8_t heartLarge[8][13] = {``{0,0,0,0,1,1,1,1,1,0,0,0,0},``{0,0,0,1,1,1,1,1,1,1,0,0,0},``{0,0,1,1,1,1,1,1,1,1,1,0,0},``{0,1,1,1,1,1,1,1,1,1,1,1,0},``{1,1,1,1,1,1,1,1,1,1,1,1,1},``{1,1,1,1,1,1,1,1,1,1,1,1,1},``{0,1,1,1,1,1,0,1,1,1,1,1,0},``{0,0,1,1,1,0,0,0,1,1,1,0,0}``}; Rather than stopping the entire program with long delays, the heartbeat can be updated based on elapsed time. This is important because JBR-001 still needs to monitor its distance sensor and respond to other events while the animation is running.

// Heartbeat animation``unsigned long heartbeatTimer = 0;``int heartbeatStep = 0;``void heartbeat() {``unsigned long now = millis();``switch (heartbeatStep) {``case 0:``matrix.renderBitmap(heartLarge, 8, 13);``heartbeatTimer = now;``heartbeatStep = 1;``break;``case 1:``if (now - heartbeatTimer >= 120) {``matrix.renderBitmap(heartSmall, 8, 13);``heartbeatTimer = now;``heartbeatStep = 2;``}``break;``case 2:``if (now - heartbeatTimer >= 100) {``matrix.renderBitmap(heartLarge, 8, 13);``heartbeatTimer = now;``heartbeatStep = 3;``}``break;``case 3:``if (now - heartbeatTimer >= 160) {``matrix.renderBitmap(heartSmall, 8, 13);``heartbeatTimer = now;``heartbeatStep = 4;``}``break;``case 4:``if (now - heartbeatTimer >= 700) {``heartbeatStep = 0;``}``break;``}``} The display can easily be adapted for other expressions and states. For example, different graphics could indicate that JBR-001 has detected an object, recognized something with its camera, or is waiting for an interaction.

Adding Sound with the Buzzer

JBR-001 uses a buzzer to provide simple audio feedback. For example, when the robot detects someone nearby, it can play a short sequence of notes as a friendly greeting.

A simple greeting can be created with just four tones:

// Play JBR-001's friendly greeting``void playHello() {``buzzer.tone(523, 120); // C5``delay(150);``buzzer.tone(659, 120); // E5``delay(150);``buzzer.tone(784, 180); // G5``delay(210);``buzzer.tone(1047, 250); // C6``delay(270);``} The ascending sequence gives JBR-001 a short and recognizable "hello" sound without requiring a speaker or audio files.

Sound can also be used to communicate different robot states. Different tone sequences could indicate successful detection, warnings, startup, or other events in your own applications.

Sensing Nearby Objects

JBR-001 uses a distance sensor located at the back of its head to sense nearby objects and measure how far away they are. The sensor continuously measures the distance behind the robot and makes this information available to your application.

Reading the distance sensor is straightforward. You can define a distance threshold and use it to trigger actions such as moving the head or arms, playing a sound, or changing the display animation.

This gives you another simple input for creating interactive behaviors and combining physical sensing with JBR-001's other capabilities.

// React when someone approaches``if (distanceSensor.available()) {``float distance = distanceSensor.get();``if (distance < DETECTION_DISTANCE && !objectDetected) {``objectDetected = true;``playHello();``}``// Ready for the next greeting once they move away``if (distance > RESET_DISTANCE) {``objectDetected = false;``}``}

Controlling the Servos

Movement is provided by three servo motors. The head servo is connected to pin 9, while the two arm servos are connected to pins 10and 11.

Each servo can be controlled by specifying its target angle:

headServo.write(90); From there, we can create more natural movement by moving between several positions rather than immediately jumping between large angles.

For example, JBR-001 can turn its head slightly toward a visitor while raising and lowering its arms as part of the greeting animation.

The servo motors require more current than should be supplied directly by the Arduino UNO Q, especially when several motors move at the same time. For this reason, all three servos are powered from an external power source.

The ground of the external servo power supply must also be connected to the ground of the Arduino UNO Q. Without this common electrical reference, the control signals sent from the UNO Q to the servos may not work reliably.

When creating your own animations, keep the mechanical limits of the robot in mind. Servo movement should remain within the range supported by the printed joints rather than automatically using the servo's entire theoretical 0° to 180° range.

Small movements often work better for JBR-001. A slight head turn or short arm movement can make the robot expressive without making the animation feel overly mechanical.

Adding Computer Vision

The camera is where JBR-001 starts becoming much more than a sensor-controlled desktop robot.

Connected to the Arduino UNO Q through the USB-C hub, the camera can provide images for computer vision applications running on the robot.

Image 16: JBR-001 - Computer Vision

JBR-001 - Computer Vision

This opens up many possibilities. JBR-001 could recognize objects placed in front of it, react differently depending on what it sees, detect specific items, or combine visual information with its distance sensor to create more sophisticated interactions.

For example, instead of simply knowing that something is standing in front of the robot, computer vision can help JBR-001 understand what it is looking at.

That is also where synthetic data becomes particularly useful. We can use images for specific objects and scenarios, train a computer vision model, and deploy it to JBR-001 without first having to manually capture and label large numbers of images.

How Computer Vision Works on the JBR-001

The basic computer vision workflow on JBR-001 is straightforward. The camera captures images of the environment in front of the robot. These images are processed on the Arduino UNO Q using a trained computer vision model. The model identifies what it sees, and JBR-001 can use the result to decide what to do next.

The complete workflow looks like this:

Image 17

Once an object has been detected, the result can be connected to any of JBR-001's physical outputs. The robot can move its head or arms, play a sound, change its display, or combine several actions into a single reaction.

This separation also makes JBR-001 easy to experiment with. The computer vision model determines what the robot can recognize, while your application determines how the robot reacts.

What Are We Going to Detect?

For our example, we trained JBR-001 to recognize different modules from the **Arduino® Modulino™**family.

When a Modulino is placed in front of JBR-001's camera, the computer vision model analyses the image and identifies which Modulino it sees. The detection result can then be used by the application to trigger movement, sound, display animations, or other behaviors.

For this project, we used an Arduino Modulino dataset, which is publicly available on $VisionDatasets.com $

Image 18: JBR-001 - Utilizing Dataset form VisionDatasets.com

JBR-001 - Utilizing Dataset form VisionDatasets.com

The dataset contains synthetic images of different Modulinos across a variety of positions, orientations, backgrounds, lighting conditions, and other visual variations designed to help the model recognize the objects when they are presented to the real camera.

The same workflow isn't limited to Modulinos. By changing the dataset and training a new model, JBR-001 can be taught to recognize completely different objects.

Importing the Dataset into Edge Impulse

For training and deploying our computer vision model, we use Edge Impulse.

Vision Datasets integrates directly with Edge Impulse, allowing the Arduino Modulino dataset to be transferred directly into an Edge Impulse project without manually downloading, organizing, and uploading the images.

Open the Arduino Modulino dataset on VisionDatasets.com and select Upload to Edge Impulse.

Image 19: JBR-001 - Dataset Upload to Edge Impulse

JBR-001 - Dataset Upload to Edge Impulse

Provide the API key for your Edge Impulse project and select the number of images, image resolution, and Modulino classes you want to include.

Once the upload is complete, the images appear under Data Acquisitionin Edge Impulse, already labeled and ready to use.

You can find a complete walkthrough of the integration in the $official Edge Impulse documentation $.

Training the Model with Edge Impulse

With the Arduino Modulino dataset available in Edge Impulse, we can create the computer vision pipeline.

Start by opening Data Acquisitionand reviewing the imported images. Verify that the different Modulino classes are represented correctly and that the training and testing data look as expected.

Next, create an impulse and configure the image processing and learning blocks for the model. Edge Impulse then handles the training workflow using the images imported from Vision Datasets. During training, the model learns the visual characteristics that distinguish the different Modulinos from one another.

The goal isn't simply to recognize the synthetic images used during training. We want the model to generalize to images captured by the real camera installed in JBR-001.

This is where variation in the dataset becomes important. Different object positions, rotations, backgrounds, lighting conditions, and other variations expose the model to a wider range of appearances during training.

Once training is complete, use Edge Impulse's model testing tools to evaluate its performance on images that weren't used during training. The most important test, however, is putting a real Modulino in front of JBR-001 and seeing whether the model recognizes it.

Once we're satisfied with the model, we can deploy it to the robot.

Running the Model on the Arduino UNO Q

The next step is to run our trained Edge Impulse model on the Arduino UNO Q.

The camera installed in JBR-001's head provides the image input. The Arduino UNO Q runs inference using the trained model and returns the prediction to our application.

Image 20: JBR-001 - Object Detection

JBR-001 - Object Detection

The process can run continuously, allowing JBR-001 to observe what is placed in front of it and react whenever it recognizes one of the Modulinos included in the model.

Connecting Computer Vision to JBR-001

Detecting an object is useful, but the project becomes much more interesting when the detection produces a physical reaction.

JBR-001 already gives us several ways to respond to what the camera sees:

  1. move the head
  2. move the left or right arm
  3. play a sound
  4. change the display animation

We can map the predictions returned by the computer vision model to these behaviors.

For example, when JBR-001 recognizes a Modulino, it could turn its head, raise its arms, play a short sound, and change the animation on its display. Different Modulinos could also trigger different reactions.

The model provides information about what exists in the physical environment, while the Arduino application translates that information into movement, sound, and visual feedback.

Build Your Own Computer Vision Application

The Arduino Modulino example is only a starting point. The same workflow can be used to teach JBR-001 to recognize completely different objects. You could experiment with recognizing tools, electronic components, everyday objects, or objects specific to your own project.

VisionDatasets.com provides ready-to-use computer vision datasets that can be imported directly into Edge Impulse, or you can create and use your own training data.

Once you've trained a different model, the physical JBR-001 platform doesn't need to change. You simply decide what the robot should recognize and what it should do when a detection occurs.

You can also combine multiple detections with different movements, sounds, and display animations to give JBR-001 completely new behaviours.

Conclusion

You now have the foundation of a working JBR-001.

We started with a set of 3D-printed parts and an Arduino UNO Q and turned them into a desktop robot that can display animations, detect distance of objects, make sounds, and move its head and arms.

JBR-001 is open source so that you can modify it, experiment with it, and make it your own. You can create new display animations, design different sounds and movements, add sensors, modify the 3D-printed parts, or completely change how the robot behaves.

And with the camera and computing capabilities of the Arduino UNO Q, you can also start building interactions based on what the robot sees.

Code

JBR-001 Source Code

GitHub repository with JBR-001 source code

Image 21syntheticAIdata /

JBR-001

Image 22

9

Image 23

1

A Desktop Companion Robot Powered by Arduino UNO Q/Read More

Latest commit to the master branch on 25-09-2026

Download as a zip

JBR-001 Source Code

cpp

head and arms movement, buzzer, distance, display

1#include <Servo.h> 2#include <Modulino.h> 3#include "Arduino_LED_Matrix.h" 4 5// JBR-001 hardware 6Servo headServo; 7Servo leftArmServo; 8Servo rightArmServo; 9 10ModulinoBuzzer buzzer; 11ModulinoDistance distanceSensor; 12 13ArduinoLEDMatrix matrix; 14 15// Servo pins 16const int HEAD_SERVO_PIN = 9; 17const int LEFT_ARM_SERVO_PIN = 10; 18const int RIGHT_ARM_SERVO_PIN = 11; 19 20// Servo resting positions 21const int HEAD_CENTER = 90; 22const int LEFT_ARM_CENTER = 90; 23const int RIGHT_ARM_CENTER = 90; 24 25// Distance detection 26const float DETECTION_DISTANCE = 200.0; 27const float RESET_DISTANCE = 250.0; 28 29bool objectDetected = false; 30 31// Small heart 32// flipped to match display orientation 33uint8_t heartSmall[8][13] = { 34 {0,0,0,0,0,0,0,0,0,0,0,0,0}, 35 {0,0,0,0,0,1,1,1,0,0,0,0,0}, 36 {0,0,0,0,1,1,1,1,1,0,0,0,0}, 37 {0,0,0,1,1,1,1,1,1,1,0,0,0}, 38 {0,0,1,1,1,1,1,1,1,1,1,0,0}, 39 {0,0,1,1,1,1,0,1,1,1,1,0,0}, 40 {0,0,0,1,1,0,0,0,1,1,0,0,0}, 41 {0,0,0,0,0,0,0,0,0,0,0,0,0} 42}; 43 44 45// Large heart 46// flipped to match display orientation 47uint8_t heartLarge[8][13] = { 48 {0,0,0,0,1,1,1,1,1,0,0,0,0}, 49 {0,0,0,1,1,1,1,1,1,1,0,0,0}, 50 {0,0,1,1,1,1,1,1,1,1,1,0,0}, 51 {0,1,1,1,1,1,1,1,1,1,1,1,0}, 52 {1,1,1,1,1,1,1,1,1,1,1,1,1}, 53 {1,1,1,1,1,1,1,1,1,1,1,1,1}, 54 {0,1,1,1,1,1,0,1,1,1,1,1,0}, 55 {0,0,1,1,1,0,0,0,1,1,1,0,0} 56}; 57 58// Heartbeat animation 59unsigned long heartbeatTimer = 0; 60int heartbeatStep = 0; 61 62void heartbeat() { 63 unsigned long now = millis(); 64 65 switch (heartbeatStep) { 66 67 case 0: 68 matrix.renderBitmap(heartLarge, 8, 13); 69 heartbeatTimer = now; 70 heartbeatStep = 1; 71 break; 72 73 case 1: 74 if (now - heartbeatTimer >= 120) { 75 matrix.renderBitmap(heartSmall, 8, 13); 76 heartbeatTimer = now; 77 heartbeatStep = 2; 78 } 79 break; 80 81 case 2: 82 if (now - heartbeatTimer >= 100) { 83 matrix.renderBitmap(heartLarge, 8, 13); 84 heartbeatTimer = now; 85 heartbeatStep = 3; 86 } 87 break; 88 89 case 3: 90 if (now - heartbeatTimer >= 160) { 91 matrix.renderBitmap(heartSmall, 8, 13); 92 heartbeatTimer = now; 93 heartbeatStep = 4; 94 } 95 break; 96 97 case 4: 98 if (now - heartbeatTimer >= 700) { 99 heartbeatStep = 0; 100 } 101 break; 102 } 103} 104 105// Play JBR-001's friendly greeting 106void playHello() { 107 buzzer.tone(523, 120); // C5 108 delay(150); 109 110 buzzer.tone(659, 120); // E5 111 delay(150); 112 113 buzzer.tone(784, 180); // G5 114 delay(210); 115 116 buzzer.tone(1047, 250); // C6 117 delay(270); 118} 119 120// Perform JBR-001's startup movement 121void makeMovement() { 122 123 // Look left, right, then forward 124 headServo.write(70); 125 delay(400); 126 127 headServo.write(110); 128 delay(400); 129 130 headServo.write(HEAD_CENTER); 131 delay(400); 132 133 // Move both arms 134 leftArmServo.write(70); 135 rightArmServo.write(110); 136 delay(500); 137 138 leftArmServo.write(110); 139 rightArmServo.write(70); 140 delay(500); 141 142 // Return to resting position 143 leftArmServo.write(LEFT_ARM_CENTER); 144 rightArmServo.write(RIGHT_ARM_CENTER); 145 delay(500); 146} 147 148void setup() { 149 Modulino.begin(); 150 151 buzzer.begin(); 152 distanceSensor.begin(); 153 matrix.begin(); 154 155 // Show the heart while JBR-001 starts 156 matrix.renderBitmap(heartSmall, 8, 13); 157 158 // Move each servo to its resting position 159 headServo.attach(HEAD_SERVO_PIN); 160 headServo.write(HEAD_CENTER); 161 delay(400); 162 163 leftArmServo.attach(LEFT_ARM_SERVO_PIN); 164 leftArmServo.write(LEFT_ARM_CENTER); 165 delay(400); 166 167 rightArmServo.attach(RIGHT_ARM_SERVO_PIN); 168 rightArmServo.write(RIGHT_ARM_CENTER); 169 delay(400); 170 171 delay(500); 172 173 // Say hello and come to life 174 playHello(); 175 makeMovement(); 176} 177 178void loop() { 179 180 // Keep the heart beating 181 heartbeat(); 182 183 // React when someone approaches 184 if (distanceSensor.available()) { 185 float distance = distanceSensor.get(); 186 187 if (distance < DETECTION_DISTANCE && !objectDetected) { 188 objectDetected = true; 189 playHello(); 190 } 191 192 // Ready for the next greeting once they move away 193 if (distance > RESET_DISTANCE) { 194 objectDetected = false; 195 } 196 } 197}

Downloadable files

JBR-001-schematics

JBR-001 wiring schematics

JBR-001-schematics.png

Image 24: Image

Documentation

JBR-001 Assembly Instructions

Assembly instructions PDF file.

JBR-001 Assembly Instructions.pdf

JBR-001 documentation

Assembly instructions

https://github.com/syntheticAIdata/JBR-001

Comments

Only logged in users can leave comments

login

Image 25: Image

syntheticaidata

7 Followers

• 1 Projects

FOLLOW

Table of contents

Intro

Devices & Components

Hardware & Tools

Software & Tools

Project description

Code

Downloadable files

Documentation

5

0

×

Notice

With your consent, we use cookies, pixels, and similar tools ("cookies"), some provided by third parties, to operate, improve, and personalize our site; serve ads; collect visitor data; and record user sessions and interactions. We and our third-party vendors may monitor, record, and access information and data, including device data, IP address and online identifiers, for these and similar purposes. By clicking Accept, you agree to such purposes. If you continue to browse our site without clicking Accept, or if you click Reject, only cookies strictly necessary to operate and enable default website features and functionalities will be deployed.
More info: PRIVACY POLICY and COOKIE POLICY.
By clicking "Accept," "Reject," or "Manage Preferences" you agree to our TERMS OF USE, to the fullest extent permitted by law.

Press again to continue 0/1

Manage preferences

Reject Accept

来源:Hacker News 热门(buzzing.cc 中文翻译) · projecthub.arduino.cc