Arduino超音波センサーとProcessingで作るリアルタイム距離測定ソナー
必要な部品と材料
| 部品 | 数量 | 備考 |
|---|---|---|
| Arduino UNO | 1 | メインマイコン |
| SG90 マイクロサーボモーター | 1 | 超音波センサー回転用 |
| 超音波センサー HC-SR04 | 1 | 距離測定用(2cm-400cm) |
| ジャンパーワイヤー | 1セット | 配線用 |
| フルサイズ ブレッドボード | 1 | 配線用 |
必要な工具
- グルーガン(超音波センサーをサーボに固定用)
- はんだごてキット
使用ソフトウェア
- Arduino IDE
- Processing IDE(The Processing Foundation)
プロジェクト概要
障害物回避ロボットの要素(サーボ+超音波センサー)を応用し、180度回転スキャンするソナーシステムを構築しました。TFT LCDが手元になかったため、PC上でProcessing IDEを使ってリアルタイムにレーダー風表示を実現しています。
仕組み
- グルーガンでHC-SR04をSG90サーボのホーンに固定
- サーボが0°→180°→0°と往復スキャン(30ms/ステップ)
- 各角度で超音波距離測定し、「角度,距離.」形式でシリアル送信
- Processing側で受信し、レーダー画面(半円スキャンライン+検出点プロット)に描画
- 距離・角度を数値表示、40cm以内の物体を赤線でハイライト
Arduinoコード(C/C++)
#include <Servo.h>
const int trigPin = 12;
const int echoPin = 11;
long duration;
int distance;
Servo s1;
void setup() {
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
s1.attach(9);
}
void loop() {
// 0度→180度 スキャン
for (int i = 0; i < 180; i++) {
s1.write(i);
delay(30);
distance = calDist();
Serial.print(i);
Serial.print(",");
Serial.print(distance);
Serial.print(".");
}
// 180度→0度 復路スキャン
for (int i = 180; i > 0; i--) {
s1.write(i);
delay(30);
distance = calDist();
Serial.print(i);
Serial.print(",");
Serial.print(distance);
Serial.print(".");
}
}
int calDist() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2; // 音速340m/sで片道距離計算
return distance;
}
Processingコード(Java)
import processing.serial.*;
Serial myPort;
String ang = "";
String distance = "";
String data = "";
int angle, dist;
void setup() {
size(2000, 800);
myPort = new Serial(this, "COM3", 9600); // ポート名は環境に合わせて変更
myPort.bufferUntil('.');
background(0);
}
void draw() {
// 残像効果付き背景クリア
fill(0, 5);
noStroke();
rect(0, 0, width, height * 0.93);
noStroke();
fill(0, 255);
rect(0, height * 0.93, width, height);
drawRadar(); // レーダー背景(同心円・角度線)
drawLine(); // 現在のスキャンライン
drawObject(); // 検出物体のプロット
drawText(); // 目盛り・数値表示
}
void serialEvent(Serial myPort) {
data = myPort.readStringUntil('.');
data = data.substring(0, data.length() - 1);
int index1 = data.indexOf(",");
ang = data.substring(0, index1);
distance = data.substring(index1 + 1, data.length());
angle = int(ang);
dist = int(distance);
System.out.println(angle);
}
void drawRadar() {
pushMatrix();
noFill();
strokeWeight(0.5);
stroke(10, 255, 10);
translate(width/2, height - height*0.06);
// 基準線
line(-width/2, 0, width/2, 0);
// 同心円(距離目盛り)
arc(0, 0, width*0.5, width*0.5, PI, TWO_PI);
arc(0, 0, width*0.25, width*0.25, PI, TWO_PI);
arc(0, 0, width*0.75, width*0.75, PI, TWO_PI);
arc(0, 0, width*0.95, width*0.95, PI, TWO_PI);
// 30度刻み主目盛線
for (int a = 30; a <= 150; a += 30) {
line(0, 0, (-width/2)*cos(radians(a)), (-width/2)*sin(radians(a)));
}
// 15度刻み補助線
stroke(175, 255, 175);
for (int a = 15; a <= 165; a += 30) {
line(0, 0, (-width/2)*cos(radians(a)), (-width/2)*sin(radians(a)));
}
popMatrix();
}
void drawLine() {
pushMatrix();
strokeWeight(9);
stroke(0, 255, 0);
translate(width/2, height - height*0.06);
line(0, 0, (width/2)*cos(radians(angle)), (-width/2)*sin(radians(angle)));
popMatrix();
}
void drawObject() {
pushMatrix();
strokeWeight(9);
stroke(255, 0, 0);
translate(width/2, height - height*0.06);
// 距離をピクセルに変換(40cmを最大半径とする)
float pixleDist = (dist / 40.0) * (width / 2.0);
float pd = (width/2) - pixleDist;
float x = -pixleDist * cos(radians(angle));
float y = -pixleDist * sin(radians(angle));
if (dist <= 40) {
line(-x, y, -x + (pd*cos(radians(angle))), y - (pd*sin(radians(angle))));
}
popMatrix();
}
void drawText() {
pushMatrix();
fill(100, 200, 255);
textSize(25);
// 距離目盛りラベル
text("10cm", (width/2)+(width*0.115), height*0.93);
text("20cm", (width/2)+(width*0.24), height*0.93);
text("30cm", (width/2)+(width*0.365), height*0.93);
text("40cm", (width/2)+(width*0.45), height*0.93);
if (dist <= 40) {
text("Distance: " + dist, width*0.7, height*0.99);
}
translate(width/2, height - height*0.06);
textSize(25);
// 角度ラベル
text(" 30", (width/2)*cos(radians(30)), (-width/2)*sin(radians(30)));
text(" 60", (width/2)*cos(radians(60)), (-width/2)*sin(radians(60)));
text("90", (width/2)*cos(radians(91)), (-width/2)*sin(radians(90)));
text("120", (width/2)*cos(radians(123)), (-width/2)*sin(radians(118)));
text("150", (width/2)*cos(radians(160)), (-width/2)*sin(radians(150)));
popMatrix();
}
回路図
配線図を参照:HC-SR04のTrig→D12, Echo→D11, VCC/GND→5V/GND。サーボ信号線→D9, VCC/GND→5V/GND。
動作確認のポイント
- Processingの
new Serial(this, "COM3", 9600)のポート名は環境に合わせて変更(Windows: COMx, Mac/Linux: /dev/ttyUSBx等) - サーボの動作範囲は0-180度。HC-SR04の測定範囲は実用的に2-40cm程度
- 電源はUSB給電で足りるが、サーボ動作時に電圧降下する場合は外部5V電源推奨
製造プロセス
- TinyML言語検出器:Edge ImpulseとArduino Nano 33 BLE Senseで「はい」を多言語判別
- Arduino NanoとMPU-6050で作るリアルタイムジャイロスコープゲーム
- Arduinoデジタルダイス: LCD表示の乱数ジェネレーター自作
- Arduinoで超音波レベーション(浮遊)装置を自作:ステップバイステップガイド
- Arduinoとスマホで作るスマート電圧計 – 簡単DIYプロジェクト
- Arduinoで温湿度ロガーを作る – DHT11とEthernetシールドでSDカード記録
- ESP8266・Arduino・超音波センサーで作るスマートIoTジャー:リアルタイム中身監視
- スマート駐車場カウンター:Arduino、Processing、PHPでリアルタイム車両管理
- Bolt IoTとArduino UNOでLED輝度をシームレス制御
- Arduino IoT CloudとAlexaでテレビを音声操作:ステップバイステップガイド
- ArduinoとProcessingで作るリアルタイムデジタルコンパス