個人ランナー向け電子ペーサーシステム
はじめに
今回私はSpresenseを用いたランニング用のペースメーカーを作成することにチャレンジしました。
結果としては、基本的なソースコードの作成と技術テストが完了しています。当初は、画像認識を用いてタイムを計測し、ELTRESを使用してSpresense同士を連携させ、区間ごとのタイムを正確に計測することを目標としていました。しかし、カメラのフレームレートの制限により、画像認識を使用してタイムを計測することが困難であることが判明したため、計画を変更しボタンを用いたタイム計測とLEDへの反映を新たな目標としました。
ペースメーカーの概要
自己タイムを計測しLEDライトで自己タイムを視覚化することができます。そのため過去の自己タイムをと競うことができるとともに他者のタイムとも競うことが可能になります。
使用した機材&ソフト
Spresenseメインボード
拡張ボード
フルカラーLEDテープ(5m)×4本
ブレッドボード
押しボタンスイッチ
モバイルバッテリー
プログラミングソフトウェア(Arduino IDE)
設計と開発プロセス
ステップ1: アイデアの発案
日本陸上競技連盟が電子ペーサーの導入のためのクラウドファンディングを実施し導入に300万円が必要であると知り、このシステムをより低コストで簡単に実現できないかと考えました。また、過去の文献を参考に、個人でもグループでも楽しめるように、手軽で効果的なトレーニングシステムの開発を目指し、このプロジェクトが開始しました。
ステップ2: spresenseと使用する機材の選定
spresenseを基礎として実装するための機材を調べ、集めました。
ステップ3: 電子部品の組み立て
SpresenseとブレッドボードにフルカラーLEDテープを接続し、バッテリーで動作させる設計を行いました。
ステップ4: プログラミング
Arduino IDEを使用して、Spresenseボードにボタンでランニングペースを計測し、LEDに表示するためのコードを書きました。このコードは走者の速度を疑似的に再現を行います。
ステップ5: 試験運用
簡易的にタイムを計測しLEDテープに表示し実際に走りました。
※当初はカメラを使用した画像認識を使用する予定でしたがボタンによる計測に変更しました。
以下は、Spresenseでボタンを用いてタイムを計測しLEDを光らせるソースコードです。
ソースコード
#include <Adafruit_NeoPixel_Spresense.h>
#define LED_PIN 8
#define LED_COUNT 600
#define BUTTON_PIN 9
#define DEBOUNCE_TIME 50
Adafruit_NeoPixel_Spresense strip(LED_COUNT, LED_PIN);
unsigned long startTime = 0;
unsigned long previousTime = 0;
int buttonClicks = 0;
int lastButtonState = HIGH;
int currentLed = 0;
void setup() {
Serial.begin(19200);
strip.begin();
strip.show(); // Turn off all pixels
strip.setBrightness(60);
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.println("Setup complete.");
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == LOW && lastButtonState == HIGH && millis() - previousTime > DEBOUNCE_TIME) {
previousTime = millis();
buttonClicks++;
if (buttonClicks % 3 == 1) {
// Start timing
startTime = millis();
Serial.println("Timer started.");
currentLed = 0; // Reset
} else if (buttonClicks % 3 == 2) {
unsigned long elapsedMillis = millis() - startTime;
float elapsedSeconds = elapsedMillis / 1000.0;
Serial.print("Timer stopped. Time: ");
Serial.print(elapsedSeconds, 2);
Serial.println(" seconds");
lightLedsSequentially(elapsedMillis);
} else {
// Turn off the LED strip
strip.clear();
strip.show();
Serial.println("LED strip turned off.");
}
Serial.print("Button clicks: ");
Serial.println(buttonClicks);
}
lastButtonState = buttonState; // Save the last button state
}
//20m用
void lightLedsSequentially(unsigned long time) {
int delayTime;
if (time > 11227) {
// タイムが11227ミリ秒より長い場合、全てのLEDを点灯
delayTime = abs(static_cast<long>(time) - 11227) / 600;
for (int i = 0; i < 600; i++) {
strip.setPixelColor(i, strip.Color(230, 128, 0));
strip.show();
delay(delayTime);
strip.setPixelColor(i, strip.Color(0, 0, 0));
}
} else {
// タイムが11227ミリ秒以下の場合、1つおきのLEDを点灯
delayTime = abs(static_cast<long>(time-37.423)) / 600;
for (int i = 0; i < 600; i += 3) {
strip.setPixelColor(i, strip.Color(250, 0, 0));
strip.show();
delay(delayTime);
strip.setPixelColor(i, strip.Color(0, 0, 0));
}
}
}
LEDの点灯時間と実際のタイムの誤差
今回のプログラムではシリアルモニターにボタンを押して計測したときの実際の測定タイムが表示されます。
しかし、その測定されたタイムとLEDが光りきるまでの時間にはLEDテープの長さによって誤差が生じることがわかりました。その結果をLEDテープの長さを変えてそれぞれ10回タイムを測定し、以下の表とグラフにまとめます。
グラフは縦軸は誤差、横軸は計測回数を表しています。5mの誤差は0.5から0.7ms、10mの誤差は2.6から2.9ms、15mの誤差は6.0から6.5ms、20mの誤差は10.9から11.55msとなっています。
このことからLEDテープの長さが長くなるほど誤差が大きくなることがわかりました。
そこで、今回は20mで実験を行うことを想定して、計測したタイムが平均誤差の11.23秒より長い場合は、平均誤差をLEDの総数(今回は600)で割った値を1つ1つのLEDが光るタイムの間隔から引いた時間で光らせるように変更しました。
また、11.23秒より短い場合はLEDを1つ飛ばしで光らせることにより、計測したタイムの近似値で動作することができました。
まとめ
今回得られた成果としては主に計測タイムのLEDテープライトへの可視化です。計測タイムとLEDライトの到達時間を計りそれぞれの誤差や傾向を得ることができました。また課題としてはLEDの信号の伝達速度の問題や本来の画像認識による動作ができなかったことがあげられました。今後はタイムが短い場合のLEDテープライトへの信号伝達の誤差を少なくしてより実用性を高める方針です。
今回は主に計測タイムのLEDテープライトへの可視化を実装できました。さらなる完成度を高めるため開発を継続し来年度のコンテスト出場を目指していきたいと思います。
参考文献
過去の走行を再現するように光るLEDテープを利用した短距離走練習方法
https://cir.nii.ac.jp/crid/1050294045368290048
日本の陸上を一歩前へ。目標記録達成のために電子ペーサーの導入を!
https://readyfor.jp/projects/distance2023
-
yukimiruthi
さんが
2024/01/31
に
編集
をしました。
(メッセージ: 初版)
-
yukimiruthi
さんが
2024/04/16
に
編集
をしました。
ログインしてコメントを投稿する