自作武器を作ろうず

<!--リトルカブにカブ90(HA02)のエンジン積んで,ペットボトルロケットでロケットランチャーを作り,ChromebookでETロボコン出て,Arduinoでウンコ妨害装置作る<strike>沖縄の学生のブログです。院生になりました</strike> いまは広島で社会人エンジニャーしてます -->


GPIO繋いでRaspberry Pi⇔ESP32でシリアル通信(C/C++, ArduinoCore) 

Abstract

 Raspberry Pi でカメラから得た情報を ESP32(ArduinoCore)に送信したかったので,シリアル通信をしました.忘備録も兼ねてサンプルコードをここに書いときます.

やりたいこと

  • Raspberry Pi が得た情報を ESP32(Arduino Core)にシリアル通信で送りたい
  • USBシリアルではなく,GPIOピンの Tx - Rx を繋いでシリアル通信をしたい
  • ESP32 も Raspberry Pi 側も C/C++ で実装したい

f:id:teppodone:20200912113416j:plain
RPiとESPを「GPIOで通信」し「C++で実装」したかったお話です


環境

下記のボードを使いました.

詳細
Raspberry Pi Raspberry Pi 2
ESP32 HiLetgo ESP32 ESP-32S NodeMCU開発ボード2.4GHz WiFi + Bluetoothデュアルモード

 とはいえ例のごとく Raspberry Pi だったら2じゃなくて 3でも4でもZeroでも何でも良いと思いますし,ESP32側もESP32本体が載ってるなら ESP-WROOM-32ブレイクアウトSD+ - スイッチサイエンス やAliexpressで二束三文で売ってそうなボードでも出来るでしょう多分(未検証)



シリアル通信のやり方

1. コード
 RaspberryPi,ESP32 にそれぞれに下記のコードないしスケッチの書き込みを行いました.

Raspberry Pi(送信側)のコード

// serialOnGPIO.cpp 
// 「GPIOを繋いで Raspberry Pi⇔ESP32(Arduino Core) でシリアル通信をする(C/C++)」, http://teppodone.hatenadiary.jp/entry/UART_GPIO_ESP32_RaspberryPi_cpp


#include <stdio.h>
#include <unistd.h>          // sleep()関数を使うのに必要
#include <wiringPi.h>  // C/C++でGPIOピンを触るのに必要
#include <wiringSerial.h> // C/C++でGPIOピンを触るのに必要


int main(){

  // シリアルポートオープン,ボーレート(19200)はESP32側と統一すること
  int fd = serialOpen("/dev/serial0",19200);    	
  wiringPiSetup();
  fflush(stdout);

  //シリアルポートを開くことが出来たか否かの確認
  if(fd<0) printf("can not open serialport\n");    
  else       printf("serialport opened\n");

  char cnt = 0;
	
  //シリアル通信で1秒おきに cnt の値を送る
  while(1){
    serialPutchar(fd,cnt);              //cntの値を送る
    printf("RPi : send %d \n",cnt);    //ついでにターミナルにcntの値を出力する

    if(255<cnt) cnt = 0;                //ざっくり言うと serialPutchar() で送れるのは 0~255 までなので,cntが255を超えたら0にするようにしてる
    else cnt ++ ;

    sleep(1);                           // 1秒待機
  }
  return 0;
}
# コンパイルと実行
pi@raspberrypi:~/ $ g++ -Wall  serialOnGPIO.cpp -lwiringPi 
pi@raspberrypi:~/ $ ./a.out


ESP32(受信側)のコード

// serialOnGPIO.ino
// 「GPIOを繋いで Raspberry Pi⇔ESP32(Arduino Core) でシリアル通信をする(C/C++)」,http://teppodone.hatenadiary.jp/entry/UART_GPIO_ESP32_RaspberryPi_cpp

void setup() {
  Serial.begin(19200); //ボーレート(19200)はESP32側と統一すること
  Serial.println("start");  
}


void loop() {  
  if(0<Serial.available()){
    char data = Serial.read();  // 受け取った値を入れとく変数
    Serial.print("received");
    Serial.println((int)data);    // 受け取った値をシリアルモニタで表示
  }
  Serial.flush();
  delay(500);
}


