2019年8月8日木曜日

ANT->BLEブリッジの製作

ANTで無線送信されたパワー計の値をBLEに変換して無線送信するデバイスを製作しました。



Zwiftという、仮想空間内に自分のアバターをおき、サイクリングするソフトがあります。


PCに挿すANTドングルで自転車のパワー値を受信して、仮想空間内を進みますが、受信が安定しないことがあります。

ZwiftをインストールしたCPUの性能は、あまり関係しないようです。
2スレッドCPUのタブレットPCで安定する場合もあれば、16スレッドCPUのデスクトップでもANT受信に失敗し、0w(--w)表示となることもあります。
周囲の電波状況が大きく影響するによう感じます。

まじめに踏んでるときに0w表示になると萎えるので、これを解決するため
ANT無線信号をBLEに変換し、BLE信号をZwiftに受信させ安定通信するためのデバイスを作った次第です。

副作用として、このデバイスを使えば、ANTチップ非搭載のsmartphoneでも、BLE対応の市販アプリでパワー値を受信・表示できます。


動作は以下のとおりです。

- AP2モジュールで、近くのANTパワー値を受信、UART txピンでnRF52840に送信

- nRF52840のUART rxピンでANTデータを受信
 nRF52840でパワー値を算出。
 スイッチがON(PIN 20がLOW(GND接地))ならパワー値に約100wを追加。
 ジャスト100wにせず、1~12の乱数を足して合計100数wを追加することとします。
 増加値に数ワットの揺らぎを持たせ、ANTパワーが0wのときでも100+数wで人間がペダリングしているように見せかけることができます。
 これで峠の麓までは、ペダリングしなくとも勝手にアバターに移動してもらう、という自動運転ができます。

- nRF52840にてパワー値を:
 1. ANTフォーマットにしてUARTでAP2に送信、AP2からANTで無線送信
 2. BLEで無線送信

Bluetoothで定義されるCyclePowerService対応でパワー値を送信するのは初めてでした。
Adafruitが公開している心拍計センサーのソースコードを流用し、パラメータを若干追加修正したら動作しました。


ここで利用したnRF52840 Dongleなるものがリリースされていることを信州Maker管理人様から教えていただきました。

調べてみると、これはArduinoIDEでプログラムできる環境が整っていることを発見しました。
Adafruit社がBootloaderやライブラリを作ってくれており、ATMEGA32xと同じ感覚で簡単にプログラムを書き込めます。

ただし、nRF52840 DongleにAdafruit Boot Loaderを書き込む必要があります。

以下のサイトに今回のデバイスのソースコードを置きました(本日の日付をファイル名としています)。

(実際にアクセスする場合、末尾の000を削除して1138で終わるようURLを修正する必要があります。ロボット除けのためで、お手数をお掛けします)

ttps://sites.google.com/site/myfiles1138000


2019年4月19日金曜日

ArduinoとANT無線中継機とZWIFTオーバーテイクボタン

ArduinoマイコンでANT+規格の無線信号を送受信するための備忘録です。

ANT+で無線通信するモジュールとしてAP2と呼ばれるものがありました。

PINOUTも独特です。


これにUART接続(送信用Tx線と受信用Rx線の2線でデバイス間を接続)してコマンドを投げると、ANT+規格の無線信号を送信および受信できます。

nRF24AP2を利用したAP2モジュールはEOLのようで、私の入手した互換モジュールはこちら



◆左はAP2のコピー品
安定して動いてくれましたが、非通電状態でも、一度雨に濡れたら、動作不能となりました。

◆真ん中は、D52モジュール
AP2の後継で、チップは、nRF52832、PINOUTは互換。
でもソフト的には、完全互換ではなかったです。
正常動作のためには
- UART通信速度は9600bps以下で利用すること、
- コマンドを送ったら最低500ms待つこと
が必要なようです。

◆右は、最近みかけるAP2の変形バージョン
よくみるnRF24L01モジュールそっくりですが、これはnRF24AP2です。

PINOUTとschematic


ピンク印がBaudRate設定で、全部GNDに接続すると、
以下のチャートの通り通信速度が4800bpsに設定されます。
BR3 BR2 BR1 Baud Rate
0 0 0 4800
0 1 0 19200
0 0 1 38400
0 1 1 50000
1 0 0 1200
1 1 0 2400
1 0 1 9600
1 1 1 57600


手持ちのAP2互換モジュールは、8ch対応です。
つまり、チャンネル1でANT+のPower(ワット)信号を受信し、
チャンネル2でそのパワー値を送信することが可能です。

自宅のZWIFT用ANTレシーバは感度が低く、よく通信が切れるため、
クランクのパワー計のANT信号を中継してZWIFTに転送するデバイスを作りました。


