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体制にすることで解決は可能かと思います。








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