ESP-WROOM-02とMB1013を使用した超音波センサモジュール

ESP-WROOM-02に取り付けた超音波センサMB1013の値をWiFi経由で取得するためのモジュールを作成した際のメモ。 実際に動作しているものと少し変えた構成で説明をしているため不具合等ある可能性があります。

2016年12月22日作成、2016年12月28日更新。

目次

1. 使用機材

下記の機材を使用した。

2. ハードウェア

下図のように結線した。超音波センサMB1013はシリアル、アナログ、パルス出力ポートを持っており、シリアルポートが最も精度が高い模様。うまくシリアルポートの値を読み込めなかったため、この回路ではパルスポートを使用している。

回路図

電源としては9V角型電池を使用した。電圧を5Vに変換するために三端子レギュレータを使用している。もともとは小型化のためにコイン電池で動作させる予定であったものの、電流の関係かそのままではうまく動かなかったため、9V角型電池を用いた。コイン電池でも動作するとの報告があるため今後改良予定。

最終的に回路一式をタカチボックスに詰め込んだ。下記は完成図である。下にある2つのボックスが超音波センサモジュール、真ん中のものがメインモジュール。本メモでは触れないが、メインモジュールにはカメラが装着されている。

全体 拡大図

3. ソフトウェア

3.1. 超音波センサモジュール側

下記は、超音波センサのデータを定期的にUDP 50000番ポートを使ってメインモジュールに送付するプログラム。

#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <WiFiUDP.h>

const char mode = 'L'; // Sensor name

const char *ssid = "****"; // WiFi SSID
const char *password = "****"; // WiFi PSK

const int pwpin = 4; // Pin connected to pulse output of ultrasound sensor
const int mainport = 50000; // Port number for main module
IPAddress mainip (192, 168, 10, 1); // IP address of main module
WiFiUDP UDP;

void setup() {
 Serial.begin(115200); // Serial is used for debug
 delay(5000);
 
 Serial.print("Connecting to ");
 Serial.println(ssid); 
 WiFi.disconnect();
 WiFi.mode(WIFI_STA);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   Serial.print(".");
 }
 Serial.println("");
 Serial.print("WiFi connected! IP address is ");
 Serial.println(WiFi.localIP());
}

void loop() {
  unsigned long range = pulseIn(pwpin, HIGH);
  if (UDP.beginPacket(mainip, mainport)) {
    char data[5];
    sprintf(data, "%c%d", mode, range);
    UDP.write(data);
    UDP.endPacket();
    Serial.print("Transmitted data ");
    Serial.println(data);
  }
  delay(50);
}

Arduino開発環境からボードに書きこむ。詳細は割愛。

3.2. メインモジュール側

あらかじめ同じWiFiにつなげておく。下記のようなPythonコードで動作確認ができる。

import socket

port = 50000

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', port))
sock.setblocking(0)
data=''
address=''

while True:
  try:
    data, address = sock.recvfrom(1024)
  except socket.error:
    pass
  else:
    c = data[0:1]
    range = int(data[1:5])
    print "received: data=", data, "sensor=", c, "range=", range

カメラ画像を表示しながらセンサデータを受信する場合は下記のようにする。ここでは2つの超音波センサモジュールからデータを受信することを想定している。カメラ画像表示プロセスとセンサデータ受信プロセスの間でのセンサデータの値の受け渡しには共有メモリを用いている。

from multiprocessing import Process, Value
import cv2
import time
import socket

# settings for camera
fps = 30
width = 480
height = 320 

# settings for network
port = 50000

# function to read from ultrasonic sensor
def readsensor(lsensor, rsensor):
  # inital settings of network
  sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  sock.bind(('', port))
  sock.setblocking(0)
  data=''
  address=''

  while True:
    try:
      data, address = sock.recvfrom(1024)
    except socket.error:
      pass
    else:
      c = data[0:1]
      srange = int(data[1:5])

      if c == "R":
        rsensor.value = srange
      elif c == "L":
        lsensor.value = srange

# function to read from camera 
def readcamera():
  # inital settings of camera
  capture = cv2.VideoCapture(0)
  capture.set(cv2.cv.CV_CAP_PROP_FPS, fps)
  capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, width)
  capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, height)
  cv2.namedWindow("camera")

  while True:
    ret, img = capture.read()

    # display value of lsensor and rsensor
    cv2.putText(img, str(lsensor.value), (0,20), cv2.FONT_HERSHEY_PLAIN, 2, (0,255,0))
    cv2.putText(img, str(rsensor.value), (width-90,20), cv2.FONT_HERSHEY_PLAIN, 2, (0,255,0))
    cv2.imshow("camera", img)

    if cv2.waitKey(10) > 0:
      break

  capture.release()
  cv2.destroyAllWindows()

# main 
lsensor = Value('i', 0) # sensor value from L sensor
rsensor = Value('i', 0) # sensor value from R sensor

p = Process(target=readsensor, args=(lsensor, rsensor))
p.start()
readcamera()
p.join()

4. 関連する卒業研究