M5StickCとサーボ(Geekservo)を使って、APIから取ってきた値を表示するアナログメーターを作ってみます。
なにを作るの?
M5StickCとサーボモーターを使って、APIから取得したデータを表示する、かっこいい汎用アナログメーターをつくります。
用意するもの

- M5StickC(ESP32開発ボードなどでもOK)
- Geekservo 270度回転サーボ
- プリンタで印刷できるステッカー用紙
- 3Dプリンター(あれば)
今回サーボは、270度の作動角の「Geekservo」を利用しました。180度サーボだとちょっと物足りない感じになると思います。また、360度連続回転サーボは開始位置が固定されず、細かい調整が難しいので避けたほうが良いです。
Geekservoは色ごとにタイプがあり、今回使ったのは灰色のタイプなので買い間違いのないようにご注意ください。
3Dプリンターでメータパネル等を制作

3Dプリンター用.STLデータおよびメーターパネルシールのpng画像はこちら
今回はメーターパネル・ニードル(針)・マウント用部品を3Dプリンターで制作しました。もし3Dプリンターをお持ちでない方は、プラ板などで同様のものを制作してもできると思います。
ちょうどサーボがはまるようになっています。左下のパーツはGoPro規格のマウント用パーツです。
サーボのキャリブレーション(調整)
メーターパネルにサーボと針を取り付けたら、まずはサーボの作動角を、ちょうど0から100の範囲におさまるように調整を行います。

配線は、サーボから出ている赤を5Vに、茶をGNDに、オレンジをIO26に接続します。
利用するライブラリ

今回はこのServoESP32ライブラリを使用します。Arduino IDEのスケッチ – ライブラリをインクルード – ライブラリを管理 から、 上記のライブラリをインストールします。もし既存のServoライブラリと競合する場合は、既存ライブラリを別の場所に移すなどしてください。
ソースコード(キャリブレーション用)
#include <Servo.h>
#include <M5StickC.h>
static const int servoPin = 26;
Servo servo1;
/*
Geekservo(灰色)のパルス間隔範囲は500〜2500。
最大パルスの位置を0にあわせ、最小パルスの数値を調整してメーターの最大値に合わせる。
*/
const int channel = -1;
const int minAngle = 0; // 最小アングル(ステップ)
const int maxAngle = 200; // 最大アングル(ステップ)
const int minPalseWidth = 400; // 最小パルス間隔(メーターの最大位置:この値を調節する)
const int maxPalseWidth = 2600; // 最小パルス間隔(メーターの最小位置)
void setup() {
servo1.attach(servoPin,channel,minAngle,maxAngle,minPalseWidth,maxPalseWidth);
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.setTextSize(4);
M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.println("Ready");
}
void loop() {
for(int posDegrees = 0; posDegrees <= 200; posDegrees++) {
servo1.write(posDegrees);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.println(posDegrees);
delay(100);
}
delay(1000);
for(int posDegrees = 200; posDegrees >= 0; posDegrees--) {
servo1.write(posDegrees);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.println(posDegrees);
delay(100);
}
}
サーボの針の位置は、パルスと呼ばれる信号の間隔で制御されています。Geekservoのパルス入力幅は400us〜2600usです。このうち最大パルスをメーターの0の位置で使い、最小パルスを調整してメーターの100の位置にあわせる作業をします。
プログラムを実行し、まずは最大パルスの位置で針が0を指すように、針の取り付けを調整します。そして、最小パルスの位置で100を指すように、ソースコードの「minPalseWidth」の値を変えます。
ちょうどよく調節できた場合、上記の動画のように最小・最大値がぴったり揃います。
それではAPIから値を取得して表示してみましょう
キャリブレーションが完了したら、実際にAPIから取得した情報を表示してみましょう。例によってビットコインの価格を表示してみることにします。メーターは100までしかないので、1/10,000の値を表示することにします。
#include <M5StickC.h>
#include <WiFi.h>
#include <Servo.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include "ArduinoJson.h"
// Wifi
static const char* ssid = "ここにWiFiのSSIDを記入";
static const char* password = "ここにWiFiのパスワードを記入";
// API(ビットフライヤー)
static const char* api = "https://api.bitflyer.jp/v1/ticker?product_code=BTC_JPY";
// Servo
static const int servoPin = 26;
const int channel = -1;
const int minAngle = 0; // 最小アングル(ステップ)
const int maxAngle = 200; // 最大アングル(ステップ)
const int minPalseWidth = 400; // 最小パルス間隔(メーターの最大位置)
const int maxPalseWidth = 2600; // 最小パルス間隔(メーターの最小位置)
WiFiMulti WiFiMulti;
Servo servo1;
void setup() {
servo1.attach(
servoPin,
channel,
minAngle,
maxAngle,
minPalseWidth,
maxPalseWidth
); // コンストラクタ
M5.begin();
M5.Lcd.setRotation(3); // M5のLCDの向き
M5.Lcd.setCursor(0, 0, 2); // M5のLCDの表示位置
WiFiMulti.addAP(ssid,password);
M5.Lcd.print("Connecting");
while(WiFiMulti.run() != WL_CONNECTED) {
M5.Lcd.print(".");
delay(1000);
}
M5.Lcd.println("");
M5.Lcd.println("Connected to");
M5.Lcd.println(WiFi.localIP());
servo1.write(maxAngle);
delay(500);
}
void loop() {
if ((WiFi.status() == WL_CONNECTED)) {
HTTPClient http;
http.begin(api);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
DynamicJsonDocument doc(1024);
deserializeJson(doc,payload);
JsonObject obj = doc.as<JsonObject>();
String price = obj[String("best_bid")];
M5.Lcd.print("Bitcoin price = ");
M5.Lcd.println(price);
int priceInt = price.toInt();
int degrees = maxAngle - ((priceInt/10000) * 2); //ここで針の位置を指定
M5.Lcd.print("Servo steps = " . degrees . "/" . maxAngle);
servo1.write(degrees);
} else {
M5.Lcd.println("error");
return;
}
http.end();
delay(10000);
}
}
WiFiへの接続に必要なライブラリやソースコード解説はこちらの記事で説明していますので、参考にしてみてください。
int degrees = maxAngle - ((priceInt/10000) * 2);
ここで針の位置を指定しています。2で割っているのは、サーボのステップ数を200ステップに設定しているからです。
それでは動かしてみましょう
はい、この通りビットコインの価格が表示されました!おおよそ98万円ぐらいのようです。だいたいしかわからないのが、アナログメーターの良いところですよね。
追記

楽しかったので、ハウジングも作ってしまいました!ガラス部分は透明なプラ板をカットしてはめこんであります。

ちゃんとM5StickCとサーボがおさまります。

バックパネルもつけました。
まとめ
今回は3Dプリンターも活用しながら、かなり作り込んでみました。ぼくと同じく、アナログメーターが大好きな方は、いろいろな値を表示して楽しんでみてください!
この記事へのコメントはありません。