注意点1. 書き込みの際は線を抜く
※ ArduinoIDEからESP32にスケッチを書き込む際には,Tx ,Rx の接続を解除しておく(ジャンパーケーブル抜いとく)必要があります(繋いだままスケッチを書き込もうとすると書き込みエラーとなる).書き込んだあとに元通り結線すればOKです.


注意点2. ボーレートを統一する
 上記コード中でボーレートを”19200”に設定していますが(Raspberry Pi のコードの13行目,ESP32のコードの5行目),このように Raspberry Pi 側(送信側),ESP32側(受信側)のボーレートは統一する必要があります.


2. 結線する
 Raspberry Pi と ESP32を下記のように結線しました.

f:id:teppodone:20200912113308p:plain
こんな感じ


ポイントは次のとおりです.

 なお,GPIO - Raspberry Pi Documentationによると,Tx,Rx の配置は8番,10番ピンに充てられています.

f:id:teppodone:20200912123805p:plain
画像はGPIO - Raspberry Pi Documentation(2020-09-12閲覧)より引用


3. プログラムを実行し,シリアル通信を行う
1. 結線がちゃんと出来ているか確認する
 スケッチを書き込む度に「結線を外す→ESP32にスケッチをアップロードする→アップロード後に再度結線する」…という手順を踏む必要がありますが,僕は94割の確率でRxとTxを逆刺ししてしまいます.

2. RaspberryPi側の送信プログラムを実行する
 スケッチを書き込んだ後に,RaspberryPi 側の送信プログラムを実行します.

pi@raspberrypi:~/ $ ./a.out

 そうると,ターミナルに「RPi : send (0~255の数字)」が1秒おきに表示されると思います.

3. ESP32のシリアルモニタで,RaspberryPi側が送った数字を確認出来れば成功
 最後に,そのまま(RaspberryPi側のプログラムを実行したまま)PCとESP32をUSBケーブル等で繋ぎArduinoIDE等からシリアルモニタを開きます(ここでもボーレートは19200).ここで,RaspberryPi側が送った数字と同じ数字がシリアルモニタに写っていればシリアル通信成功です!

www.youtube.com



ポイント

 ポイントと言うほどのこともありませんが,メモ書き程度に記しておきます.
Wiring Pi を使った
 今回,C/C++でシリアル通信を行うため Raspberry Pi 側(送信側)のプログラムに「Wiring Pi」を使いました.
  wiringpi.com
 Wiring Pi は,Raspberry Pi の GPIOピンをC言語で操るためのライブラリで,その中にシリアル通信を行うための便利機能も含まれています.上記コード中では6, 7行目でインクルードし,13, 14, 25行目でWiring Pi のライブラリからシリアル通信を行っています.

 Wiring Pi のインストール方法等はググれば出てくるので適当に調べて下さい.


Raspberry Pi ⇔ ESP32 間の通信と,ESP32 ⇔ PC(シリアルモニタ)間の通信で同じチャンネル使うのあんま良くなさそう
 ここの項はかなり推測まみれのお話なんですが(リファレンス読め)…

 上記のコードでは「Raspberry Pi ⇔ ESP32 間の通信も,ESP32 ⇔ PC(シリアルモニタ)間の通信 も,たった1つの同じ”Serial”オブジェクトで行っている(同じチャンネルを使っている)」といった振る舞いをしているような気がします.
 要は「ESP32から見たときに,1つのチャンネルを使ってRaspberry Pi と通信をし,シリアルモニタとも通信しているんじゃないか」ということです.(要出典).

 本来,シリアル通信(UART)とは1対1通信のための規格なので,あまりこういうお行儀の悪いことはしないほうが良いんじゃねぇかなァ~って気がします.無用なトラブルを未然に防ぐ的な意味で.
 