Arduino ProMini(3.3v動作品)とAP2の接続図
UARTで、
ArduinoのTxをAP2のRxへ
ArduinoのRxをAP2のTXへ

ArduinoUno(3.3v動作に改造済)でも動作


ANTのパワー値を一度受信して、受信した数値を転送してます。
転送する際にパワー値をゴニョゴニョすると、オーバーテイクボタンを作れます。
「ボタンを押すと燃料の混合比が変わってプラス50馬力出力でマンセルをオーバーテイク」することはできませんが、ボタンを押すと、受信した生データに+100wの値を増加してZWIFTに転送、ZWIFT上で絡まれたくない相手を楽に振り切る、ということはできます。
チートとみなされると、まずいことになると思いますが、早速、中継器として動作実験開始・・・

ANTのシミュレータ上では、オーバーテイクボタンを押すと、283wの出力に100wを足して383wを受信できました。

でもなぜか途中で止まったり、ANT信号の受信に失敗したり。

どうもArduino UnoやProMiniで、SoftwareSerialを使ってANTモジュールと通信すると、安定せず、途中停止するようです。
ハードserialが2chあるArduino Microの3.3v対応品を取り寄せて、再度実験予定です。
2019/8/8更新:ArduinoMicroが思うように動かないため、nRF52をArduino化して実験しました(2019/8/8付けで投稿しました)が、やはり途中停止することがあり、ANTの受信は、途中停止を検出して、リセットする必要があると思います。

ANTの受信と送信を同時に行う今回のソースコードをUPLOADしました。
また、このコードでは、ZWIFT上で、ANTシミュレータの結果と異なり、0wの表示しかしませんでした。
ZWIFTは、たまにANT信号の受信に失敗し、0w表示となる問題があります。
今回のANT信号中継器を改良して、ZWIFTの0w表示問題も解決できればと思います。


新しいひずみゲージの貼り方を試しました

■4iiii社のひずみゲージの張り方
4iiiiの特許出願



クランクアームに直接ひずみゲージをはっていない。
クランクアーム(100)に接着剤(190)でアルミのプレート(195)を張り付け、そのプレートにひずみゲージ(102)を張っている。

これでもひずみを計測できるようです。

ということで、試してみました。
クランクの上に2mm厚のアルミプレートを貼りました。




アルミプレートの上側にR1,R3を、下側(クランクアーム接着面なので、クランクとアルミプレートにサンドイッチされてます)にR2,R4を配置。(写真の赤丸内、緑のひずみゲージがアルミ用、茶色のは鉄用で失敗したものをそのまま残してるだけです。)


クランクアームにトルクがかかり曲がりが生じると、その曲げがアルミプレートにも発生するので、アルミプレートのひずみを測定すれば、トルク測定が可能、というものです。
長期間つかった場合の信頼性は要検証ですが、とりあえず、動作するようです。
初期のゼロオフセット値がけっこうバラつく感じはしますが・・・
【2019/05/24追記
やはり、アルミ素材に鉄用のひずみゲージを張り付けた場合と同じようにゼロオフセット値が安定せず、コロコロとオフセット値が変化し、実用化は不可でした。

この方法だと、アルミプレートを瞬間接着剤でクランクアームに接着すれば、瞬間接着剤はがし液でプレートをはがして、再利用、ということも可能です。
ひずみゲージを貼る位置をあれこれ試すには、よい方法かと思います。

■クランクの表面を削るか
4iiiiの初代パワー計は、キットとして販売され、ユーザが自身でエポキシ接着剤を使ってパワー計センサーユニットをクランクに張り付けるキットとなっていました。
このとき、クランクアーム側は、サンドペーパーで削るのですが、アルミ面を完全に露出するまで削ることは求めてませんでした。




もちろん基本形は、クランク表面を600番の耐水ペーパで削り、完全にアルミ面を露出し、そこにロックタイト401で接着、ということになりますが、この程度けがいた状態でもOKな事例もあるようです。

■ひずみゲージの種類
Amazonの激安ひずみゲージでも、うまく機能させることに成功している方もいらっしゃいます。
http://shinshu-makers.net/shinshu_makers/2018/08/25/%E3%80%90%E3%83%91%E3%83%AF%E3%83%BC%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC2018%E3%80%91%E3%83%9A%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%BC%E5%82%99%E5%BF%98%E9%8C%B2/

激安ひずみゲージもそれ自体は、よく知られた製法で作られており、機能するもののようです。
ただ激安品は、アルミ用ではなく、鉄用です。
当方のスキルでは、鉄用のひずみゲージをアルミに張って、うまく動作させることはできておりません(3日前に試しに鉄に張ったところ、これは正常に動きました)。
うまく動かせる方もいるので、当方が何かを間違ってると思います。

