公開日:2022/08/20
title.png

22nd Season


#22-3 万歩計を完成させる

 「#21-8 万歩計を作ろう」で試作した万歩計を完成させようと思います。
 先の記事では何しろ、腰にぶら下げて歩く万歩計に適した表示器が手元に無かったので、モールス符号で現在の歩数を聞き取るとか、少し無理がありました。

 前回「#22-2 OLEDディスプレイを使う」、衝動買いしたOLEDディスプレイ(下図)は、とても小さくて接続端子数4本と言うお手軽な表示器なので、これを使って万歩計に表示器を接続してみたいと思います。

a222_oledisp.jpg

 表示器を接続して、単に歩いた歩数だけを表示しても面白くないので、歩数の他、歩行速さや消費カロリ、歩行時間なども表示する様にして見ます。

消費カロリの計算

 運動(エクササイズ)による消費カロリの簡易換算式は、厚生労働省が発行した「健康づくりのための運動指針2006」の中に記載があって、以下式となります。

  エネルギ消費量[kcal]=1.05×METs×時間[h]×体重[kg]

 しばしば食事🍛の摂取カロリ数が話題となるので、何らかの運動をした時、摂取カロリとのバランス(収支)が取れているかどうか?知りたくなります。そんな方々のため、簡易的にエネルギ消費量(以下、消費カロリと読み替えます)を計算するための式です。

 計算に必要となるのは以下の3値で、まだ、この段階では、全く万歩計との関連が見えず、途方に暮れてしまいます。

 各々読み解いていきましょう。

体重

 まずは一番簡単なところから手を付けます。運動した人の体重[kg]です。
 店売りの万歩計なら、何らかのU/Iを作って使用者が自由に設定できるようにするべきでしょうが、U/Iの設計やデバッグは大変面倒なので、プログラム中の定数で設定する方法にします。

  const int ped_WEIGHT=50;  // ped: weight [kg]

 数値をご自身の体重に書き換えてコンパイルしてください。整数型なので、1kg未満は四捨五入または切り捨てとしてください。

歩行時間の計測

 「時間」は、運動した時間です。万歩計の場合、ウォーキングと言う運動だと考えられるので、「歩行時間」に相当します。
 万歩計プログラム(pedometer.ino)では、加速度センサMPU9250の加速度変化を監視して、歩行を検知しています。歩行を検知したら、その時間(millis()関数の返り値)を一旦記憶ped_msec_preしておいて、次に歩行を検知した時間msecとの差分が、「一歩、歩いた時間」msec_one_stepです。これを毎回、累積歩行時間ped_msec_walkに加算して行きます。

  uint32 msec_one_step;

  msec_one_step=msec - ped_msec_pre;
  ped_msec_walk += (msec_one_step>ped_msec_WK_MAX)?
    ped_msec_WK_MAX: msec_one_step;


 途中で暫く止まっている時間があると、その間「歩行」を検知できないため、前回検知時間ped_msec_preとの差分が非常に大きな数値となる場合があります。そこで、「一歩、歩くのにかかる最大時間ped_msec_WK_MAX」を設定して、止まっていた時間は歩行時間に含まない処理となっています。
 デフォルトでは、ped_msec_WK_MAX=2[s]です。一歩、歩くのに2秒以上かける方、普通は居ませんよね?