じゃぁどうすればええねん
 ESP32には3チャンネルの Hardwareserial が備わっている*1ので
  • Raspberry Pi ⇔ ESP32 間の通信に UART0 を
  • ESP32 ⇔ PC(シリアルモニタ)間の通信にUART1を
 といった感じでRaspberry Pi ⇔ ESP32 間,ESP32 ⇔ PC(シリアルモニタ)間で別々のハードウエアシリアルを割り当ててあげればいいんじゃないでしょうか.しらんけど*2
qiita.com


int 型の数字とか送ろうと思ったらもうひと工夫必要
 本記事のコードでは char 型すなわち 0~255 の範囲でしか数字を送れませんが,それより広い範囲の数字を送ろうと思ったらもうひと工夫必要です.一応,出来るには出来たので気が向いたら記事書きます(2バイトint (最大 32767)の情報をやりとりしてる様子).




参考文献






日記

f:id:teppodone:20200912132541j:plain
てぽどさん「聞いてよアカネチャン」

 ふと久々にウンコジャマーの動画見たら,知らんうちにニコニコ兵器開発局のタグランキングで1位取ってました.しかも今年の3月.嬉し半分,なんで今さら??という疑問も大きいです(投稿したのは2018年)
 とはいえ,動画を色んな人に見てもられることは工作動画マンにとってはこの上なく嬉しことです.ありがとうございます.もっと見て下さい(視聴推奨).
 
ウンコ妨害装置を作ってみた【ウンコジャマー】 - ニコニコ動画
ウンコ妨害装置を作ってみた【ウンコジャマー】, YouTube
 

*1:Arduino-ESP32 Serial通信 - Qiita,2020-09-10閲覧

*2:というか,最初これ(1つのチャンネルで2方向に通信するのは)出来んでしょと思い込んでたけど,適当にやってみたら出来てしまったのでビビった

VideoCapture cap(0) 実行時にフリーズする問題(OpenCV, C++)

Abstract

 USBカメラから取り込んだ映像をOpenCVでアレコレ触ろうと思ったのですが,実行時に"VideoCapture"コンストラクタを呼び出した段階でフリーズする(コンパイルエラーも実行時エラーも出ずただフリーズするのみ.)という現象が見られました.結論から言うと,「どうもこれはカメラ側の問題っぽい」という結論に至りました.

f:id:teppodone:20200823145832j:plain:w640
冷やしOpenCVはじめました

事象・概要

 「冷やしOpenCVはじめました!」…かったんですが早速壁にぶち当たりました.以下事象の詳細です.

やりたかったこと
 Raspvberry Pi 上で OpenCV を使って USBカメラからの映像を取り込みたかった.

やったこと
  1. Raspvberry Pi に OpenCV4 をインストールしUSBカメラを接続した.
  2. コード(後述)をコンパイルした.このときコンパイルエラーは発生せず.
  3. 実行したところ,VideoCapture クラスのオブジェクト生成(10行目)周辺で処理が止まった.このとき実行時エラー,ワーニングは発生せず

コード*1

/* camera.cpp */
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace std;

int main(){
 cout << "Handle USBcam with OpenCV4" << endl;
 VideoCapture cap(0);  //USBカメラを扱うためのオブジェクト生成. どうもココで止まってるっぽい.

 if(cap.isOpened()) cout<<"succeeded to open camera \n"<<endl;
 else         cout<<"faild to open camera \n"<<endl;

 return 0;
}



コンパイルと実行結果

pi@raspberrypi:~/  g++ `pkg-config --cflags --libs opencv4` camera.cpp
pi@raspberrypi:~ $ ./a.out 
Handle USBcam with OpenCV4
_                            #←ずっとこのままウンともスンとも動かない



これが発生した環境

仕様
備考
OpenCV4 C++
V4.0.0
こちらの手順に従ってインストールした
OpenCV4 for Raspberry Pi - Qiita
Raspberry Pi Pi2
USBカメラ HD
UVC
大昔にAliexpressで買ったやつ
720P HD Video Surveillance UVC USB Camera mini usb Camera module CCTV PCB Board CMOS pc webcam support Windows pc free shipping|cctv pcb board|module cctvcamera mini usb - AliExpress
f:id:teppodone:20200824084720j:plain:w360
ジャンクの箱からボワッと~(ボワットー) 怪しいカメラが登~場~