日本メーカのアルミ用ゲージは、2mmと5mmの長さのものが比較的容易に入手できるようです。
ただ2mm品は、クランクアーム用には感度が足りないので、5mmを利用した方が楽だと思います(東京測器さんでは、5mm品も販売しているようです)。

経験上、面積が小さく感度が最も高いのはOMEGA社のものでした。
値段も最も高いのですが、2つのゲージが並列になっているものもあり、扱いやすいです。

4iiiiのパワー計を開発された方が、趣味でパワー計を開発していたころのブログです。たしか、OMEGAのものを利用されていて、私はこれをまねしたこともあります。
http://keithhack.blogspot.com/2013/05/testing-results.html



2019年3月14日木曜日

パワー値の算出とキャリブレーション


■パワー計のパワー算出式
パワー(watt) = トルク × 角速度

これをプログラムコードにすると
Power=Torque*(CadenceRPM/60)*6.28

以下、前回記事のAndroidパワー表示アプリで使用した、パワー算出コードです。

//calc Power
 iCdc = (6000000/iMills);  //ケイデンスを算出
              //iMillsはクランクが360度回転するのに要した時間ミリ秒

 iRead=iRead-(int)iZero; 
    //読み取り値平均からゼロオフセット値を引き、歪の変化量を抽出
             
iTorque =(iRead * 0.175 / iSlope); //スロープ値からトルクNmを算出
                  // クランク長175mm
if (iTorque <= 0) {iTorque=0;};
iPower  = (int) (iTorque * (iCdc/60*6.28)); //パワー(ワット)を算出


■ゼロオフセット値(iZero)のキャリブレーション
 負荷ゼロのときのひずみゲージ値を取得します。
 重りなしでクランクを地面に垂直に真下に向けて、ひずみゲージの値を読み取ります。
 5回計測して、 最高値と最小値を除いた3回分の値の平均をゼロオフセット値とします。
 市販のパワー計で、皆さんがよくやってるキャリブレーションです。
 温度が変わると、ゼロオフセット値も変化するため、キャリブレーションが必要になります。

■スロープ値(iSlope)のキャリブレーション

スロープ値=ひずみ変化量÷トルク(Nm)

クランク長:175mm
おもり重量:2.605Kg
の場合のトルク(Nm)= 2.605×9.81×175/1000 = 4.47213375

ゼロオフセット値:928788(実測値)
(クランクを垂直に真下に向けおもり無しのときのひずみゲージの読取り値)

クランクを3時方向(下記のwatteam方式は9時)に向けておもりを付けたときの値 :930838(実測値)

上記のひずみ変化量 = 930838-928788 = 2050

したがって、
スロープ値 = 2050/4.47213375=458.39
というように算出します。

これを自動計算するスプレッドシートを作りUPLOADしました。
ttps://sites.google.com/site/myfiles1138000
本日の日付の入ったXLファイルです。
(実際にアクセスする場合、末尾の000を削除して1138で終わるようURLを修正する必要があります。ロボット除けのためで、お手数をお掛けします)



watteam社は、ユーザが自身でスロープ値のキャリブレーションを行う際、以下の方法を指示しています。
オモリの水入りバッグ(5Kg程度)を両方のクランクにつけているのがミソです。

私は、オモリのペットボトルを片側につけ、ペットボトルの重さに苦労してましたが、バイクを逆さにして両方のクランクにオモリをつけると楽そうです。
天才的発想と感心してしまいました。


















オモリは、2.6Kg程度では軽すぎで、Powertap比で最大10%程度の差が出ます。
SRM社は20Kg程度を使っているそうです。
本来は、体重に匹敵する数十キロの オモリが必要です。
数十キロの重りはぶら下げられない・・・と思ってましたが:

https://shinshu-makers.net/shinshu_makers/2017/03/21/%E3%80%903%E6%9C%8821%E6%97%A5%E3%80%91%E3%83%91%E3%83%AF%E3%83%BC%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC%EF%BC%9C%E6%A0%A1%E6%AD%A3%E5%8F%B0%E8%A9%A6%E9%81%8B%E8%BB%A2%E3%83%AD%E3%83%BC%E3%83%89/

すごいアイデアです。やはりプロ中のプロの技術者は違うと感心しました。
耐荷重40Kgということで、こちらが王道かと思います。


■ その他の校正方法

1. パワータップハブで校正

後輪にパワータップハブをつけ、サイコンにパワー値を表示し、
自作パワーメーターのスロープ値を変更していき、パワータップと同じパワー値の表示になるようにします。
お手軽なうえ、「パワータップと同じ値がでている」という安心感があります。


