つっちー1964のブログ

つっちー1964のブログ

ブログの説明を入力します。

Amebaでブログを始めよう!

M5 Stick C Plus と一緒にENV II HATを購入したので、以前購入しておいたGROVE接続のGPSモジュールと一緒につなげてAmbient Ambientにデータをアップロードするようにプログラミングしてみた。参考にしたのはこの辺りのページ。

 

Arduino ESP8266で温度・湿度を測定し、Ambientに送ってグラフ化する – Ambient (ambidata.io)

 

 

M5StickCPlusとGPS UNITで位置情報を取得 - modalsoul’s blog (hatenablog.com)

M5 Stick C用のENV II HATのサンプルプログラムをベースにしてヘッダをM5 Stick C Plus用に変更、その状態でまずは動作確認、そこからAmbientへ書き込むように修正。

WiFiのSSID、Ambientの書き込みチャネルIDは適宜修正が必要。

そこからGrove接続のGPSモジュールを使用できるように追加。

Groveは32、33を指定。なお、気圧はオリジナルだとパスカル表示なので100で割ってヘクトパスカルとした。
 

/*
    note: need add library Adafruit_BMP280 from library manage
    Github: https://github.com/adafruit/Adafruit_BMP280_Library
*/

#include <M5StickCPlus.h>
#include "SHT3X.h"
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include "Adafruit_BMP280.h"
#include "bmm150.h"
#include "bmm150_defs.h"
#include "Ambient.h"
#include <WiFi.h>
#include <TinyGPS++.h>

SHT3X sht3x;
BMM150 bmm = BMM150();
bmm150_mag_data value_offset;
Adafruit_BMP280 bme;
HardwareSerial GPSRaw(2);
TinyGPSPlus gps;
Ambient ambient;
WiFiClient client;

unsigned int channelId = 12345;  //channel ID
const char* writeKey = "**************"; // Write Key
const char* ssid = "SSID";
const char* password = "PASSWORD";
float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;
uint8_t setup_flag = 1;

void calibrate(uint32_t timeout)
{
  int16_t value_x_min = 0;
  int16_t value_x_max = 0;
  int16_t value_y_min = 0;
  int16_t value_y_max = 0;
  int16_t value_z_min = 0;
  int16_t value_z_max = 0;
  uint32_t timeStart = 0;

  bmm.read_mag_data();
  value_x_min = bmm.raw_mag_data.raw_datax;
  value_x_max = bmm.raw_mag_data.raw_datax;
  value_y_min = bmm.raw_mag_data.raw_datay;
  value_y_max = bmm.raw_mag_data.raw_datay;
  value_z_min = bmm.raw_mag_data.raw_dataz;
  value_z_max = bmm.raw_mag_data.raw_dataz;
  delay(100);

  timeStart = millis();

  while ((millis() - timeStart) < timeout)
  {
    bmm.read_mag_data();

    /* Update x-Axis max/min value */
    if (value_x_min > bmm.raw_mag_data.raw_datax)
    {
      value_x_min = bmm.raw_mag_data.raw_datax;
      // Serial.print("Update value_x_min: ");
      // Serial.println(value_x_min);

    }
    else if (value_x_max < bmm.raw_mag_data.raw_datax)
    {
      value_x_max = bmm.raw_mag_data.raw_datax;
      // Serial.print("update value_x_max: ");
      // Serial.println(value_x_max);
    }

    /* Update y-Axis max/min value */
    if (value_y_min > bmm.raw_mag_data.raw_datay)
    {
      value_y_min = bmm.raw_mag_data.raw_datay;
      // Serial.print("Update value_y_min: ");
      // Serial.println(value_y_min);

    }
    else if (value_y_max < bmm.raw_mag_data.raw_datay)
    {
      value_y_max = bmm.raw_mag_data.raw_datay;
      // Serial.print("update value_y_max: ");
      // Serial.println(value_y_max);
    }

    /* Update z-Axis max/min value */
    if (value_z_min > bmm.raw_mag_data.raw_dataz)
    {
      value_z_min = bmm.raw_mag_data.raw_dataz;
      // Serial.print("Update value_z_min: ");
      // Serial.println(value_z_min);

    }
    else if (value_z_max < bmm.raw_mag_data.raw_dataz)
    {
      value_z_max = bmm.raw_mag_data.raw_dataz;
      // Serial.print("update value_z_max: ");
      // Serial.println(value_z_max);
    }

    Serial.print(".");
    delay(1);

  }

  value_offset.x = value_x_min + (value_x_max - value_x_min) / 2;
  value_offset.y = value_y_min + (value_y_max - value_y_min) / 2;
  value_offset.z = value_z_min + (value_z_max - value_z_min) / 2;
}