解決策(?)と分かったこと

 電気屋行って適当なUSBカメラ"UCAM-C310FBBK(ELECOM)"買ってきて付けたら動きました.「何じゃそりゃ」と思うかもしれませんが,そんだけです.Aliexpressで買った例の中華カメラ(以下,「中華カメラ」)を刺したら上記不具合が発生し,UCAM-C310FBBK(ELECOM)を刺したら普通に動くという現象が確認されました.
 www.elecom.co.jp


分かったこと
以上のことから,次の事がわかりました.
 OpenCVとUSBカメラには相性みたいなのがあり,相性が悪いと実行時にVideoCapture オブジェクトを生成した段階でフリーズすることがある.

 今回「USBカメラを変えたら動いた」という所まではわかりましたが,「じゃぁ何故,中華カメラでは動かなかったのか」という所まではわかりませんでした.もしかすると,OpenCV側の設定やパラメータを弄ったら中華カメラも動かせるのかもしれません.が今の所私はそこまでたどり着けてません.あとでドキュメント読みます.


質問コーナー
Q. それカメラが壊れてただけでは?
 それがそういう訳でもなさそうです.Raspvberry Pi に中華カメラを接続し,mjpg-streamer(ストリーミングするやつ)を起動したところ,普通に中華カメラからの映像を配信できました.よってカメラが壊れたわけではないみたいです.

Q. オブジェクト生成時の引数(デバイス番号?)が違うんでは?
 上記のコードの10行目,VideoCapture cap(0); について,VideoCapture クラスのオブジェクトを生成するときに,引数にはUSBデバイスの番号(?)を指定する必要があります("cap(0)"の"0"の部分). この数字は大概の場合は”0”ですが,USBカメラの接続状況によっては”1”や"2"等,適切な番号を指定してあげる必要があります.
 当然間違ったデバイス番号を指定すると実行時にエラーが出るのですが,その場合は明示的にちゃんと下記のエラー文が表示されます.

pi@raspberrypi:~$ ./a.out # 10行目を VideoCapture cap(1); に変えたコードをコンパイルしたやつ
Handle USBcam with OpenCV4
[ WARN:0] global /home/pi/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (1759) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module v4l2src0 reported: Device '/dev/video1' is not a capture device.   
[ WARN:0] global /home/pi/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (888) open OpenCV | GStreamer warning: 
unable to start pipeline
[ WARN:0] global /home/pi/opencv-4.2.0/modules/videoio/src/cap_gstreamer.cpp (480) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
[ WARN:0] global /home/pi/opencv-4.2.0/modules/videoio/src/cap_v4l.cpp (887) open VIDEOIO(V4L2:/dev/video1): can't open camera by index
faild to open camera 

 このようにデバイス番号の指定を間違えた場合は,ちゃんとエラーで「1番にはUSBカメラ繋がってないやで(三行目の" Device '/dev/video1' is not a capture device. ")」と教えてくれますが,今回はエラーも出ずにアボートもされず,ただ止まるのみという状況だったので,コレとはまた別だと思います.