2. 他人頼み校正
自作パワーメーターのスロープ値を適当に入れて、時速30Km/h時に200wくらいと表示されるようにします。

次にパワーメーター付きのバイクに乗ってる仲間とヤビツ峠とかを一緒に上り、一緒にゴールして平均何ワットだったか聞き出します。
相手との体重差を計算にいれつつ、自作パワーメーターと何ワット差があるか把握して、その差をなくすようスロープ値を変更します。
間違っても、自分よりも速い人と一緒にいってはいけません。
千切られたうえに、「平均出力は320wくらいかな」とドヤ顔されて、
普段の練習方法の校正が必要と凹んでしまうだけです。

■ご参考
パワー、トルク、角速度の解説動画です。
 https://www.youtube.com/watch?v=MO5Ylm9qJ5Q
解説者の方は、世界で最初に自作パワーメータの作り方を公開し、後に4iiii社と組んで商品化したエンジニアです。
この動画は、4iiiiと組む前に、自作パワー計Version3を趣味で製作された際に公開されました。

私は、パワーとトルクの違いも説明できなかったド素人ですが、こちらの方が公開された情報をもとに、パワー計の作り方を学びました。

彼はブログの中で、エンジニアとして、この世に革新的なものを生むには、 まず自分が基本的な事項を公開し教える、とのポリシーのもと、情報公開をされていました。
ありがとうございます。








誰でも簡単!?手作りパワーメーター(準備中)

現時点で最もお手軽に作れるクランクアーム型パワーメーターを製作しました。

■必要なハードウェアは
1)歪ゲージ付きアルミクランクと
2)電子回路

電子回路の基本モジュールは
- ADコンバータHX711(約150から350円。eBay、秋月等)と
- 無線マイコンBL652(約900円@Digikey)
の2つのみです。




■動作原理
電子回路に通電すると、
- マイコンBL652がADコンバータHX711にひずみゲージの値を読み取るよう命令を発行
- HX711は、約80回/秒でBL652にひずみゲージの値を送信
- クランクが1回転し、REEDスイッチがバイク・フレーム上のマグネット上を通過すると、REEDスイッチが磁力でONとなり、BL652が1回転に要した時間(ミリ秒)とそれまでに取得したひずみゲージの読み取り値の平均値をBLEで無線送信
- AndroidでBLE信号を受信し、パワー値を算出し、画面にパワー表示

以降、この繰り返し
です。

■組み立て

各電子部品を以下のように結線します。


赤線と黒線は、電源ラインです(赤が+、黒が-)。
ADコンバータとマイコンの接続は、緑とオレンジの2本のみの簡単配線です。

電池は、爆発リスクがなく充電できるeneloop、これをAE-XCL102D333CR-G(300円@秋月)で3.3vに昇圧しています。

HX711は読み取り速度を80Hzに変更(PIN15を浮かせてVDDに接続)しておきます。
HX711をひずみゲージに接続します。
<解説準備中>



個々のひずみゲージはただの可変抵抗と考えられ、プラスマイナスの極性はありません。
でも裏表はあるので、張り付けるときは、要注意です。

私は、アルミ用のひずみゲージを使用しています。
鉄用のは、未だに使いこなせておりません。

張り方はこちらで紹介されています。
https://shinshu-makers.net/shinshu_makers/2019/03/11/%e3%80%90mft2019%e3%80%91%e7%b0%a1%e5%8d%98%e8%87%aa%e4%bd%9c%e3%83%ad%e3%83%bc%e3%83%89%e3%82%bb%e3%83%ab%e8%ac%9b%e5%ba%a7%ef%bc%91%ef%bc%9c%e5%8d%8a%e6%97%a5%e3%81%a7%e4%bd%9c%e3%82%8c%e3%82%8b/

ありがとうございます。

ひずみゲージは4個を1組にWheastone bridge(下のOMEGA社の資料の図B)として結線します。
なぜか・・・
頭の良いWheastone氏がそれがよいと考えたから。
それを真似すれば間違いない。
当初は、本当にこんなレベルでやってました。








配線が無事に完了すると(120Ωのゲージの場合)
Exc+とExc- 間は約120Ω
Exc-とSig+間は約90Ω
Exc-とSig-間は約90Ω
上記から大きく抵抗値がずれる場合は配線に失敗してるので、見直します。

クランクへの貼り付け位置は、下のOMEGA社資料にある、bending strain計測用の図Cの位置に貼るのが基本のようです。





ハード的にはこれだけです。
あとフレームに100均マグネットを一つ、クランク上のReedスイッチ(1パック300円@秋月)が通過するそばにはります。

