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がゴミになるリスクはないと思います。


2018年9月15日土曜日

続・ANT+サイコンの製作

ANT+対応サイコンをDynastream社のD52無線マイコンを用いて組み立ててみました。

↓標準版のD52モジュール
 https://www.digikey.jp/product-detail/ja/dynastream-innovations-inc/D52QD2M4IA-TRAY/1094-1023-ND/6149451
 ↓加速度センサ内蔵バージョンです。
 https://www.digikey.jp/product-detail/ja/dynastream-innovations-inc/D52QD2M4IA-A-TRAY/1094-1024-ND/6149452


前回(2017年5月公開)は、ANTモジュールにBC-ANT-シリアルを利用しましたが、私のような素人には扱いが難しく、不安定になったり動作不能になったりと悩みました。

シリアル通信でコマンドを発行することによりANT+の信号を受信することができるモジュールは、以下の候補があります。
これらはNordic社の難解なSDK環境を構築することなく、シリアルコマンドでANT通信を実現できるので、私のような素人には、お手軽で、開発時間を短縮できるメリットがあります。
- BC-ANT-シリアル
- nRF24AP2
- D52(nRF528ベース)
今回は、D52を選択しました。
上の写真では、D52で受信したANT信号(パワー値283w)を秋月のArduinoUnoに送信、Nokia5110という200円液晶に表示しています。



便宜上、上記のような2システム構成です。
赤枠のシステムは、D52でANT+信号を受信し、ArduinoProMini8Mhz(3.3v動作)でテキストに変換してシリアル送信します。
オレンジ枠のシステムは、上記ArduinoProMiniからテキストを受信し、Nokia5110液晶に表示します。

D52とArduinoProMiniの接続図
電源Vcc, GNDとTx、Rxを接続するだけです。

D52のPINOUT

ArduinoUnoは5v動作のため、D52のような最大電圧3.7v程度のモジュールを接続するにはいちいち電圧を落とす必要があり面倒です。

私は5vが必要なデバイスをほとんともっていないので、秋月の基板のパターンを以下のようにカットして、5vラインを切断、代わりに3.3vを供給し、システム全体を3.3v動作に改造しています。3.3vで16Mhz動作となるので、オーバークロックとなりますが、短時間であれば、動作します。安定性が必要な場合は、クロックダウンが必要です。






今回のD52でANT受信を行うArduinoソースコード、および
Nokia5110で値を表示するArduinoソースコード(別途Nokia5110用ライブラリが必要)を以下のサイトに置きました(本日の日付をファイル名としています)。

