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 ライブラリを使用しました。
...