METsの推定

 普通に考えて、こんな簡単な式で消費カロリなんて算出できるはずは無いんですよ。でも、簡易的に換算できる理由は、このMETsという値で調整しているから、です。消費カロリ計算の肝と言って過言ではありません。
 色々な運動をした時のMETs値は、国立健康・栄養研究所発行の「身体活動のメッツ表」に一覧表があります。

 万歩計で「歩いた」という運動に対する消費カロリを計算しようとしているので、「身体活動のメッツ表」から、「ウォーキング」となっている項目を抜き出してみました。すると、ウォーキングのパラメータが歩行速さ[km/h]であることが解りました。
 グラフを描いて解析してみたところ、指数近似が一番それらしく近似できたのですが、何しろ肝となるMETs値なので、近似式ではなく、「歩行速さ、対、METs値」のテーブルを作り、それを参照してMETs値を推定することとしました。

  const int ped_mets[ ]=  // ped: walking speed vs mets table
  {
    // m/h, mets*10, ...
    1, 20,
    3200, 28,
    4000, 30,
    4500, 35,
    5100, 35,
    5600, 43,
    6400, 50,
    7200, 70,
    8000, 83,
    0, 0
  };


 参照表の第一項目は歩行速さ[m/h]、第二項目はMETs値を10倍したものです。いずれも、整数として扱えるように、[km/h] → [m/h]への単位変換(×1,000倍)と、METs値×10倍で調整してあります。


 万歩計で歩行速さを計測、そこからMETs値を参照して求める、と言う手順です。歩行速さが参照表に存在しない数値となった場合には、前後の一番近いデータ2個から補間してMETs値を求めています。

  int spd0;  // 前後2点の歩行速さ
  int spd1;
  int met0;  // 前後2点のMETs値
  int met1;

  // interpolate
  spd0=ped_mets[idx - 2];
  spd1=ped_mets[idx];
  met0=ped_mets[idx - 1];
  met1=ped_mets[idx + 1];
  mets=met0 + (met1 - met0)*(ped_spd_walk - spd0)/(spd1 - spd0);



 なお、METs値は、同じ「ウォーキング」でも、平坦な道と坂道では異なるし、歩行速さやリュック等荷物の重さでも変わってきます。今回使う参照表は、「身体活動のメッツ表」から、荷物を持たず平坦な道をウォーキングした時の値だけを抜き出して参照表を作りました。
 これと条件が異なる場合、換算した消費カロリには、その分の誤差が生じます。簡易的に消費カロリを算出するための値なので、この程度の前提条件を理解した上で使えば問題は生じないと考えられます。

歩行速さの計測

 METs値を知るためには、歩行速さがわかれば良いことが前節で判明しました。既に、歩行時間は計測できています。万歩計だけに歩数もカウントしているので、平均歩幅を知ることができれば、歩数との積によって歩行距離も知ることができ、「歩行速さ=歩行距離÷歩行時間」で計算できます。

 平均の歩幅は、例えば10歩ほど歩いてみて進んだ距離を測定し、10で除すと求めることができます。「そんなの面倒だな〜」と言う方も、ご安心ください。統計的に、平均歩幅は身長の×45%程と知られています。これも、プログラム中の定数に埋め込んでおきます。

  const int ped_TALL=160;  // ped: tall [cm]
  const int ped_STEP=ped_TALL*45/100;  // ped: step width [cm]


 ちゃんと10歩、歩いて計測した方は、その数値をped_STEP[cm]に直接指定してください。横着なあなたは、ped_TALL[cm]に身長を設定してください。


 以上を持って、消費カロリの簡易換算式中に有った未知数がすべて出そろったはずです。

 身長・体重などの個人データを、プログラムの定数として埋め込むことにしましたので、このプログラムをコンパイルして組み込んだ万歩計は、「私専用万歩計」となります。ちょっと特別感があって、赤くペイントしたくなりませんか?!

整数(固定小数点)演算

 以前、固定小数点演算のやり方をレクチャしたことがありました。
 今回も、浮動小数点演算(遅い、重い)は使わずに消費カロリの計算をしていますので、固定小数点演算でオーバフロウやアンダフロウさせないための考察内容をお見せしておきます。

 万歩計プログラムでは、一定時間ped_msec_ITVL(=10ms)毎に加速度を測定して、歩行を検出しています。歩行を検出した時、歩数が更新されることに伴って、歩行速さや消費カロリも再計算します。毎回ped_msec_ITVL期間内に処理を完遂しないと、次のサンプリングまでの時間が空いてしまって、正しく歩行を検出できなくなってしまう可能性があります。
 このため、遅くて重い浮動小数点演算は避けて、処理の高速化を図っています。

 今回はArduino DUEなので、32ビット符号付整数を使って固定小数点演算しています。

歩行速さの計算

 まず、歩行速さped_spd_walkの演算について考察します。

 最終的な計算式は、以下となります。

  ped_spd_walk[m/h]=ped_STEP[cm] ×ped_cnt_walk ×(3,600[s/h] ÷100[cm/m]) ÷sec_walk[s]

 この順で32ビット符号付整数演算を実行すると、整数範囲をオーバフロウ/アンダフロウすることなく、演算可能です。

消費カロリの計算

 もう一点、消費カロリped_cal_walk計算についても考察して補足します。整数演算するため、消費カロリは単位[kcal]ではなく、[cal]で計算します。

 最終的な計算式は、以下となります。

  ped_cal_walk[cal]=(105 ×mets ×ped_WEIGHT[kg] ÷100 ÷10) ×(ped_msec_walk[ms] ÷3,600)

 この順で32ビット符号付整数演算を実行すると、整数範囲をオーバフロウ/アンダフロウすることなく、演算可能です。

