2026年8月25日火曜日

Arduino手習い

 YouTubeで日本の電子部品店の歴史という動画が出ていた。見てみるとお馴染み秋月や共立と並んでSwitch Scienceが紹介されていた。私はSwitch Scienceは外資系の会社だと思っていたが日本人が興した日本の会社だ。細かい話は動画を見ていただくこととして、Switch ScienceがArduino日本導入の先駆者らしい。PICの次はArduinoかと考えて、試してみたくなった。Arduinoは秋月でも売っているがこれまで気にも留めていなかった。

 Arduinoについて資料を漁り開発環境(Arduino IDE)をインストールした。たまたま秋月で興味本位で買ってデッドストックになっていた ESP32-DevKitC-32E はそのままIDEで扱えるようなので、お決まりのLEDチカチカに挑戦した。

IDEに付属のスケッチ例の中の 01.Basic にあった blink を試してみた。スケッチとは Arduino IDEにおけるプロジェクトに相当すると考えればよいようだ。スケッチはC/C++で記述し、最上位にmain() ではなく setup() と loop() という関数を記述する。setup() は初期化部分を記述し、loop() は実行部分を記述する。これは、

void main(){
    setup();
    while(1) loop();
}

という関係だと考えれば良いのだろう。

実際にIDEで例にあるプログラム(blink)をコンパイルすると、PICのコンパイラと比べやたら遅い。それにお決まりのコンパイルエラーだ。 エラーは次の記述で発生した。

   pinMode(LED_BUILTIN, OUTPUT);

 この LED_BUILTIN が不明だと。確かにプログラム中の何処にも LED_BUILTIN は規定されていないし、#include 文も無い。ここで全くの初心者なら途方に暮れ、投げ出す所だろう。ネットで pinMode を検索すると第一引数はピン番号を表す整数のようだ。ここに直接数字を書いても良いが #define 文で LED_BUILTIN を定義するのがCのやり方だ。そして出来上がったのが次のプログラムだ。

#define LED_BUILTIN   5

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

static void loop_sub(unsigned int len1, unsigned int len2) {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(len1);
  digitalWrite(LED_BUILTIN, LOW);
  delay(len2);
}

void loop() {
  loop_sub(200, 200);
  loop_sub(200, 200);
  loop_sub(200, 200);
  loop_sub(600, 200);
  delay(500);   
}
 

単なる LEDチカチカでは面白くないのでモールスでテスト信号を表す V(= ...-)と光るようにした。

しかし、Cでプログラムを書くためには文法は勿論として、ライブラリーや関数に関する知識が不可欠だ。そこら辺の情報は何処にあってどう入手できるのだろうか。個人的には中身が見えないライブラリーは苦手だ。バグがあったり、メモリーを大量に消費したり、無駄なコードがあったり、見えない前提条件が設定されていたり、デバッグで苦労しそうな感が拭えないからだ。

しかしArduinoって名前は何を表しているんだ?製品名であり開発環境であるが、ESP32-DevKitC-32E も Arduino の範疇で扱える。Raspberry-Pi-Pico も Arduino IDE で扱えるらしい。なんか固定したイメージが無くぼんやりしていて良く分からない。まだまだ先は長そうだ。

(後日)

トラ技2025年10月号を見ると Arduino Uno にはオンボードLEDが搭載されており、それが13番ピンに接続されているらしい。その場合には LED_BUILTIN は規定値(13)として予め定義されているのだろう。それで Builtin か、納得。

 

2026年8月23日日曜日

超音波距離計(その6)

 車に取り付ける超音波距離センサーには防水機能が必須だ。一方秋月で売っていて(その1)で使った超音波センサー(US-015やHC-SR04)には防水機能が無く使い辛い。最近Amazonを覗いていたら防水機能を持った超音波距離センサーを売っていた。売っているタイプには2種類あり、1つはUS-015と同じような送信と受信が別のユニットになっている一体型のタイプで、他は車のバンパーについているような送受共用ユニット(トランジューサ)を用いたタイプである。送受共用ユニットを使った場合の特性を知りたかったのと値段的に随分安かったので、後者を注文した。

届いたセンサー(袋にはX0018RCNB3と記載)はトランジューサと制御基板が別になっていて、その間を2.5mのケーブルで接続する。制御基板の出力端子の印字を見てみると、電源のほかTrigとEchoがあり、またピン配置もUS-015と同じでピンコンパチに出来ているようだ。


さらにRX,TXという記載もある事から何処かのジャンパーを変更すればUARTにも対応しているのだろうが説明書は添付されてない。 

実際にこれを(その1)及び「LiDARを使った距離計(その2)」で作った基板に繋げてみると何もせずそのまま動作した。但しトランジューサが共用なので送受切替時間に対応したブラインドゾーンが大きく、19cm以下の距離は計れなかった。


 