以下、パイオニアの説明書の引用ですが、同じように磁石をフレームに貼ります。
“マーク” との記載あるクランク箇所にReedスイッチをつけます。


ソフトウェアについては、
AndroidからマイコンBL652に、パワー計のファームウェアをUPLOADし、
<UPLOAD方法要説明追加>
対応アプリをAndroidにInstallすれば、パワー表示できます。

上記はデバッグ・アプリです。
クランク上のBL652からは、「:;001812E004D00268」
というフォーマットで文字列がBLE無線送信(advertise)されています。

この文字列の意味は上の図のとおり、
青□が歪ゲージの読取値(平均)
緑□が温度(BL652内蔵温度センサ)
ピンクがクランクが360度回転に要した時間ミリ秒
赤字がこれらをもとに算出したパワー値(3回転Average)

上記のAndroidのデバッグ・アプリは、このadvertiseを受信し、
パワー値を算出し、表示しています。
このadvertise送信を受信する方法は、connectionをはる必要がないので、安定して受信できるメリットがあります。
BLEのconnectionが切れて、データを受信できなくなることがなくなります。

ただ、このADVERTISEを1秒間に複数回受信できるのは、私の知る限りSONYのXPERIA Zシリーズのみです。
ジャンクなAQUOS, ARROWS, GALAXYのいづれも、受信が安定せず、最悪6秒程度、データを受信できない場合もありました。
BLEチップのファームかドライバの実装の問題のようで、ANDROID OSからでは、どうやっても解決できませんでした。


BLE無線送信用のファームウェア(.inoファイル)と
Androidデバッグ・アプリ(.zipファイル)のソースコードをUPLOADしました。
ttps://sites.google.com/site/myfiles1138000
本日の日付のファイル名です。
(実際にアクセスする場合、末尾の000を削除して1138で終わるようURLを修正する必要があります。ロボット除けのためで、お手数をお掛けします)

Androidの開発環境は、
Ubuntu 16.04
Android Studio 3.1.2

【ANT+対応(ZWIFT対応)について-ご質問へのご回答】

ZWIFTでパワーデータを受信するには、パワー計がBLEかANT+のPowerプロファイルに対応する必要があります。

今回の記事のパワー計は、いずれのパワー計プロファイルにも対応していません。
あくまで、BLEのAdvertiseをAndroidで受信して、パワー表示をしてます。



これをANT+に対応するには、
1.市販品のようにクランクからANT+で無線送信するか、
2.パイオニアのように一旦サイコン側でパワーデータを受信し、ANT規格に変換して送信しなおす必要があります。

上記1.は、クランク上の電子回路が複雑になります。クランク上の電子回路はその衝撃と遠心力で故障リスクが高いため、なるべく簡素化したいので、ANT送信モジュールは載せたくありません。
上記2.は、AndroidでANT無線送信する手段が考えられますが、簡単に作れるソースコードを持ち合わせておりません。

そこで、クランクからAdvertiseされてる無線データを拾い、ANT+規格に変換してZWIFTやGARMINに送信するデバイス「ANTコンバータ」を作りました。



クランクのデータは、AdvertiseとしてTV放送波のようにbroadcastされているので同時にAndroidとANTコンバータで受信可能です。

ハードの構成


BL652でクランクのデータを受信し、ArduinoProMiniにTx信号線で送信、
Arduinoは、HARDWARE Rx端子で受信して、パワー値を算出、ANT送信モジュール(D52またはAP2モジュール。詳細は2019年4月19日の「ArduinoとANT無線中継機とZWIFTオーバーテイクボタン」にあります)でANT送信します。

ANT+については、2019年5月現在、自作パワー計でもZWIFTはパワーデータを受信しています。
ただ、ZWIFTの問題として、PCのスペックが低いと、時折0Wと表示されてしまう問題を抱えているようです。


ANTコンバータ用のBL652とArduinoのソースコードを以下のサイトに置きました(2019/05/25の日付をファイル名としています)。

(実際にアクセスする場合、末尾の000を削除して1138で終わるようURLを修正する必要があります。ロボット除けのためで、お手数をお掛けします)

ttps://sites.google.com/site/myfiles1138000

なお、ANT通信を行うには、NETWORK KEYを入手してソースコードに書き込む必要があります。
このあたりは信州Makers管理人様が詳しく公開されております。
いつもありがとうございます。
http://maru-yo.net/shinshu_makers/2017/08/15/%E3%80%90%E3%83%91%E3%83%AF%E3%83%BC%E3%83%A1%E3%83%BC%E3%82%BF%E3%83%BC%E3%80%91antatmega328p%EF%BC%88%E5%86%85%E8%94%B58mhz%E6%8E%A5%E7%B6%9A%EF%BC%9C5v-3-3v%E3%82%82%EF%BD%8F%EF%BD%8B%EF%BC%9E/