void showLocation() {
  if (gps.location.isValid()) {
    M5.Lcd.setCursor(10, 80, 2);
    M5.Lcd.printf("lat:%.4f\n", gps.location.lat() );
    M5.Lcd.setCursor(10, 100, 2);
    M5.Lcd.printf("lng:%.4f\n", gps.location.lng() );
  } else {
    M5.Lcd.setCursor(10, 80, 2);
    M5.Lcd.println("wait gps");
  }
}

void setup() {
  // put your setup code here, to run once:
  M5.begin();
  Wire.begin(0, 26);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(10, 0, 2);
  M5.Lcd.print("ENV TEST ");
  pinMode(M5_BUTTON_HOME, INPUT);
  // GPS Initialize
  GPSRaw.begin(9600, SERIAL_8N1, 33, 32);
  // BMM150 Initialize
  if (bmm.initialize() == BMM150_E_ID_NOT_CONFORM) {
    Serial.println("Chip ID can not read!");
    while (1);
  } else {
    Serial.println("Initialize done!");
  }
  // BMP280 Initialize
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
    while (1);
  }
  calibrate(10);
  Serial.print("\n\rCalibrate done..");
  // WiFi Initialize
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  M5.Lcd.println(WiFi.localIP());
  // Ambient Initialize
  ambient.begin(channelId, writeKey, &client);
  // end of setup
}

void loop() {
  // put your main code here, to run repeatedly:
  if (sht3x.get() == 0) {
    tmp = sht3x.cTemp;
    hum = sht3x.humidity;
  }
  while (GPSRaw.available() > 0) {
    if (gps.encode(GPSRaw.read())) {
      break;
    }
  }
  showLocation();

  M5.Lcd.setCursor(10, 20, 2);
  M5.Lcd.printf("Temp: %2.1f Humi: %2.0f", tmp, hum);

  bmm150_mag_data value;
  bmm.read_mag_data();

  value.x = bmm.raw_mag_data.raw_datax - value_offset.x;
  value.y = bmm.raw_mag_data.raw_datay - value_offset.y;
  value.z = bmm.raw_mag_data.raw_dataz - value_offset.z;

  float xyHeading = atan2(value.x, value.y);
  float zxHeading = atan2(value.z, value.x);
  float heading = xyHeading;

  if (heading < 0)
    heading += 2 * PI;
  if (heading > 2 * PI)
    heading -= 2 * PI;
  float headingDegrees = heading * 180 / M_PI;
  float xyHeadingDegrees = xyHeading * 180 / M_PI;
  float zxHeadingDegrees = zxHeading * 180 / M_PI;

  Serial.print("Heading: ");
  Serial.println(headingDegrees);
  Serial.print("xyHeadingDegrees: ");
  Serial.println(xyHeadingDegrees);
  Serial.print("zxHeadingDegrees: ");
  Serial.println(zxHeadingDegrees);
  M5.Lcd.setCursor(10, 40, 2);
  M5.Lcd.printf("headingDegrees: %2.1f", headingDegrees);

  float pressure = bme.readPressure() / 100;
  M5.Lcd.setCursor(10, 60, 2);
  M5.Lcd.printf("pressure: %2.3f", pressure);

  ambient.set(1, tmp);
  ambient.set(2, hum);
  ambient.set(3, pressure);
  ambient.set(4, gps.location.lat());
  ambient.set(5, gps.location.lng());
  ambient.set(6, headingDegrees);
  ambient.send();

  //  delay(100);

  delay(120000);

  if (!setup_flag) {
    setup_flag = 1;

    if (bmm.initialize() == BMM150_E_ID_NOT_CONFORM) {
      Serial.println("Chip ID can not read!");
      while (1);
    } else {
      Serial.println("Initialize done!");
    }
    if (!bme.begin(0x76)) {
      Serial.println("Could not find a valid BMP280 sensor, check wiring!");
      while (1);
    }
    calibrate(10);
    Serial.print("\n\rCalibrate done..");
  }

  if (digitalRead(M5_BUTTON_HOME) == LOW) {
    setup_flag = 0;
    while (digitalRead(M5_BUTTON_HOME) == LOW);
  }
}