(実際にアクセスする場合、末尾の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年8月16日木曜日

BL652 - BLEマイコン(ハードウェア編)

BL652というBluetooth Low Energy対応の小型マイコン・モジュールを入手しました(約900円@digikey)。


搭載されているマイコン自体はnRF52ですが、Laird社独自のsmartBASICでプログラムを書き込めるのがウリです。
nRF52は、Nordic社のSDKが不思議な出来栄えで、素人には使いこなすのが厳しかったですが、smartBASICを使えば、このようなSDK不要、開発環境構築不要、と謳ってます。

BL652への書き込みは、115200bpsでUART接続で行いました。
書き込みに使用したUSB-シリアル変換は、秋月のArduinoUno互換ボードAE-ATMEGAです。
これは、良くできていて、USB-シリアル変換のラインのジャンパを外すことにより、USBーシリアルの信号を外部に取り出して、外部のマイコン(ArduinoProMini、BL652等)にも接続・書き込みが可能です。








































BL652から引き出す最低限必要な配線は:
-GND, VDD (電源)
-UART RX, TX(データの有線送受信。それぞれUSB-シリアルのTX, RXへ接続)
-Reset(リセット。GNDに通電するとリセット動作)

半田づけするには基盤のピッチが狭く、45歳以上の方は老眼鏡必須レベルです。
フラックスを使えば、手で半田づけできるレベルでもあります。


はんだ付けを終え、テストプログラムを書いてみます。
BL652は、温度センサを内蔵しているので、温度を計測し、smartphoneで表示することとします。
BLEの通常のプロトコルでは、smartphoneからデバイスを検索=>接続(connect)=>温度データ読み取り、となります。
しかし、BLEは、ここの“接続”ができない、ないし勝手に切断され、不安定と感じます。

ANT+通信では、このような“接続”がなく、ANTセンサーはブロードキャストを行い、受信機はそれを拾って表示するだけです。当然、エラーで拾いもれも発生しますが、大勢に影響はありません。
この結果、接続がきれました、とかエラー表示され通信ができない自体は回避されてます。

そこで、BLEでも、このブロードキャスト方式で送信を行うこととしました。
Beaconとかいうプロトコルがこれに該当するようですが、制約が面倒なので、独自のプロトコルとします。

BLEの子機は、親機に対して、自分の名前とアドレスをAdvertise送信します。
これを受けて親機(smartphone等)からBLEスキャンをかけると周囲の子機が以下のように表示されます。
今回は、この子機の名前文字列に温度データを乗せてしまおう、という作戦です。
これなら、親機が子機に接続する必要もなく、子機がブロードキャストしてるデータを親機が拾うだけで、ANTと同じ安定動作が期待できます。

実際にやってみた図です。


名前欄に“Dgrade#1=369”と表示されてますが、ここの369の数値が温度データでリアルタイムに変化し、表示されます。(Dgrade#1は勝手につけたデバイス名です。とくに命名ルールはないようです)
36.9度の屋外で実験してるわけではないので、温度データがおかしいのですが、原因は後日究明するか、もっと精度の高い温度センサーを実装しようと思います。

この方式のメリットは、BLE子機と接続(コネクション)を張る必要がないので、複数のBLE子機のデータを1親機で拾ったり、逆に1つの子機のデータを複数の親機で拾うことが可能です。

BLE子機からパワー計のデータを送信し、smartphoneで受信・表示しながら、他の親機でも受信し、ANTプロトコルに変換してGARMINに送信、とかできてしまいます。

応答性もまあまあで、シフトレバーにスイッチを付け、スイッチオンで“Dgrade#1=SHIFTDOWN_ON”、スイッチオフで“Dgrade#1=SHIFTDOWN_OFF”を送信し、受信機でリアルタイムにスイッチのON/OFFを把握できます。
これを使えば、Di2のシフトスイッチを無線化できるうえ、SRAMのeTapのように、左右のレバー同時押しで、フロント変速とかも自由自在です。

NGな用途は、無線で部屋の照明全部消し等をするセキュリティに影響のある分野です。
子機のスイッチの状態を複数の親機に無線伝達できるため、照明ON/OFFや鍵のLock/unlockとか技術的には可能ですが、セキュリティ的に相当マズイと思います。

ソフトのコンパイル・書き込みは方法は、ソフトウエア編で紹介いたしました。




2018年7月24日火曜日

Bluetoothモジュール比較

秋月にてBLE(BluetoothLowEnergy)の通信モジュールAE-TYBLE16を発見しました。

http://akizukidenshi.com/catalog/g/gK-12339/

これは有線のUARTインターフェースに接続すると、UARTのデータを勝手にBLE規格で無線送信してくれる優れモノです。

使い手は、難しいBLEのお作法を勉強することなく、既存のUARTインターフェスにこのモジュールを接続するだけでBLE上でデータを送受信できます。

パワー計を自作する場合、クランクとハンドルバーの表示器の送受信にこの無線機を使うと便利そうです。
(図は、シマノの特許出願図面です。)















実際、使ってみました。




上の動画のGarmin表示は、PowerTapハブのデータ、スマートフォン表示は試作した3000円パワー計のデータです。
AE-TYBLE16を使用して、クランク上のマイコンで算出したパワー&ケイデンス値をスマートフォンにBLE送信してます。

モジュールの製造元の太陽誘電が本モジュール対応のAndroidアプリのソースコードを配布しているので、ユーザはこれを改造して動画内のタコメータアプリとかも簡単に作れます。

従来は、Bluetoothクラッシックのモジュールを使用してましたが、消費電流が20mAを超えるため、単四電池では10時間持たない感じでした。



手持ちのBluetoothモジュールの3.3v駆動時の消費電流を計測しました。
HC-05(20mA), SPP-CA(9mA), AE-TYBLE16(1.8mA), HM-10(8mA)

AE-TYBLE16単体であれば、ボタン電池で駆動できるレベルです。

これをマイコンに接続する際は、
Rx ー>Tx
Tx ー>Rx
Vcc  ー>Vcc
GNDー>GND
のように接続するだけです。


同様のモジュールに、Nordic社のNordicUartServiceを搭載したモジュールを過去に使用しましたが、BLEが原因なのか不安定でした。

AE-TYBLE16をジャンクで入手したXperia Z3、Z4、AQUOS PHONE ZETA、およびAQUOS SERIE SHV32でテストしたところ、(検証が必要ですが)Androidのバージョンが重要なようでVer.5未満では接続が不安定になることがありました。





2018年1月3日水曜日

最安パワー計製作計画 プチ成功

クランクアームにひずみゲージを貼り付けるパワー計では、クランクアームの捻じれの程度によって、見かけ上パワー値が上下してしまう問題がありました。
クランクアームの捻じれは、ペダル軸の外側を踏むとより大きく発生します。

通常踏んでいる55mm地点付近よりも110mm地点を踏んだ方が、クランクアームの捻じれが大きくなり、見かけ上のパワー値が大きくなってしまいます。

そこで、この見かけ上のパワー値を補正して真のパワー値を算出する方法を試しました。
すでに各社の特許出願に記載されている技術で、何も独創的なものはありません。

ひずみゲージセットアップ

曲げ計測用(赤丸)
ペダルを踏むとクランクアームが下方向に曲がり、クランクアームの上面が伸び、下面が縮みます。
この変化を赤丸ひずみゲージでとらえて、電圧としてフィードバックします。

ねじれ計測用(青丸)
クランクの側面に45度の角度でひずみゲージを貼り付けます。クランクアームに捻じれが生じると、捻じれ方向により、片側のひずみゲージが伸び、もう一方のゲージが縮みます。このように2つのゲージでひずみを捉えて電圧に変換することのより、2倍の感度を実現します。

実物・・・汚い・・・


ハードウェア構成
今回、2系統のひずみゲージ・ブリッジからデータを取得するため、ひずみゲージが返す電圧の変化をデジタルに変換するADコンバーターを2個設置しました。



HX711は1個でも3チャンネルの接続端子がありますが、2チャンネル分を同時に80回/秒で変換するのは無理と思い、ADコンバータを2個づけにしてみました。
Arduinoマイコンから読み取りコマンドを同時に2つのADコンバータに送信し、結果を同時取得します。

ADコンバータHX711からの読み取りルーチンは以下のとおりです。
long AE_HX711_Read(void)
{
  long data=0; long data2=0;
  uint8_t dataary[3] = { 0 };
  uint8_t filler = 0x00;

  while(digitalRead(pin_dout)!=0);
  while(digitalRead(pin_dout2)!=0);//メモ:2つのHX711が両方ともREADYになってから読み込み開始しないと不正確なデータになってしまう。1個がreadyならもうひとつも・・というのはNG。
  delayMicroseconds(10);
  for(int i=0;i<24;i++)
  {
    digitalWrite(pin_slk,1);
    digitalWrite(pin_slk2,1);
    delayMicroseconds(5);
    digitalWrite(pin_slk,0);
    digitalWrite(pin_slk2,0);
    delayMicroseconds(5);
    data = (data<<1)|(digitalRead(pin_dout));
    data2 = (data2<<1)|(digitalRead(pin_dout2));
  }
  digitalWrite(pin_slk,1);
  digitalWrite(pin_slk2,1);
  delayMicroseconds(10);
  digitalWrite(pin_slk,0);
  digitalWrite(pin_slk2,0);
  delayMicroseconds(10);

  A2D_CH1=data;
  A2D_CH2=data2;
  return data;//^0x800000;
}

しかし、ここでHX711固有の問題が発生。
HX711は、AD変換するために約10ms程度ひずみゲージに通電する必要があります。
これを1秒間に80回行うと、ずっーーーーとひずみゲージに通電することとなり、ドリフト(じわじわと読取値がズレる)が発生しました。
このドリフトが20分以上も収まらない状況で、「最初の数十分はパワー値が安定しないパワー計」ができてしまいました。

よい解決策がみつからないので、HX711の利用は一時保留としました。

そこで、ADコンバータを最先端ながらコストは10倍以上のAD7124-4に代えました。
これは1つのコンバータで4chの入力があるので、今回の2ch入力には、1個で足ります。

これで実験しました。
ねじれ計測用のゲージと曲げ計測用ゲージの計測結果に基づくパワー値等をシリアルで無線転送したログの一部です。
55mm地点のペダリング3回転分と110mm地点ペダリング3回転分です。

赤線のAxxx.xxの数値は、曲げ計測用ひずみゲージから算出したパワー値の3回転平均で、約300wです。
このときのケイデンスは、パワー値の2行上のc5080、c5084、c5115をそれぞれ100で割った値で約50RPMです。
それぞれの赤線の2行上にあるA303、A298, A306は捻じれ計測用ひずみゲージから算出したパワー値で、こちらも約300wです(やや校正があまいですが・・・)。

同一負荷の状態でペダリング位置を110mm地点にずらすと、ケイデンスは約50rpmのままですが、パワー値は緑線の値で約330wです。
他方、捻じれ計測用ひずみゲージの値は360w強で、より捻じれに反応してるのが分かります。
本来約300wとなるべきところ、クランクの捻じれにより見かけ上のパワー値がそれぞれで330w、360wと増えています。

固定ローラで、常に55mm地点でのみペダリングをするのであれば、曲げ/ねじれ計測用の一方のひずみゲージだけでパワー値を算出しても問題ないと思います。
実走でダンシングとかするとそうもいかないので、補正が必要です。

補正は、曲げ計測用ゲージとねじれ計測用ゲージの乖離率をベースに補正係数を割り出し、補正してみました。
ペダリングを55mm地点より外側で行うと、55mm地点からの距離に比例して、見かけ上のパワー値が上昇します。

青線の値が補正後の値で、55mm地点ペダリング同様、110mm地点でも約300wとなりました。
この点では、実験成功です。
激安ひずみゲージでも、この補正方式を採用すれば、パワー計として機能しそうです。

4iiiiのパワー計は、これと同じ技術で、精度を確保するため、ひずみゲージを4×2=8枚使用している、と開発者がWEB上で公言しておりました。
最安パワー計を目指すと、8枚も使えないため、1×2=2枚でどのような結果となるか実験する予定です。

数千円の自作パワー計でも、実用的なパワー値は表示されるので、普及すればむやみに上り坂でペースアップする人が減るはず・・・
これをチーム代表に提案するも「いや、登りで上げすぎちゃう人は、パワー計ついててもなおりません」との意見をもらっております。

今回のコードをこちらにアップロードしました。
ttps://sites.google.com/site/myfiles1138000
(20180103.inoというファイル名です。実際にアクセスする場合、末尾の000を削除して1138で終わるようURLを修正する必要があります。ロボット除けのためで、お手数をお掛けします)

なお、私がAD7124の使い方が変わっていないようで、しばしばゼロオフセット値がずれる問題がでておりますが、何が原因かわかっておりません。



2017年10月23日月曜日

最安パワー計製作計画 - 失敗編

最安24bit ADコンバータHX711モジュールが秋月から発売されている、と信州MAKERS管理人様より情報をいただいておりました。

秋月では350円、eBayでは100円未満のもあります。その名称にかかわらず、セブイレブンでは取り扱いがないようです。

これを利用して価格優先パワー計を製作してみました。

HX711は温度計を内蔵せず、温度補償機能を簡単に実装できないため、パワーメーターというより、Power Estimatorと呼ぶほうが適切かもしれません。

◆ 基本動作と使用部品

クランクアームのひずみゲージの値をHX711で読み、Arduinoでパワー値を算出後、SPP-CでBluetooth送信、PCのteratermやAndroidのbluetermアプリで受信・表示する、というものです。





◆ ひずみゲージ 約200円@ebay

前回までは、スパイダー・アームにひずみゲージを貼っておりましたが、走行中にランダムにゼロオフセット値が変化することがある、という問題が出ております。

そこで、新しいひずみゲージの貼り方を試してみました。

ネットで海外の自作パワーメータ製作者の方が投稿していた方法です。

写真は右側クランクアームで、ペダリングすると、アームのひずみゲージ面が右方向に延び、左のひずみゲージが伸び、右のひずみゲージが縮みます。

クランクアームの裏面の対象位置にも同様にひずみゲージを貼り、こちらは、ひずみゲージ面の縮みにより生じるひずみの変化を電圧に変換します。


◆ADコンバータHX711 約100~350円

 HX711は仕様上は、10SPSか80SPS(1秒間に10サンプル計測か80サンプル計測)でADコンバートが可能です。

しかし、秋月のモジュールでは、10SPSに固定されています。

10SPSでは、パワー計として使えないので、80SPSで動作するよう改造します。

データシートをみると、15番ピンをGNDに落とすと10SPSに、VCCに上げると80SPSになるようです。

早速、15番ピンとGNDをつなぐパターンをカッターで切断します。


結果・・・失敗。

見た目は切断されましたが、テスターでは、15番ピンはGNDとつながってました。

ならばと、15番ピンをプリント基板から浮かせて、GNDから分離する方法を試みます。

ゼッケンピンの針先部分で、15番ピンを上方向に持ち上げる圧力をかけながら、半田ごてを当てて加熱。
簡単にピンがプリント基板から浮き、無事に基板上のGNDから分離されました。

浮いた15番ピンをお隣の16番ピンVCCに半田付けします。



これで80SPSで動作するようになりました。


◆Arduino 約200円@ebay

 消費電力の低いArduino ProMiniの8Mhz品を使ってます。

これをさらに消費電力を落とすため、prescalerで4Mhzに落として駆動します。

 HX711とArduinoは、電源線(VCC, GND)に加えて、HX711のData線、Clock線の2本をそれぞれPIND6, PIND7につなぐだけで動作しました。

 今回のArduinoのソフトウェアはいつもの場所に置きました(余分はコードもいっぱいはいってますが)。

 ひずみゲージのゼロオフセット値やスロープ値をArduinoのEEPROMに保存し読出す関数は、こちらのサイトのものを使わせていただきました。ありがとうございます。
ttp://projectsbiotope.blogspot.com/2010/11/2-eeprom.html


◆昇圧DCDCコンバータ+REEDスイッチ+磁石+SPP-C 約700円

 今回は単四電池で駆動したため、1.2v->3.3vのDCコンバータを利用しました。

 角速度を算出するためにREEDスイッチを使用し、フレームには磁石を張り付けています。

 IMUは、信州MAKERS管理人様よりアドバイスはいただいておりますが、まだ実装できておりません。

 Bluetoothモジュールと置き換えでArduinoからのシリアルデータをもとに、ANT+規格でパワー値を送信するモジュールを別途製作中です。これを取り付ければ、ANT対応となります。


部品代の総額は1500円程度とお手頃価格に収まりました。

電子部品を3Dプリントしたオレンジのおにぎりの中収めます。
(イメージ図)


試作中で、ひずみゲージとその配線の整理ができておらず、実際はこんな小汚い状態です




基板類はすべておにぎりに収まり、また、おにぎりはこの位置だとペダリングに干渉することなく、取り扱いが楽です。

早速実験開始・・・結果・・・失敗。

ひずみゲージの配置/種類がNGでした。

同一負荷、同一ケイデンスで回しつつ、フラットペダルの踏位置を内側から外側にずらしていきます。

内側=155wで、外側=180w。

ダメダメです。

ペダルのより外側を踏むとより大きく生じる、クランクのねじれのひずみを大いに拾って、外側を踏むと大きなパワー値が表示されます。

しかし、ここまで派手にクランクのねじれに反応してくれると、むしろねじれの影響がよくデータとして見えるので、補正もしやすいのでは、と気づきました。

パワー測定用のひずみゲージの値を、クランクのねじれ測定ゲージの値で補正する、というのが簡単にできそうな予感です。


Tが真のパワー値とします。

ペダルの踏み位置が1から2へと外側にずれるに従い、パワー計測用のひずみゲージ(Gage1)の値が、クランクアームの捻じれにより大きく計測されてしまう(100wのはずが120w)、というのが今回の失敗です。

この誤った値に対して、ペダルの踏み位置計測用/クランクアームの捻じれ計測用のゲージ(Gage2)の値を利用すれば、補正係数を割りだし、真の値T(100w)に補正できるはず、というかそうすればいい、とPioneer, Shimano, および4iiiiの特許出願に書いてありました。

クランクアーム式ももう少し検討しますが、そもそも、ギアがインナーのときとアウターのときで、同一負荷でも見過ごせない誤差を生じるデータが出たりと問題山積です。

4iiiiのパワー計開発者の方のこちらのフォーラムでの発言もそれを裏付けています。

ttp://forum.slowtwitch.com/forum/Slowtwitch_Forums_C1/Triathlon_Forum_F1/4iiii_Precision_arrived_P5495248/

これを見て、市販のパワー計が表明している精度2%未満とかは、相当な量の前提条件をあれこれ置いたときの値なんだな、とわかりました。