2018年9月26日水曜日

スピード計の製作(ハブ巻き付け型)

GARMINの自転車用スピードセンサーで、ハブに巻き付けるタイプがあります。

これを真似てBLE送信するものを製作してみました。
これはマグネット不要で、簡単に他のホイールに付け替えられるので、従来のマグネットセンサーのものより便利です。
精度は劣るようですが、私は、スピード計に精度は求めないので、こちらの方がお気に入りです。

GARMINの偽物のようなものが格安で売られたりしており、経済的には自作するより購入した方がよいのですが、自己満足度が高いので、製作してみました。

ハード構成は、BL652無線マイコンに、秋月の3軸加速度センサモジュール ADXL335を取り付けました。
配線は、BL652のアナログ入力4番ピンとADXL335のY軸出力を結線しただけです。
tmpdata=GpioRead(4)
この一行で、ADXL335のアナログ出力値をtmpdataに代入できます。
システム全体の消費電力が低いのでボタン電池CR2032で駆動可能です。

消費電力は、無線送信込みで、1秒間に100回ADコンバートして、0.8mA、
2000回ADコンバートすると、1.7mA程度でした。
1秒間に100回のサンプリングでは、明らかに精度が足りませんが、電池寿命を優先しています。センサー類の電池切れは、自転車でもっとも残念なイベントの一つと思ております。

ADXL335は、加速度をアナログ出力するので、BL652のADコンバータでデジタル値に変換し、角度情報を得ます。

実験中、スピード計をハブにつけたり、はがしたりが面倒なので、「ハブ回転シミュレータ」を開発しました。
↓こちらです。サラダ水切り器です。

これは、上のハンドルを回すと、中身のザルが回転し、遠心力で、サラダの水切りができます、というデバイスです。
これに今回のスピード計をいれてテープで固定、ハブ回転方向にグルグルすると、センサー角度に応じて、センサーから値が得られました。
1回転すると、最大値が490以上、最小値が340以下でした。最大値、最小値ともにけっこうブレ幅があります。この辺を詰めないと、精度はでないと思いますが、とりあえずテストしてみます。
アルゴリズムは、ADXL335の読み取り値が345を下回ったら、1回転したと判定します。
1回転したら、1回転に要した時間をミリ秒単位で算出し、
BLEデバイスのデバイス名の最後に、16進数の文字列として設定し、
デバイス名をBLEのAdvertise送信します。
これをBLE対応のAndroid端末で独自アプリで受信、デコードして、スピードとして表示します。
受信側はAndroidでなく、BL652でも可能です。
BL652で受信して、Nokia5110液晶に表示すれば省電力スピードメーターの完成です。

システム全体が小さいので100均のLEDライトに仕込むとキレイに収まりそうです。

まだ、収納できる段階でないので、
とりあえず、ハブにガムテープで巻いて走行しました。

結果・・・そこそこ動きました。
サラダ水切り器シミュレータでも40Km/h以上では不安定でしたが、
実走でも、かなり不安定で、しばしば10Km/h以上低く表示されたりと
アルゴリズムを考え直す必要がありそうです。
個人的には、このくらいでも、無いよりマシと感じます。

スマホ表示

0x:0000019A0000000B7C
と数字ばかり並んでますが、これが今回のスピードセンサーから無線Advertise送信されたBLEデバイス名です。
最後のB7Cは、10進数に直すと2940、つまり1回転に2940ミリ秒を要した、という意味です。
これをもとにスピードを算出してます。

このAndroidアプリは、AndroidStudioのBluetooth Le Gattというサンプル・プログラムを改変してます。

AndroidStudioでダウンロードしたサンプルコードですが、Android6以上では、なんと動きません。
サンプル・コードが動かないとか、意味が分からないのですが、なぜかAndroidでは、頻発するので、敷居が高く感じます。
以下のPermissionをmanifestとアクティビティのOnCreateにそれぞれ追加するとAndroid6でも動作しました
<uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    if(Build.VERSION.SDK_INT >= 23)
    {
        this.requestBlePermission();    }




@TargetApi(23)
private void requestBlePermission(){
    if(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
        requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION        },1);    }
}

今回は、暫定的にAndroidアプリを作りましたが、Androidアプリは、スマホをサイクル・コンピュータとして利用する際に汎用的に利用できるよう、もっと汎用性のあるつくりにしたいと考えております。

今回のスピードセンサー用BL652のソースコード、および
Androidのスピード表示アプリのソースコードを
以下のサイトに置きました(本日の日付をファイル名としています)。