4月26日〜28日国内最大級の規模で行われるトレランレースのUTMF2019に今年もエイドスタッフとして参加してきた。

今年はSTYが無くなった事でスタート時間が繰り上がったのだが、流石にGW10連休前の月末締め日と重なったので、26日は仕事が終わってから車で行く事にした。
23時にバイト帰りの娘を迎えに行った後に出発、先日開通した新東名の伊勢原JCT、足柄SAのスマートICを通るルートを選んで藤沢バイパスを進むと渋滞情報が出ていた。GW前夜から移動する車で東名高速道路は渋滞、バイパスも混んでいたが、新東名は空いていた。


足柄SAのスマートICを出てからはナビに従って一般道を進んでいったが、途中の三国峠辺りから霧が発生して前が殆ど見えなかった。ゆっくり進んで山中湖きららに到着したのはトップ選手が通過した後の午前2時だった。当初の予定では朝6時から活動開始だったけど、上位の選手を見たかったのでそのまま活動開始したが、師匠の壮太さんは既に山伏峠に向かった後だった。

暗いうちに到着した選手は本当に少なかったのだが、計測担当から「チェックポイントで計測が上手く出来ていない」という話が出てきた。どうやら前回の大会で両足に付けた計測チップが両方とも無くなった選手がいたらしく、今回はナンバーカード裏に大きなアンテナを設置した使い捨てのタイプを初めて採用したとの事だったが、それが上手くいっていないとの事で、急遽エイド出口でバーコードの読み取り作業をする事になり、エイドスタッフは選手を止めて説明する事になった。更に後ろのナンバーカードにあるバーコードはミシン目で切り離せるのだか、これはリタイア時に切り取る事になっているため、取れてしまうとリタイア扱いになってしまうとの事で白の養生テープで補強する作業も追加された。ただ雨でナンバーカードも濡れていたため、途中からは余り効果はなかったかもしれない。この作業は昼間のスタッフが到着する昼過ぎまで2時間毎に30分づつ続けたので途中の仮眠はせいぜい1時間程だった。
女子のトップは中国の選手、やっぱりレベルが上がっていると思った。星野由香理がエイドを出る時の表情は明らかに昨年より悪かった。泥濘んでいるから疲労も昨年以上なのだろう。
ポツポツと知り合いも到着してきたが、SOTA練仲間のAさんが救護スタッフに抱えられてきた。体調崩してリタイアするとの事だった。ご近所のT
さんはエイドに到着したが、体調不良で仮眠室に直行したらしく会えずじまいだった。雨で身体を冷やしてしまった選手が増えてきて仮眠室はいっぱいになってきた。
エイドのテントも雨が溜まって漏れてきたのでペットボトルで雨どいを作って対応した。


14時頃から少し霙混じりになっきて、エイドに到着する選手達から雪が降っていると言う情報が入り始めた。念の為山伏峠に居る壮太さんと連絡して山の状況を聞いてみると雪が積もっており、かなりテクニカルになっているので自身がない選手は先に進まない方が良いとの事であった。エイドに到着したが冷えた身体が回復するのを待つ選手達で混み始め、山中湖も雪が降る様になってきた。コース上で誘導している知り合いから中止になりそうと言う情報が出てきた。エイドに到着した選手の中には杓子山がヤバいらしい!、大平山もヤバかった!という話が飛び交う様になり、エイド責任者の宇佐美さんからも「中止になるかもしれない。そうなったらここは夜戦病院状態になる」との話があった。しばらくして15時半頃大会本部から「短縮となったので待機するように」とのアナウンスがあり、SMSも届いた。短縮ってここから迂回して河口湖に向かうのか?と思ったら現時点までで距離を短縮して、勝山エイド以降のエイド毎に「そこまで完走」とするらしかった。残念がる選手もいたが、多くは安堵の表情であった。