2026年7月18日土曜日

LiDARを使った相対速度計(その9)

 PICを16F18326に変えることで、LiDARとの間の通信はI2Cに限定された。一方新品のLiDARのインターフェイスはデフォルトでUART(460,800bps)に設定されているのでこの矛盾を何とか整合させたい。以前、ポートを直接ソフトウェアでON/OFFしてUART信号を作り、460,800bpsを9600bpsに落とすことが出来たが、その応用として9600bpsのソフトウェアUARTを作りたい。とりあえず送信だけ出来れば何とかなるので作ってみた。そのコア部分は、

#define TX_OUT      LATAbits.LATA4

#define DLY_9600BPS __delay_us(100)     //Bit width shall be 104us 

static void send_byte_9600(byte data){

    TX_OUT      = 0;   DLY_9600BPS;  // Start bit
    byte cnt = 8;
    while(cnt-- > 0){
        TX_OUT  = data & 0x01;
        DLY_9600BPS;                // Data Bit
        data >>= 1;
    }
    TX_OUT      = 1; DLY_9600BPS; DLY_9600BPS;  // Stop bit  
}

void u2raw_send_cmd(byte *data, byte len){
    for(byte n=0; n<len; n++){
        send_byte_9600(*data++);
    }
}

である(同期ずれを防ぐため2StopBitsとしている)。また9600bpsに相当するビット幅は104μsだがオーバーヘッドを考慮して100μsの遅延を入れて試したら動いたので、そのまま使っている。なおこのプログラムを呼び出す前段階として出力ポートの設定や、同期ずれを防ぐための割り込み禁止措置が必要である。受信はサポートしていないので正確にはUAT(Universal Asynchronous Transmitter)だ。

これを使えばUARTでLiDARの一通りのコマンドを実行できる。完全なソフトウェアUARTを作る事もできるが、それは後回しにしよう。

とりあえず、ドライバーの立ち上がり時のLiDARの制御は、

  1. ソフトウェアUARTで460,800bpsを9600bpsへ落とす。
  2.  ソフトウェアUARTでインターフェイスをI2Cへ変更。
  3. 以降I2CインターフェイスでLiDARと通信。 

とする。2.のI2Cインターフェイスへの切り替えは次のようなコマンドをソフトウェアUARTで生成している。


LiDARは一旦I2Cへ切り替えると以降はUARTへ戻すコマンドを実行しない限り一旦電源を切ってもI2Cのまま保留されるが、I2C通信時にUART信号を送っても無視されるので実用上はこれで特に問題はない。

 (続く)

 

 

2026年7月14日火曜日

LiDARを使った相対速度計(その8)

 さて、PIC上で動かすI2Cのドライバー(プログラム)であるが、以前、見様見真似で納得しないまま作ったものを再利用してみたが上手く行かない。最初は何とか動いたように見えたが、ソフトを弄っているうちにLiDARが全く応答しなくなり、不正なデータを送って内部状態が異常になったか壊れたと思ってLiDARをもう1個買い足したりしたが結果は変わらなかった。

仕方が無いので改めてI2Cドライバーを作り直した。今回はハード/ソフトに関する理解が進んだのか意外とすんなりと動き、LiDARも正常な応答を返すようになった。

I2CでLiDARを扱う場合は先ずIDを読んでみて、IDを正しく読めているかを確認する。 I2Cの場合、データの書き込みより読み出しの方が少しややこしいのいで、読み出しが成功すれば一安心だ。実際のI2Cのトレースを取得してみると、

LiDARのIDの取得、 

 測距データの取得、

ソフトウェアバージョンの取得、
シリアル番号の取得、

レーザーON、

なおTSD20でレーザーをOFFにすると測距データは20,000mmに固定される。

 (続く)

 

2026年7月13日月曜日

LiDARを使った相対速度計(その7)

 TSD20は思いのほか小さかった。コネクタも小さいので抜き差しすると壊しそうだ。接続線も簡単に切れそうに細い。

TSD20では測定頻度を毎秒50回を含む他の頻度に変更するのも上手く行った。

 TSD20を空に向けると測定値は20000mmとなり、マニュアルにあるような50000mmでは無い。これはTSD50のマニュアル記述の使い回しで修正を失念したのかな。

LiDARにUARTでSTOPコマンドを送ると1秒1回程度の頻度で次のデータを自発的に送ってくる(6番目の0xf0はチェックサムだ)。 

5a 0f 02 ff ff f0

 これが何を意味しているのかマニュアルに記述が無く、ネット情報も無く皆目分からない。たぶん Keep Alive 的な性格を持っているものと推察する。

 