(実際にアクセスする場合、末尾の000を削除して1138で終わるようURLを修正する必要があります。ロボット除けのためで、お手数をお掛けします)

ttps://sites.google.com/site/myfiles1138000

公開ソースコードは備忘録として利用しているため、スピードセンサーに関係ないコード(実験中のパワーメーターのコード)も混ざっており大変読みにくくなっております。











2018年9月20日木曜日

BL652 - BLEマイコンで温度センサー(ソフトウェア編)

BLEモジュールのBL652を用いて、温度を計測しスマホにBLEで送るデバイスを作りました。
BL652は、Noridic社のSDKを使わずにsmartBASICと称する BASIC言語でソフト開発が可能で、開発時間を短縮できます。

今回の温度計測は、BL652のベースであるnRF528チップの内蔵温度計を使用しています。
データシート上、計測誤差が±4度と、温度計としては実用範囲外ですが、Garmin等のサイコンの温度表示もこのレベルかと思います。

smartBASICでは、簡単に温度を計測できる関数がありました。
i=SYSINFO(2024)
これで変数iに温度(摂氏×10倍)が代入されます。



1.任意のテキスト エディタでBASICコードを書きます。
特に開発環境に指定はありません。

















// Definitions
//******************************************************************************
//#define TEMP_MANTISSA                        2711
#define TEMP_EXPONENT                        -2
#define UUID_HEALTH_THERMOMETER_SERVICE      0x1809

//#define UUID_HEALTH_THERMOMETER_SERVICE      0x1818

#define ENABLE_DEBUG_PRINTS                  1
#define BLE_DISCOVERABILITY_GENERAL          2
#define BLE_APPEARANCE                       0
#define MAX_DEVNAME_CHRS                     20
#define BLE_CHARVAL_AD_TAG                   0x16

#define ADV_SCAN_IND                         2
#define ADV_FILTERPOLICY_ANY                 0

        //Advertise interval
#define ADV_INTERVAL_MS                      250
        //Advertise timeout
#define ADV_TIMEOUT_MS                       0
        //Whitelist Policy in Adverts
#define ADV_WHITELIST_FILTER_POLICY          ADV_FILTERPOLICY_ANY

//******************************************************************************
// Global Variable Declarations
//******************************************************************************
dim rc         //Result code
dim devName$   //Device name
dim hChar      //Characteristic handle
dim hSvc       //Service handle
DIM  TEMP_MANTISSA

//Example :: BleVSpWrite.sb (See in BL652CodeSnippets.zip)
#define GPIO_TEMP_SENS           3 

DIM tx$,scRpt$,adRpt$,addr$,hndl,cnt,iToggle,adc
DIM iInterval,iTimerCount,startTick,prevTick,veloTick,iGcounter
iInterval=1
iGcounter=0
DIM tmpdata, data
DIM i 
DIM iCrankPass, iPower
//------------------------------------------------------------------------------
// For debugging
// --- rc = result code
// --- ln = line number
//------------------------------------------------------------------------------
Sub AssertRC(rc,ln)
    if rc!=0 then
        print "\nFail :";integer.h' rc;" at tag ";ln
    endif
EndSub
//------------------------------------------------------------------------------
// Register Error Handler as early as possible
//------------------------------------------------------------------------------
sub HandlerOnErr()
  if (ENABLE_DEBUG_PRINTS!=0) then
    print "\n OnErr - ";GetLastError();"\n"
  endif
endsub

//------------------------------------------------------------------------------
// This subroutine gets called first
//------------------------------------------------------------------------------
sub OnStartup()

endsub

//******************************************************************************
// Handler definitions
//******************************************************************************

//Example :: TimerRunning.sb
FUNCTION HandlerTimer0()
DIM rc,dvcNme$,nmeWrtble,apprnce,MinConnInt,MaxConnInt,ConnSupTO,sL,sTgt$,tmp$
DIM addr$ : addr$=""

DIM discovMode : discovMode=0 
DIM advAppearance : advAppearance = 1
DIM maxDevName : maxDevName = 22
DIM advRpt$ : advRpt$=""
DIM scRpt$ : scRpt$=""

    dim scnRpt$  //Empty scan report

//----------------------
nmeWrtble = 0             //Device name will not be writable by peer
apprnce = 768             //The device will appear as a Generic Thermometer
MinConnInt = 500000        //Minimum acceptable connection interval is 0.5 seconds
MaxConnInt = 1000000       //Maximum acceptable connection interval is 1 second
ConnSupTO = 4000000        //Connection supervisory timeout is 4 seconds
sL = 0                   //Slave latency--number of conn events that can be missed