選手達はバスで河口湖に向かう事になり、整理券の配布が始まったが、最終的には200名程がバスを利用、それ以外はサポートや応援に来ていた知り合いの車で移動してもらい、スイーパーの到着をもってエイドを終了した。
皮肉なもので中止決定後には雨も上がり、レース中見えなかった富士山も姿を見せてくれた。

クリーンナッパー担当の私はエイド撤収後そのまま2階にある楽屋で仮眠、朝6時に忍野エイドを出発してコース上のマーキングを回収した。昨年同様に2人1組で忍野出発組ときらら出発組と分かれての作業とした。2年続けてなので少し学習して肩がけのマイバッグ持参である。マーキングはテープだけではなく、パウチしてあるものもあるので、ゴミ袋だけだと破けてしまうためである。2人1組だったから良かったが、意外と相棒が見落としていた。大平山に登る途中から雪が積もっていた。流石にコース上の雪はほぼ溶けていた。

大平山の山頂はまだまだ雪が残っていた。
晴れて富士山が綺麗だった。選手達にも見せたかった。
3時間半程できららに到着、大会本部がまだ残っていたので、ゴミ袋を預けて任務終了。帰りに石割の湯で汗を流し、足柄SAで昼食を済ませ帰宅。



甲州アルプス オートルート リリールートチャレンジ② 大会本番


リリールートは朝8:00スタートなので当日受付が可能ということもあり、夜中に移動して現地で仮眠することにしました。3日は昼間仮眠23:30過ぎに出発して1:30過ぎは到着出来たのでトランクに足を突っ込んで寝袋で寝ます。朝4時過ぎには周りが少しうるさくなってきたので目覚めてしまいましたが、会場側まで車を移動してオートルートのスタートを待ちました。さすがに真っ暗だったので一部の人しか挨拶出来ませんでしたが、スタートを見送り、再度仮眠を取って6:30に受付して準備開始、朝食におにぎりを食べ、トイレを済ませ、装備チェックを受けてSOTA練の仲間たちとスタートを待ちました。






スタート前にお会い出来たのは安走会のつねつね(実家が車で10分程らしい)、小野さん、SOTA練初期メンバーの兒玉さん、佐々木さん、鎌倉トレイル協議会の大森さん、永山さん等など。