改定版プログラム

 以下にOLEDディスプレイ対応版の万歩計プログラムをリンクしておきます。

  改定版プログラム:pedometer.ino


 デバッグ用にUSE_SERIALマクロを有効にしてコンパイルすると、シリアルモニタから以下のコマンドを受け付けています(今回追加分)。

  追加のシリアルモニタコマンド:

 改修前のプログラムから対応していた、元のコマンドも有効です。元のコマンドも含めて、全てデバッグ用のコマンドなので、シリアルモニタ無しでも万歩計として自立します。最終的には、USE_SERIALマクロを無効にした状態でコンパイルしてください。

エクササイズの実験

 万歩計にOLEDディスプレイを接続して完成させるところまでは、前回既に報告済みです。回路図だけ以下に再掲しておきます。

a218_schem.png

 その他詳しくは、こちらをご参照ください。

 以下、前回の再掲となりますが、実験中の様子です。

a222_expr.jpg


 なお、USBをPCに接続してデバッグする場合は、プログラム(pedometer.ino)先頭付近のSerialXマクロに「Serial」を設定しておくと、いつもの通りUSB⇔UART変換経由のシリアルモニタが使えて便利です。……FTDIを別途繋がなくてもデバッグできます。

  #define USE_SERIAL
  #define SerialX Serial  // specify Serial/Serial1 class


 今回は、消費カロリや歩行速さの計算/計測に着目した実験となりますので、モバイルバッテリを使うというより、PCに接続した状態でデバッグした方がやり易いと思います。

  実験サンプル:【 】内はシリアルモニタからの送信データ
  【set,700】
  OK: set 700[step] 466[s]

 コマンドを実行したら、表示を更新するために1回、万歩計を上下に振ってください。← 一歩、歩いたと認識させる。
 OLEDディスプレイに歩数と消費カロリ、歩行速さ、歩行時間が表示されますので、これを確認して下さい。

  歩数=701[歩]
  消費カロリ=19[kcal]
  歩行速さ=3.8[km/h]
  歩行時間=7[minu]

 こちらで解説した計算式に従った計算結果が表示されることを確認しました(↑)。OKみたいです。


 では、万歩計の機能を検証した時の動画をご覧に入れます。腰につけた状態で歩き回ると撮影が困難なので、実際に歩く代わりに手で上下に振っています(1^_^;)。



 あっ、気が付きましたか?歩数の単位が漢字の「歩」になっていたことに。アルファベットの「H」と「O」に分けて「歩」のフォントを設定してあるので、連続して「HO」と表示すると、漢字が表示されるようになっています。→ フォントを万歩計用にカスタマイズしてあるので、ご注意ください。

※「Welcome HOME」って表示しようとすると、「Welcome 歩ME」と表示されてしまいます(1^−^)。

 フォント配列ole_font[ ]の該当箇所(以下)で、コメントしてある元の値に戻すと、単位「歩」の代わりに「HO」が表示されて、普通に「H」と「O」が使えるようになります。

  //0x3ffe, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x3ffe, 0x0000,  // 'H'
  0x0020, 0x0420, 0x4220, 0x413E, 0x40A0, 0x2020, 0x2420, 0x17FF,  // '歩'の左半分
    :
  //0x07f0, 0x180c, 0x2002, 0x2002, 0x2002, 0x180c, 0x07f0, 0x0000,  // 'O'
  0x1024, 0x0824, 0x0424, 0x02A4, 0x0124, 0x0620, 0x0020, 0x0000,  // '歩'の右半分



 他にも、【owr】コマンド【prn】コマンドでOLEDディスプレイ制御のデバッグができますが、ちゃんと歩数や消費カロリが表示されたことでOLEDディスプレイの動作確認も十分ですので、割愛します。


 OLEDディスプレイ(SSD1306)の表示が4行分あって、そこに歩数、消費カロリ、歩行速さ、の3行まではすぐに決まったのですが、4行目に何を表示しようか?と悩んで、歩行時間を選択しました。ことによると、歩行距離の方が知りたい情報でしたか??まあ、「私専用万歩計」なので、お好きにカスタマイズしてお使いください。


btn_arduino.png

btn_prev.png btn_next.png

home