//---------------------------------

 「USBカメラ自体は生きている」「エラーが出ない」が重なった結果,「原因は分からんけどUSBカメラが動く...ってことは,問題はUSBカメラ以外のどっか別の所に問題が有るんやろ!」と思ってトラブルシューティングするという最悪のムーブをしてしまいました.志村後ろ !原因はそこや(足元!!
 ともあれ,これでようやくUSBカメラを使った顔検出ができるようになってめでたしめでたし.



日記

 ファクトリオやりてぇ~~~ 生産ライン引きてぇ~~~~~!!!!!
 
 あのですね,GWの暇つぶしにゲーム買ったんスよ.無人の惑星で工場の自動化ラインを引くゲーム「ファクトリオ」.
 もうニッチな沼感がぷんぷんしますが,お察しの通りとんでもない沼地でして.製品ができるまでのリードタイムを計算して工場ラインのレイアウト設計を最適化したり,生産のボルトネックになってる部分を改善したり,時間的効率 VS 歩留まり どっちを優先させるかとか考えたりの,常に「現状でも十分だけど,もっと効率化できる方法は無限にある」が存在するタイプのゲームです.

 な ん で す が … ファクトリオ入れて遊んでたメインPCが5月末にご臨終しちゃって.その日からHDDのなかに眠る僕の工場は,今日のいままで生産停止してるんすよね… 工場再稼働に向けてゲーがミングする感じのPCを組みたいんですが,でもシンゾー君*2の給付金はクラブマンの輸送費とGP100TT(タイヤ)と3Dプリンタに使っちゃったしなぁ…

f:id:teppodone:20200824160835j:plainf:id:teppodone:20200824160829j:plain
せんきゅーシンゾー…日本経済10万1千までキッチリ回したぜ…(3D🍮は中国製だけど許して)

*1:参考URL:「【初心者向け】USBカメラで撮影した動画をリアルタイムで顔検出(https://qiita.com/yutoakaut/items/6787aed37721a8a22f64,2020/08/24閲覧」

*2:2020/08/28 19:13 追記 上記の記事は一週間前ぐらいに書いて予約投稿セットしてたんだけど,今日仕事から帰ってきてニュース見て.まぁ驚いたわ.今まで長いことお疲れさまでした.ありがとうございました.どうかお体を大事にされてください.

ホムセンで売ってる木材で作業机作った.費用3980円ぐらい.

Abstract

 ホームセンターで入手可能な 2x4 と板材で作業机もといサブデスクを,材料費サンキュッパ程度で作りました.本記事では作業机の作り方・制作費用・設計図(木取り図)について述べられています.

f:id:teppodone:20200819215009j:plain
コレが今回作った作業机.さっそくとっちらかってる.

 時は令和二年.素手で木を切り倒し木材を手に入れインベントリを開き木材4個を並べてクラフトしなくても,ホームセンターに行けば作業台が作れる便利な時代になりました.


仕様…天板広さ:幅910x奥行き450,高さ:724

 まず,今回作る作業机の仕様です.

f:id:teppodone:20200808072010j:plain
外寸こんな感じ

 ホームセンターに幅 910[mm] x 奥行き 450[mm] x 厚み 18[mm] の丁度よい板材が売っていたので,これをそのまま天板としました.また今回作った作業机は,脚の長さを 700[mm],天板の厚さが 18[mm],脚と天板のクリアランスを 6[mm]設けましたので,床から天板上面までの高さは 724[mm]となります(700+18+6).
 強度については,「ハンダ付けやカブのエンジンをバラしたりできればOKかな~」程度を考えています.




材料と費用

 ホームセンターで下記の材料を購入しました.材料費あわせて3764円

材料 仕様 個数 使用箇所 小計(税込み)
2x4材 6フィート
(1828mm)
3 枠組みと脚 1194円
(398円/本)
コーススレッド φ4.2 x 75 24 枠組みと脚の固定 忘れた.
仮に袋入で200円
板材 910 x 450
厚み 18
1 天板 1750円
L字ステー 4 天板と枠組みの固定 500円
(125円/個)
木ネジ 皿ネジ 16 天板と枠組みの固定 120円
(袋売)


使用した工具

f:id:teppodone:20200808072654j:plain
コーナークランプ(左),my new gear...(中央),木工用ドリルビット(右)

  • 部材を直角に保持する治具(コーナークランプ)
  • 電動ドライバー
  • 木工用ドリルビット
 とくにコーナークランプ君が今回大活躍しました(後述).なおタイトルの「費用3980円ぐらい」には工具を買うお金は含まれておりません.あしからず.


作り方

①2x4材(6フィート)を3本買って下記寸法でカットしてもらう
 今回作る作業机は2x4材で作る「脚」と「枠組み」の部分,それから板材を使った「天板」の3部分に分けられます.まずホームセンターに行って2x4材(6フィート)を3本買い,そのままホームセンター特有の「カットサービス」で下記の寸法に切り出してもらいました.なお,ウッカリ「反り」のある木材(曲がったり歪んでる木材)を買っちゃうと,後述の「枠」を組むときに面倒くさい*1ので,なるべく反りの少ないものを選びました.

使用箇所 寸法 個数
700 4
枠(短手) 374 2
枠(長手) 758 2

※「枠(短手)」「枠(長手)」を組んで「枠組み」を作ります(後述).


f:id:teppodone:20200808073825j:plainf:id:teppodone:20200808073830j:plain
「脚」と「枠(長手)」「枠(短手)」の寸法(左),実際に切り出してもらった2x4(右)


木取り図
  6フィート(1820[mm])の2x4 3本を下記の寸法で「脚」と「枠(長手)」「枠(短手)」に切り出しました.(図の上側の [枠(短手)]-[枠(短手)]-[脚] は2セット必要)

f:id:teppodone:20200813190254j:plain:w460
木取り図.図上部の [枠(短手)]-[枠(短手)]-[脚] は2セット必要


 いっしょに天板も買ってきました.

f:id:teppodone:20200819214504j:plain
 税込み1700円ぐらいのパイン材

②「枠組み」を作る
 「枠(長手)」「枠(短手)」を下記のように組み,コーススレッドでネジ止めし「枠組み」を作りました(ネジ位置は後述します).この枠組を組むときにコーナークランプを使い,きっちり直角を出しつつネジ止めすることができました.

f:id:teppodone:20200813191112j:plain

f:id:teppodone:20200819214448j:plain


③「枠組み」に「脚」を生やして「天板」を乗せて完成
 はい完成. いきなり完成図になってしまい大変恐縮ですが,「枠組み」をベースに「脚」と「天板」をネジ止めしました(途中の写真あんま撮ってなかったから詳しく書けない).完成写真たくさん乗せるので詳しい作り方や部品の位置関係は察して下さい.
f:id:teppodone:20200819220240j:plain
f:id:teppodone:20200819220248j:plain


「枠組み」「脚」のネジ止めの位置
 「枠組み」「脚」のコーススレッドのネジ止め位置ネジ止めの位置は下記のとおりです.

f:id:teppodone:20200819215608p:plain
カイシャでこんな適当図面書いたら怒られそう


「枠組み」と「天板」の締結
 「枠組み」と「天板」はL字ステーと皿ネジで固定しました(位置適当)

f:id:teppodone:20200819222128j:plain
 適当にステーと皿ネジで停めました


まとめ:日曜大工,クソ楽しい

 「しょせんは日曜大工の机つぐり.チャッチャと適当に作ってしまうか~」程度にしか思っておらず,記事にするつもりはさらさらなかったんですが,いやはや色々調べて考えて選んで実際に作ってみると何これメッチャ楽しいですね.
 今回,「初めての家具職人」という事もあり,補強もなければニスも塗らない,棚やキャスター等の便利機能もない「最小構成の作業机」を作ってみました.が.「次はソーホースブラケットを使った折りたたみ机(駐車場に広げてバイクの整備できるようなやつ)」とか,「キャンプで使える折りたたみローチェア」とか色々わくわく考えてしまいます.キャンプ行かないくせに.

 なにより机ができて便利になりました.
 大袈裟な言い方ではありますが「自分の生活環境を己の技術で改善した」という自尊心と達成感は何物にも代えがたいですね.この気持は大事にしたいです.



余談
 で,この机に今なにが乗ってるのかというと…



























 こ い つ が 鎮 座 し て ま す😎😎😎😎😎😎


日記
 ちょっと前の話になりますが,遂にこっちに持ってきましたークラブマン!俺のGB250!!
 新品タイヤすなわちGP100TTを入れ,ウッキウキで瀬戸大橋までツーリングに行きました.

 この時なんですが,なんと四国にお住まいのふぇるねこ氏(エンジンが死んだねこ (@kujyou_neko) | Twitter)がコッチまで駆けつけてくれて急遽GBMT at 瀬戸大橋 が開催されてしまいました👏👏👏  久々に界隈の諸兄とオタクディスカッションができて楽しかったです!ありがとうございました!!


※広島じゃなくて岡山です.

*1:「反りすぎてソリになったw」って泣きながらツイートする羽目になります

Copyright © 2012- piyo teppodone piyo