PRINT "\nSystmp 2024    = ";SYSINFO(2024) 

i=SYSINFO(2024) 

//---Advertise

SPRINT #tmp$, " ";integer.h' i
tmp$=RIGHT$(tmp$, strlen(tmp$)-4)
sTgt$=tmp$
dvcNme$="temp.="+sTgt$

nmeWrtble = 0                
apprnce = 768            
MinConnInt = 500000          
MaxConnInt = 1000000         
ConnSupTO = 4000000      
sL = 0                      

rc = BleGapSvcInit(dvcNme$,nmeWrtble,apprnce,MinConnInt,MaxConnInt,ConnSupTO,sL)

IF BleAdvRptInit(advRpt$, discovMode, advAppearance, maxDevName)==0 THEN
 PRINT "\nAdvert report initialised"
endif

PRINT BleAdvRptAddUuid16(advRpt$, 0x180F,0x180A, -1, -1, -1, -1)
PRINT BleAdvRptsCommit(advRpt$, scRpt$)

//rc =BleScanStart(20000, 0)
PRINT "\n --- New DevName : "; BleGetDeviceName$()
IF BleAdvertStart(0,addr$,25,60000,0)==0 THEN   
    PRINT "\nAdverts Started\n" 
endif

ENDFUNC 1         //remain blocked in WAITEVENT
        //exit from WAITEVEN if end func ZERO0
//----------------------------MAIN C----------------------------------
ONEVENT EVTMR0 CALL HandlerTimer0

//setups------------------------------------------------------------------------------------------------
TIMERSTART(0,1000,1)  //4 NG 14 work    //start a 1000 millisecond recurring timer
PRINT "\nWaiting for Timer 0"
//Remove resistor 
PRINT GpioSetFunc(GPIO_TEMP_SENS, 1, 2)  
//Analogue in 
PRINT GpioSetFunc(GPIO_TEMP_SENS, 3, 0)

WAITEVENT

PRINT "\nExiting..."
2.オンラインコンパイラで、BL652(とfirmwareのバージョン)を指定し、上記で書いたBASICのファイルを選択し、XCompileボタンを押すと、ソースがコンパイルされ、実行ファイルがダウンロードされます。
エラーがあると、ブラウザにエラー箇所が表示されます。




Laird社推奨のUwTerminalXを使用して、上記の実行ファイルをBL652に書き込みます。
まず、COMポートの設定を行います。


続いてTerminalタブで右クリックー>LOAD+RUNー>ファイル選択
でBL652に書き込む実行ファイルを指定すると、書き込めます。
 LOADとRUN・・・懐かしい。



書き込みが完了すると、自動的に実行ファイルがRUNされます。
PRINT文の出力は、Terminalに表示されます。


“Systmp 2024=”の値が温度です。(摂氏×10倍)
“New DevName” は、BL652モジュールがBLEデバイスとしてAdvertiseしてる名前です。


↓スマホ側の表示です。
BLEデバイスをスキャンすると、以下のようにtemp.=として温度(摂氏×10倍)が16進数でデバイス名として表示され、プログラム通りにスマホに無線送信(Advertise)されていることが確認できます。



BL652のsmartBASIC開発は、 オンライン・コンパイラを利用するため、面倒なSDKの開発環境を構築する必要がありません。
一見お手軽ですが、オンラインコンパイラが閉鎖されると、BASICでは何も開発できないリスクは感じます。
ただ、最後は、Nordic社の開発環境を利用して、ソフト開発はできるので、購入したBL652がゴミになるリスクはないと思います。


2019/05/24追記

BL652を腕時計型デバイスに組み込めるか。
BL652は、以下のように小型です。
素手ではんだ付けができる限界サイズといえる小ささです。






腕時計型デバイスを作成するにあたり、
今回のようにBLEのAdvertiseによってデータを送信し、
XperiaZシリーズで受信するのであれば、
何ら問題ないとおもいます。
消費電力も小さくCR2032で賄える(2ma以下)で動作可能と記憶してます。

しかし、BL652でAdvertiseし、BL652でスキャン/受信すると
データの受信にタイムラグ(4秒程度)が生じます。
原因は調査中ですが、ややインパクトがあるので、
BL652間通信は、VSP(VirtualSerialProtocol)と称する
BLE上でUART通信する技術を用いることとなるかと思います。
この場合、マイコンのリソース/パワーの多くを無線通信にもっていかれるため、
心拍センサーとのI2C通信が安定的に行えるか、やや不安がございます。

BL652でI2Cは行ったことはございませんが、万一、安定しない場合、
I2Cの制御用にBL652を一つと、無線送信用にBL652をもう一つと、
2CPU体制にすることで解決は可能かと思います。