8:00レーススタート、公園の中を取って裏山を一旦登ってからロードで文殊院のトレイルヘッドまで走ります。途中トイレに寄ったので安定の最後尾グループ、45分程掛かりました(^^;;

SOTA練のメンバーと

スタート直後

文殊院からトレイル、昔より踏み跡がしっかりしています。恩若ノ峰まで30分程、ここまではまあ予定通り。細かいアップダウンが続き、予想通りハードなコース、と言ってもまだ序盤なので、抑えて走ります。途中応援の音が聞こえてくるのでよく見ると東京ハセツネクラブの野口さんでした。どうやらここが復路の分岐点のようです。一旦下っていよいよ源次郎岳、ジェルで補給してから登り、源次郎岳に11時過ぎに到着、上日川の関門が13時との事なので走れるところはしっかり走ります。途中で島田さんを発見、体調不良でリタイアするとの事でした。何とか15分前に関門の上日川エイドに到着。ここはチーカマメンバーがやっているのでエイド前後には知り合いが沢山いました。鎌田さん、なおちゃん、ふみふみ、ノリさん、ゆきさん、まりさん、えりりん、ちゃーさん応援ありがとうございました。

源次郎岳の登り

上日川エイド出発直後

トイレを済ませて出発、一路稜線を目指します。次の関門は10km先、関門時間は16時、必死に登り天狗棚山に到着、岩場&落ち葉が沢山あり、時々ポールが刺さって大変でした。ここから暫くはポール使用不可です。天狗棚山からは展望の良かったですが、小金沢山に向かう途中は霧の中、足元も木の根が多くペースも上がりません。

小金沢山手前、絶景は見えなかった


それでも15時過ぎに牛奥ノ雁ヶ腹摺山に到着、残り3kmの下りを1時間で走れば関門に間に合います。ここはペースよく走れ、30分前に到着出来ました。エイドにはチームSOTAの野村さんがいました。

トイレを済ませ、補給して出発、途中でチームSOTAの渡辺さん親子に会い、前を走る野村さんを追いかけます。野村さんは登りを走っていましたが、私はポールを使ってパワーウォークでしたが、良いペースで進めたので余り差は広がらず進めました。ロードを登り切り、林道を進むと往路で島田さんが居た場所に出ました。ここから源次郎岳の先まで来た道を戻ります。源次郎岳に到着したのは16時半過ぎ、残り1時間半くらいかかるとのことなので関門の18時まで余り時間がありません。分岐点まで慎重に降りていよいよ初めて通るマロニエエイドまでのルートです。源次郎岳の下り途中からヘッドライトを点灯して進みました。初めて通るので意外とアップダウンがあるなと思いながら走っていると雨が降り始めたのでレインを着用しました。時計で標高を確認するもまだまだ先は長そうですが、気持ち良く走れ、関門25分前にマロニエエイドに到着。

ここにはハセツネ30kの試走で知り合ってからお世話になっている松永さん、チームSOTAの北風さん達が居ました。トイレを済ませて補給していると野村さん、オートルート参戦中のすーさん、さとあやちゃんが到着。残り2時間10分で9km進めはいよいよフィニッシュですが、ここからラスボスが登場!300mの直登が待っています。ロードを下り、トンネル前に到着、登り始めると雨が降り始めたのでさっきエイドで脱いだレインをまた着用してひたすら登ります。高低図を作った時に適当に作ってしまったのでまさか偽ピークがこんなにたくさんあるとは思っていなかったので、いつまでたってもピークにつかないし、デジャヴのように同じような倒木があったりしましたが標高を頼りに進み、ようやくスタッフの居る分岐点に到着。

本当は直登じゃなかった!

ここから最後の下り、トレイルを走りきり、ロードに出ると最後のエイドです。ここにはチームSOTAの大川さんが居ました。

最後のエイドにて

この時点で残り5km、50分。あれ?4kmじゃないの?じゃあ歩いたら間に合わない!という事で、意を決して走ります。ポールを使ってリズムの取り、前を走る野村さんとすーさんを追いかけ、いよいよフィニッシュ地点が見えて来ました。最後はポールを片手に持ち、ヘッドライトを消してフィニッシュ!11時間43分15秒でした。

フィニッシュ後に壮太さんと握手して完走証をもらい、そのまま車に乗って勝沼の天空の湯に移動、汗を流してから帰路につきました。高速が少し渋滞している様だったので談合坂サービスエリアで夕食を食べているとその間に渋滞もなくなり、23時半には帰宅できました。

今回良かったところ

・最後の山もポールを使ってリズム良く登れた。下りでも上手く使えたので、前腿への負担も軽減出来た。

・先日の六甲縦走キャノンボールではインソールが合わずに足が痛くなってしまったが、インソールを柔らかい物に変えたおかげか最後まで走れた。

悪かったところ

・ヘッドライトをREACTIK+だけにしたが、少し暗かった。そのせいか何度かつまづきそうになった。

・マイカップをザックの後ろに付けたのでエイドでいちいちザックを降ろさなければならなかった。

・走れないなりにも、もう少し関門に余裕を持って走りたかった。

・スマホの電池が持たなかった。最初のロード途中でメッセージが入った事で機内モードにしていない事に気づいた時に既に75%でした。電池がかなり劣化しているので予備のスマホは持っていましたが、写真が殆ど撮れなかった( ;  ; )