Arduino UNO 用コマンドラインインターフェース (CLI) – 高速・省メモリ・すぐ使える
必要な部品
- Arduino UNO × 1 (または互換ボード)
このプロジェクトについて
Arduinoスケッチにテキストベースのコマンドラインインターフェース (CLI) を簡単に追加できるライブラリです。シリアルモニターから add 5, 10 や blink 3 のようにコマンドを入力するだけで、センサー値の確認、変数の変更、モーター制御などが対話的に行えます。C言語標準ライブラリ (string.h, stdlib.h) のみを使用し、String オブジェクトを避けることでメモリ効率を最大化しています。
特徴
- 軽量: コマンドバッファー25文字、グローバル変数最小限
- 高速:
strtok()でトークン分割、atoi()で数値変換 - バックスペース対応: 入力ミスを修正可能
- 拡張容易:
DoMyCommand()にif-elseでコマンド追加 - タブ分離:
CommandLine.hとして独立、#include "CommandLine.h"するだけ
基本的な使い方
- Arduino IDEで新規スケッチを作成
- 右上の ▼ から「新しいタブ」→
CommandLine.hと命名 - 下記のライブラリコードを貼り付け
- メインスケッチに
#include "CommandLine.h"を追加 setup()でSerial.begin(115200)loop()に以下を記述:void loop() { if (getCommandLineFromSerialPort(CommandLine)) { DoMyCommand(CommandLine); } // ここにメイン処理を追加 }- シリアルモニター (115200 bps、改行コード「CR+LF」) でコマンド入力
デフォルト搭載コマンド
| コマンド | 引数 | 動作 |
|---|---|---|
add | 数値, 数値 | 2数の加算結果を表示 |
sub | 数値, 数値 | 2数の減算結果を表示 |
コマンド追加の手順
CommandLine.h内の//Modify hereコメント箇所を編集- コマンド名トークンを追加:
const char *myCmdToken = "mycmd"; - 実行関数を追加:
int myCommand() { int arg1 = readNumber(); int arg2 = readNumber(); // 任意の処理 return result; } DoMyCommand()に分岐追加:if (strcmp(ptrToCommandName, myCmdToken) == 0) { result = myCommand(); print2("> Result = ", result); }
ヘルパー関数リファレンス
| 関数 | 説明 |
|---|---|
readNumber() | 次のトークンを int として読み取り (カンマ/スペース/改行区切り) |
readWord() | 次のトークンを文字列ポインタとして読み取り |
print2(label, value) | Serial.print(label); Serial.println(value); のマクロ |
nullCommand(name) | 未知コマンド時のエラー表示 |
ライブラリ全文 (CommandLine.h)
/*****************************************************************************
* Simple Command Line Interpreter for Arduino
* Usage: add 5, 10 → > The sum is = 15
* sub 10, 5 → > The difference is = 5
*****************************************************************************/
#ifndef COMMAND_LINE_H
#define COMMAND_LINE_H
#include <string.h>
#include <stdlib.h>
#define print2(x,y) (Serial.print(x), Serial.println(y))
#define CR '\r'
#define LF '\n'
#define BS '\b'
#define NULLCHAR '\0'
#define SPACE ' '
#define COMMAND_BUFFER_LENGTH 25
char CommandLine[COMMAND_BUFFER_LENGTH + 1];
const char *delimiters = " , \n";
// ---- コマンド名トークン (ここを追加/変更) ----
const char *addCommandToken = "add";
const char *subtractCommandToken = "sub";
// -------------------------------------------
// シリアルから1行読み取り、コマンド完成で true 返す
bool getCommandLineFromSerialPort(char *commandLine) {
static uint8_t charsRead = 0;
while (Serial.available()) {
char c = Serial.read();
switch (c) {
case CR: case LF:
commandLine[charsRead] = NULLCHAR;
if (charsRead > 0) {
charsRead = 0;
Serial.println(commandLine); // エコーバック
return true;
}
break;
case BS:
if (charsRead > 0) {
commandLine[--charsRead] = NULLCHAR;
Serial.write(BS); Serial.write(SPACE); Serial.write(BS);
}
break;
default:
// c = tolower(c); // 大文字小文字を区別しない場合は有効化
if (charsRead < COMMAND_BUFFER_LENGTH) {
commandLine[charsRead++] = c;
}
commandLine[charsRead] = NULLCHAR;
break;
}
}
return false;
}
// トークン→数値
int readNumber() {
char *numTextPtr = strtok(NULL, delimiters);
return atoi(numTextPtr);
}
// トークン→文字列
char *readWord() {
return strtok(NULL, delimiters);
}
void nullCommand(char *ptrToCommandName) {
print2("Command not found: ", ptrToCommandName);
}
// ---- ここに独自コマンド関数を追加 ----
int addCommand() {
int a = readNumber();
int b = readNumber();
return a + b;
}
int subtractCommand() {
int a = readNumber();
int b = readNumber();
return a - b;
}
// -----------------------------------
// コマンドディスパッチャー
bool DoMyCommand(char *commandLine) {
char *cmd = strtok(commandLine, delimiters);
if (!cmd) return false;
int result;
if (strcmp(cmd, addCommandToken) == 0) {
result = addCommand();
print2("> The sum is = ", result);
} else if (strcmp(cmd, subtractCommandToken) == 0) {
result = subtractCommand();
print2("> The difference is = ", result);
} else {
nullCommand(cmd);
}
return true;
}
#endif // COMMAND_LINE_H
活用例
setPWM 9, 200→ PWM出力変更readTemp→ 温度センサー値表示motor 1, 150→ モーター速度設定pid 2.5, 0.1, 100→ PIDゲイン動的変更log 1/log 0→ データログ ON/OFF
大量コマンド時の高速化ヒント
- コマンド名を1文字にして
switch-case化 - ハッシュテーブル (連想配列) で O(1) ルックアップ
- ただし Arduino では数十コマンドまでなら
if-elseで十分高速
製造プロセス
- 長い driveway 向けの信頼性の高いワイヤレスセンサー - Raspberry Piとの簡単統合
- デジタルピンのみでRaspberry Pi用低コスト赤外線近接センサーを構築
- ANDY – 多目的ヒューマノイドロボット
- シンプルPiロボット - Raspberry Piで2WD自律ローバーを構築
- スチールコイルスリッターラインの理解:コイルを精密ストラップに加工する
- トップカットツーレングスラインメーカー:包括的ガイド
- C# コメントをマスターする:種類、ベストプラクティス、XML ドキュメント
- C#インターフェイスをマスターする:定義、実装、実践的なユースケース
- C言語コマンドライン引数のマスター:実践ガイド
- C#のインターフェース:堅牢なオブジェクト指向設計のための契約定義
- Javaインターフェース完全ガイド:概念、実装、ベストプラクティス