さて、TSD10やTSD20ではUARTインターフェイスで上手く行ったが、一方TSD50では毎秒500回という固定した測定頻度の関係で9600bpsではデータを送りきれない。そこでI2Cインターフェイスに挑戦する事にした。併せてPICを容量の大きいPIC16F18326に変えるが、このPICには2個目のUARTが搭載されていないのでI2C専用、或いはソフトでUARTを実現する必要がある。

PICとのインターフェイスでLiDARでデフォルトのUARTを選んだ場合、UARTは全二重通信なのでデータはLiDAR主導で測定頻度に従って勝手に送られてくる。またLiDARへのコマンドの送信とレスポンスの受信も送信側の勝手なタイミングで行われる。一方、I2Cの場合はポーリング方式なのでマスター(PIC)側主導でデータを転送する必要がある。

従ってUARTではPICはLiDARから勝手に送られてくるデータを受信し処理すればよいが、一方I2Cを使う場合はPIC主導で定期的にデータを取得し、その結果を処理する必要がある。つまりUARTとI2Cではソフトの造りが違ってくる。

I2Cを使ったデータ転送は具体的にはLiDARの内部レジスタのデータの読み出し/書込みという操作である。I2Cを使う場合は、LiDARの内部レジスタの書き換えは500Hzの測定毎に行われると思われるが、それとデータ取得の関係(タイミング)についてデータシートには何も説明が無く、やってみないと結果は分からない。

LiDARのI2Cアドレスについてもマニュアルの説明では0x52と書いてあるが説明図では0x54(0b010101xx)みたいに見える。これも試してみないと分らないが、後のチェックで0x52が正解であることが分った。

(続く)

  

2026年6月12日金曜日

LiDARを使った相対速度計(その6)

前にLiDAR距離計で作った基板では TSD20やTSD50に対応できないので、新しく基板を起こすことにした。TSD20は電源電圧が3.3Vであり、TSD20やTSD50ではUARTの代わりにI2Cインタ-フェイスを使うことができるので、それらを加味して次の回路を設計した。なおPICには16F15325を使っているがメモリー容量が足りないは場合はピンコンパチで2倍のメモリー容量を持つ16F18326を使う。ただし16F18326にはUARTは1つしか搭載していないのでLiDARインターフェイスはI2Cに限定される。

そして次の基板を発注した。部品点数は増えたがSMDを裏面にも配置して基板のサイズは前のままである。

1週間を待たず基板が届き、早速組立てた。

センサーにはTSD50を試したい所であるが、高価なうえに上手く行くとも限らないので、とりあえずより安価なTSD20で試す事とした。

(続く) 

(追伸)

上の回路図でI2Cバス用双方向電圧レベル変換IC(PCA9306D)とPICの間のI2Cの信号線にもプルアップ抵抗が必要です。 

 

2026年5月29日金曜日

LiDARを使った相対速度計(その5)

 出来上がった相対速度計を室内(廊下)でテストしてみたが、測定距離が4~5m位になると測定値が安定しなくなるというよりランダムな値が出るようになる。その原因はS/Nの悪化か、空中の埃やエアロゾルの影響か、或いは測定原理に起因するものか分からない。

そもそも赤外線が1nsで進む距離は30cmである。これを使ってmm単位の距離を測るためには数ps単位の時間分解能が必要であり、そのため初歩的な方法では100GHz以上のクロックが必要で現実的ではない。 またLEDやフォトダイオードの応答速度なども大きく影響しまともな測定は出来ないだろう。

この点をCopilotに相談すると波形の相関処理を行う事でサンプリング周期の100倍以上の分解能を得る事が出来るようだ。逆に考えると、何らかの要因で波形が乱れて相関処理が上手く行かなくなると極端に精度が悪くなるのだろう。これ以上測定範囲を伸ばしたいなら上位のLiDARセンサーを買う必要があろう。いずれにしても距離を正確に計れなければ相対速度もヘッタクレも無い。

 さて、相対速度計を実際の車に持ち込んで動かしてみた。赤外線がガラス窓に直交するようにLiDARを向けるとガラス窓の反射を拾って窓までの距離を測った。一方、赤外線がガラス窓に直交しないように置くと数十cm~数mの範囲の出鱈目な数字を表示した。ガラスの赤外線の減衰が大きいのかガラスを通しては正しく測定できないように見える。そこでLiDARを車外に出してみたが結果は変わらない。外光の影響が大きいのかな。とにかくこのままでは上手く行かない。

 上位のLiDARを使ってみる必要があるようだ。上位のLiDARには距離を20mまで計れるTSD20と50mまで計れるTSD50がある。どちらを使うにしてもTSD10と互換では無いので一工夫が必要だ。例えばTSD20は電源電圧が3.3Vだし、測定頻度が200回/秒だ。TSD50では電源は5Vでよいが測定頻度が500回/秒なので9600bpsではデータの転送が間に合わない。


何処をどうトレードオフしようか?

(続く)