M5stickCで始める筋肉ムキムキ計画💪

本記事は<a href="https://qiita.com/advent-calendar/2020/m5stack">M5Stack Advent Calendar 2020</a>の12月3日分です。

はじめまして！　記事をご覧くださりありがとうございます。
**半分NEETのようなフリーランスエンジニアのたつのぶ**と申します。
今回は、**M5stickCで始める筋肉ムキムキ計画💪**と題してM5StickC内蔵の加速度センサを
使って腹筋回数を可視化する記事です。ぜひ最後まで読んでくださると幸いです！！

#はじめに
ポテチはおいしいな～(mgmg
箸で食べるという技も極めてるから手も汚れないぜ✨
今日も今日とて間食にスナック菓子を食べる生活をしていた...
<img width="400" alt="potechi" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/56738eb7-8f50-0f68-a8a8-b74c68765bd5.jpeg">
最近洋服がきつい。だけど、ポテチうまうま。
<img width="400" alt="potechi2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/6d2a373a-2423-d79f-0679-70f66f1fff42.png">
訳あって5年ぶりくらいに親戚のおばさんと会った。最初の一言。
**「たつのぶくん、太った？」**
![stand1_front08_obasan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/3eaf331e-cd8d-0fd2-22f8-6d7ec37fce30.png)
**ぼく「絶対痩せてやる！！！！」**
![gaman_okashi_man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/2cd3e46b-dd21-7a60-bc78-b2f81be90dc9.png)

そんなわけでお腹周りをへこませることを目標とした
**M5stickCで始める筋肉ムキムキ計画💪**の始まり始まり～～～👏👏

#準備するもの
- レンタルサーバー
- PC： WindowsPC
- M5StickC本体/付属USBType-Cケーブル/付属リストバンド
<img width="400" alt="m5stick" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/cab2008b-9523-090a-080b-82e52a83a671.jpeg">
- 腹筋ワンダーコア2

 ![1670506656.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/09e0613a-db4a-aed4-4aff-71ed195aa512.jpeg)


#システム構成図

![Untitled Diagram.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/e26e4ae8-e85c-3ba7-24c2-51561ec1ce6c.jpeg)



#M5stickCに書き込む準備

### ArduinoIDEのインストール
公式HPよりArduino IDEをインストールする。
https://www.arduino.cc/en/software
### M5StickCライブラリのインストール
① 「ツール」＞「ライブラリを管理…」を選択。
② 「m5stick」で検索すると、「M5StickC」が現れるので「インストール」をクリッ
ク。

#腹筋回数をカウントしてサーバーにPOSTするファームウェア
⇒SSIDとパスワード、サーバ送信先は自分の環境に合わせてください。
⇒500ミリ秒ごとに加速度センサの値をとって、腹筋行動の閾値になるとサーバにPOSTする
仕組みになってます。

```C++:FukkinPost.ino
#include <M5StickC.h>
#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "yourssid";
const char* password =  "yourpassword";
const char* svrinfo = "https://hogehoge.jp/logfit.php";

float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;
float oldaccY = 0.0F;
float oldaccZ = 0.0F;
bool  Continuous = false;

void setup()
{
  Serial.begin(115200);
  M5.begin();
  M5.IMU.Init();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(40, 0);
  M5.Lcd.println("IMU");
  M5.Lcd.setCursor(0, 10);
  M5.Lcd.println("  X       Y       Z");
  delay(4000);   //Delay needed before calling the WiFi.begin
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) { //Check for the connection
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connected to the WiFi network");
}
void SvrPost(){
  if(WiFi.status()== WL_CONNECTED){   //Check WiFi connection status
    HTTPClient http;               
    http.begin(svrinfo);  //Specify destination for HTTP request
    http.addHeader("Content-Type", "text/plain");             //Specify content-type header
    int httpResponseCode = http.POST("fukin");   //Send the actual POST request
    if(httpResponseCode>0){          
      String response = http.getString();                       //Get the response to the request
      Serial.println(httpResponseCode);   //Print return code
      Serial.println(response);           //Print request answer
    }else{
      Serial.print("Error on sending POST: ");
      Serial.println(httpResponseCode);
    }
      http.end();  //Free resources
  }else{
    Serial.println("Error in WiFi connection");   
  }  
}
void loop()
{
  oldaccY = accY;
  oldaccZ = accZ;
  M5.IMU.getAccelData(&accX, &accY, &accZ);
  M5.Lcd.setCursor(0, 30);
  M5.Lcd.printf(" %5.2f   %5.2f   %5.2f   ", accX, accY, accZ);
  M5.Lcd.setCursor(140, 30);
  M5.Lcd.print("G");
  if((oldaccY - accY) >= 0.3  && (oldaccZ-accZ) >= -0.3 ){
     if(oldaccY == 0.0 && oldaccZ == 0.0 ){
       Serial.println(0);
       Continuous = false;
     }else{
        if(Continuous == true){
            Serial.println(0);
            Continuous  = false;
        }else{
            Serial.println(1);
            Continuous  = true;
            SvrPost();
        }
     }
  }else{
    Serial.println(0);
    Continuous = false;
  }
  delay(500);
}

```
#M5stickCからPOSTされたデータを受け取るサーバーサイドスクリプト
```php:logfit.php
<?php
  $data = file_get_contents('php://input');
  $time1 = date("Ymd");
  $time2 = date("H:i:s");;
  $json = file_get_contents('data.json');
  $records = (array)json_decode($json, true);
  $i = count($records) + 1;
  $records[] = [
    'id' => $i,
    'time1' => $time1,
    'time2' => $time2,
  ];
  $out_json = json_encode($records);
  file_put_contents('data.json', $out_json);
?>
```
#腹筋状態を確認するフロントページ
⇒CSS・jsは同一ファイルに書いてます 　~~（てへぺろ~~
⇒サーバにあるjsonを一定周期で参照して腹筋回数を可視化しています。

```html:logfitview.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>腹筋ログ</title>
<style>
body {
  width: 100%;
}

h2 {
    text-align: center;
}

table {
  border-collapse: collapse;
  margin: 0 auto;
  padding: 0;
  width: 650px;
  table-layout: fixed;
  color: #000;
}

table th {
  padding: 15px 0;
  border-right: 1px solid #bbb;
  text-align: center;
}

table tr {
  background-color: #fff;
  padding: 30px;
  border-bottom: 1px solid #bbb;
}

table tr:last-child{
   border-bottom: none
}

table td {
  padding: 1em 10px 1em 1em;
  border-right: 1px solid #bbb;
  text-align: center;
}

table th:last-child,
table td:last-child{
  border: none;
}
</style>
<script>
var counter;
// 1桁の数字を0埋めで2桁にする
var toDoubleDigits = function(num) {
  num += "";
  if (num.length === 1) {
    num = "0" + num;
  }
 return num;     
};
function getJSON() {
	var req = new XMLHttpRequest();						// XMLHttpRequest オブジェクトを生成する
	req.onreadystatechange = function() {				// XMLHttpRequest オブジェクトの状態が変化した際に呼び出されるイベントハンドラ
		if(req.readyState == 4 && req.status == 200){	// サーバーからのレスポンスが完了し、かつ、通信が正常に終了した場合

			var data = JSON.parse(req.responseText);	// 取得した JSON ファイルの中身を変数へ格納
			var len = data.length;						// JSON のデータ数を取得
			var result = _.chain(data) 
  				.groupBy(function(o){ return o.time1; })
  				.pick(function(o){ return o.length > 0; })
  				.mapObject(function(o){return _.pluck(o,'id');})
  				.value();
  			var date = new Date();
  			var yyyy = date.getFullYear();
  			var mm = toDoubleDigits(date.getMonth() + 1);
  			var dd = toDoubleDigits(date.getDate());
			var yyyymmdd = yyyy + mm + dd;
			var  resjson = JSON.stringify(result);
			     resjson = JSON.parse( resjson );
			document.querySelector('.titletoday').innerHTML = "本日 [" + String(yyyymmdd) + "] のトレーニング回数";
			if(resjson[yyyymmdd]){
				document.querySelector('.result').innerHTML = resjson[yyyymmdd].length +"回";
				counter = resjson[yyyymmdd].length;
			}else{
				document.querySelector('.result').innerHTML = "0回";
                                counter = 0;
			}

		}
	};
	req.open("GET", "https://hogehoge.jp/data.json", true);				// HTTPメソッドとアクセスするサーバーのURLを指定
	req.setRequestHeader('Pragma', 'no-cache');
	req.setRequestHeader('Cache-Control', 'no-cache');
	req.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
	req.send(null);										// 実際にサーバーへリクエストを送信
}
function proc1()
{
	getJSON();
        const input1 = document.getElementById('p1');
	if (input1.value < 100 ) {
		input1.value = counter;
	}
}
setInterval(proc1, 100);
</script>
</head>
<body onload="proc1();">
<div style="border: 2px ridge #000; padding: 10px;">
                <p style="font-size: 2.0em;">ﾘｱﾙﾀｲﾑ腹筋回数<br>
                </p> 
	        <em style="color: #000000;background-color: #b1f9f6">腹筋ログ</em>
                
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore-min.js"></script>
<h2 class="titletoday"></h2>
<table class="table_box">
  <tr>
    <th>種目</th>
    <th>ステータス</th>
    <th>回数</th>
  </tr>
  <tr>
    <td><h2>腹筋</h2><img src="./images/fukkin_man.png" width="309" height="400" alt="hukkin"></td>
    <td><progress id="p1" min="0" max="100" value="0"></progress></td>
    <td><h2 class="result"></h2></td>
  </tr>
</table>
</body>
</html>
```

# M5stickC付属のリストバンドを腹筋ワンダーコアに巻き付ける
![PXL_20201113_132929806.MP.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/8bce666d-f223-4ffa-34b4-5ed8f4ac88ca.jpeg)

#ブラウザで腹筋回数をリアルタイム表示
⇒腹筋ワンダーコアで普通に腹筋をするだけで回数がカウントされます！
![MBJpD9HII6SjqSwipZIG1605278744-1605279018.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/c50cb654-bfb2-9bfe-156c-5c99c2951f28.gif)

#一日の目標回数(60回)に達したらアラート表示！
![60.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580405/575332e1-a175-b429-0a62-c8b65200e37a.png)

#最後に
この記事をご覧になった方。
今回は、約2千円という安価で購入できる**M5stickC**の新たな使い方を記事にしてみました！
ムキムキボディが手に入るかはさておき、
たのしく腹筋トレーニングができると思います（やったね✌🏼✌🏼
**この年末はM5stickCを活用して一年のおなかにたまった脂肪を落としてみてはいかがでしょうか？？？**
それでは✋