ESP32とFreeRTOSのタスク(マルチスレッド)機能を使って、2つのサーボモータを同時に動かす方法をまとめます。delay 関数だけだと一方の処理待ちでもう一方が止まり、複数のサーボを別々のリズムで動かすのが難しいです。本記事では ESP32Servo ライブラリと xTaskCreate を組み合わせ、それぞれのサーボを独立したタスクで制御します。
必要なものはESP32ボード(ESP32 DevKitCなど)、SG90のようなサーボモータ2個、サーボ用の外部5V電源、Arduino IDEまたは PlatformIO のいずれかです。実際の動作は次の動画で確認できます。
なんの工夫もなしに delay 関数を使ってサーボモータを動かそうとすると、ひとつのサーボモータの処理が終わるまで待たなければならず、同時に動かすことが難しいです。非ブロッキングなポーリング処理(コルーチン)で動かすやり方も考えられますが、コーディングが複雑になり管理が難しいです。ESP32ならばFreeRTOSのタスク機能(マルチスレッド)が使えますので、簡単に複数のサーボモータを動かすことが可能です。
ソースコード
次のコードは、FreeRTOSのタスク利用してマルチスレッドで複数サーボモータを制御する例です:
#include <Arduino.h>
#include <ESP32Servo.h>
#define SERVO_A_PIN 32
#define SERVO_B_PIN 33
Servo servoA, servoB;
const int pulse_min = 544; // default 544us
const int pulse_max = 2400; // default 2400us
// プロトタイプ宣言
void taskServoA(void * parameter);
void taskServoB(void * parameter);
void setup() {
Serial.begin(115200);
servoA.attach(SERVO_A_PIN, pulse_min, pulse_max);
servoB.attach(SERVO_B_PIN, pulse_min, pulse_max);
servoA.write(5); // リセット
servoB.write(5); // リセット
delay(2000);
// FreeRTOSを使用してタスクを作成
xTaskCreate(taskServoA, "TaskServoA", 10000, NULL, 1, NULL);
xTaskCreate(taskServoB, "TaskServoB", 10000, NULL, 1, NULL);
}
void loop() {
}
void taskServoA(void * parameter) {
for (;;) {
for (int pos = 5; pos <= 180; pos += 1) {
servoA.write(pos);
vTaskDelay(2 / portTICK_PERIOD_MS);
}
vTaskDelay(700 / portTICK_PERIOD_MS);
for (int pos = 180; pos >= 5; pos -= 1) {
servoA.write(pos);
vTaskDelay(2 / portTICK_PERIOD_MS);
}
vTaskDelay(700 / portTICK_PERIOD_MS);
}
}
void taskServoB(void * parameter) {
for (;;) {
for (int pos = 5; pos <= 180; pos += 1) {
servoB.write(pos);
vTaskDelay(6 / portTICK_PERIOD_MS);
}
vTaskDelay(300 / portTICK_PERIOD_MS);
for (int pos = 180; pos >= 5; pos -= 1) {
servoB.write(pos);
vTaskDelay(6 / portTICK_PERIOD_MS);
}
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}
解説
サーボモータを、0度から180度へ行き来させるプログラミングです。サーボモータの制御は、ESP32Servo ライブラリを使用しました。
本来は pos = 0 とすべきですが、サーボモータが震えてしまうため、5度までを下限として pos = 5 のように宣言してます。
xTaskCreate で、タスク(スレッド)を作成します。
一時停止を行いたい場合は delay 関数を使わずに、 vTaskDelay で処理します。vTaskDelay は、タスクを指定した時間だけブロック(一時停止)できます。
配線と電源の注意
SG90のような小型サーボでも、2個同時に動かすと瞬間的に大きな電流が流れます。ESP32の5V/3.3V出力からそのまま給電すると、起動時にリセットがかかったり書き込みに失敗したりするので、サーボの電源はESP32とは別の5V外部電源から取り、GNDだけESP32と共通にするのが安全です。書き込み自体がうまくいかないときは ESP32への書き込みエラー対処 も合わせて確認してください。
関連記事
- ESP32でLチカするまでの設定
- はじめてのBLE通信、iOSからESP32のLチカ
- Clion x PlatformIOでESP32(Arduino)開発
- 電磁弁とESP32で水道のオンオフを制御してみた
関連アイテム
サーボ駆動には外部電源が必須です。配線とピン番号を確認してから通電してください。