🦾 راهاندازی سروو موتور با ESP32: کتابخانهی ESP32Servo، روش ledc ۵۰ هرتز و تغذیهی درست
اگر قبلاً با آردوینو اونو سروو چرخانده باشی، احتمالاً اولین تلاشت با ESP32 با یک خطا تمام شده است: کتابخانهی Servo.h میگوید فقط بردهای AVR را پشتیبانی میکند. خبر خوب این است که راهاندازی سروو با ESP32 با یک کتابخانهی دیگر دقیقاً به همان سادگی است و حتی بدون کتابخانه، با واحد PWM خود ESP32 هم میشود. در این آموزش هر دو روش را یاد میگیریم، سروو را با یک پتانسیومتر کنترل میکنیم و مهمتر از همه، یاد میگیریم سروو را درست تغذیه کنیم تا برد وسط کار ریست نشود. کد اصلی را در شبیهساز ESP32، به همان سبکی که در ووکوی (Wokwi) کار میکنی، اجرا میکنیم.
سروو چطور زاویه را میفهمد؟
سروو موتور یک موتور کوچک با چرخدنده و یک مدار کنترل داخلی است. سیم سیگنال آن هر ۲۰ میلیثانیه (یعنی ۵۰ بار در ثانیه، ۵۰ هرتز) یک پالس میگیرد و طول همین پالس زاویه را تعیین میکند: حدود ۵۰۰ میکروثانیه یعنی صفر درجه، ۱۵۰۰ میکروثانیه یعنی وسط (۹۰ درجه) و حدود ۲۴۰۰ میکروثانیه یعنی ۱۸۰ درجه. این عددها بین مدلها کمی فرق دارند. پس هر روشی که بتواند یک پالس ۵۰ هرتزی با طول دقیق بسازد، میتواند سروو را بچرخاند. این همان PWM است، فقط با فرکانس خیلی پایین. اگر فرق سروو با موتور معمولی برایت روشن نیست، سروو یا موتور DC؟ را بخوان.
قطعهها و سیمکشی
- یک برد ESP32
- یک سروو موتور کوچک مثل SG90
- یک پتانسیومتر ۱۰ کیلو اهم
- برای سرووهای بزرگ: یک منبع ۵ ولت جدا و یک خازن ۴۷۰ تا ۱۰۰۰ میکروفاراد
| از | به ESP32 | توضیح |
|---|---|---|
| سیم قهوهای یا مشکی سروو | GND | زمین مشترک؛ هرگز فراموشش نکن |
| سیم قرمز سروو | VIN | ۵ ولت USB؛ نه 3V3 |
| سیم نارنجی یا زرد سروو | GPIO18 | سیگنال؛ پایهی امن و بدون نقش در بوت |
| پایهی کناری پتانسیومتر | 3V3 | ولتاژ مرجع ADC |
| پایهی وسط پتانسیومتر | GPIO34 | ورودی آنالوگ روی ADC1 |
| پایهی کناری دیگر پتانسیومتر | GND |
چرا GPIO18 و GPIO34؟ اولی هیچ کار خاصی هنگام بوت نمیکند و دومی بهترین پایهی آنالوگ است. منطق انتخاب پایهها را در پین اوت ESP32 نوشتهایم.
روش ۱: کتابخانهی ESP32Servo (پیشنهادی)
در آردوینو IDE از منوی Tools گزینهی Manage Libraries را باز کن، ESP32Servo را جستوجو کن و نصبش کن. این کتابخانه از واحد ledc خود ESP32 استفاده میکند ولی دستورهایش همان attach و write آشناست. اگر هستهی ESP32 نسخهی ۳ داری، ESP32Servo هم باید نسخهی ۳ یا جدیدتر باشد.
// ESP32 + servo: the knob sets the angle (ESP32Servo library).
#include <ESP32Servo.h>
const int SERVO_PIN = 18; // any output pin that is not a strapping pin
const int POT = 34; // ADC1, input-only
Servo arm;
int lastAngle = -1;
void setup() {
Serial.begin(115200);
arm.attach(SERVO_PIN, 500, 2400); // pulse width (us) for 0 and 180 degrees
arm.write(90); // start in the middle
}
void loop() {
int raw = analogRead(POT); // 0..4095 on ESP32
int angle = map(raw, 0, 4095, 0, 180);
if (abs(angle - lastAngle) > 1) { // ignore tiny ADC jitter
arm.write(angle);
lastAngle = angle;
Serial.print("angle:");
Serial.println(angle);
}
delay(20);
}
#include <ESP32Servo.h>بهجایServo.h. اسم کلاس همانServoاست، پس بقیهی کدهای قدیمیات تقریباً بدون تغییر کار میکنند.arm.attach(SERVO_PIN, 500, 2400)دو عدد اضافه دارد: طول پالس برای صفر و ۱۸۰ درجه. با این دو عدد، سرووهای SG90 بیشتر بازهی واقعیشان را میچرخند. اگر سروو در دو انتها صدای «زززز» میدهد و فشار میآورد، بازه را کمی تنگتر کن، مثلاً ۶۰۰ و ۲۳۰۰. فرکانس پیشفرض این کتابخانه ۵۰ هرتز است؛ اگر خواستی صریحاً بنویسی، قبل از attach دستورarm.setPeriodHertz(50)را روی برد واقعی اضافه کن.map(raw, 0, 4095, 0, 180)عدد ADC دوازدهبیتی ESP32 را به زاویه تبدیل میکند. اگر کد را از اونو آوردهای، ۱۰۲۳ را به ۴۰۹۵ تغییر بده. حساب map را میتوانی در ماشینحساب map امتحان کنی.- شرط
abs(angle - lastAngle) > 1سروو را از لرزش نجات میدهد. ADC در ESP32 کمی نویز دارد و بدون این شرط، سروو مدام یک درجه اینطرف و آنطرف میرود. جزئیات نویز ADC در آموزش analogRead در ESP32 است. - خروجی
angle:در سریال برای نمودار سریال است؛ زاویه را زنده به شکل منحنی میبینی.
روش ۲: بدون کتابخانه، با ledc در ۵۰ هرتز
اگر میخواهی بفهمی پشت صحنه چه میگذرد، یا نمیخواهی کتابخانه نصب کنی، خودت پالس را با ledc بساز. ایده ساده است: یک کانال PWM با فرکانس ۵۰ هرتز و دقت ۱۶ بیت میسازیم. دورهی هر موج ۲۰۰۰۰ میکروثانیه است و دقت ۱۶ بیتی یعنی این دوره به ۶۵۵۳۶ قسمت تقسیم میشود. پس برای پالس ۱۵۰۰ میکروثانیهای، مقدار duty برابر ۱۵۰۰ ضرب در ۶۵۵۳۵ تقسیم بر ۲۰۰۰۰ است؛ یعنی حدود ۴۹۱۵.
// ESP32 servo without a library: ledc at 50 Hz (Arduino-ESP32 core 3.x).
const int SERVO_PIN = 18;
const int FREQ = 50; // 50 pulses per second = 20 ms period
const int BITS = 16; // duty range 0..65535
// convert a pulse width in microseconds to a 16-bit duty value
uint32_t usToDuty(int us) {
uint32_t duty = us; // 32-bit, so us * 65535 cannot overflow
return duty * 65535 / 20000;
}
void writeAngle(int angle) {
int us = map(angle, 0, 180, 500, 2400);
ledcWrite(SERVO_PIN, usToDuty(us));
}
void setup() {
ledcAttach(SERVO_PIN, FREQ, BITS);
}
void loop() {
writeAngle(0);
delay(1000);
writeAngle(90);
delay(1000);
writeAngle(180);
delay(1000);
}
این کد برای هستهی نسخهی ۳ نوشته شده است. اگر هستهی نسخهی ۲ داری، در setup بنویس ledcSetup(0, 50, 16); ledcAttachPin(SERVO_PIN, 0); و در writeAngle بهجای پایه، شمارهی کانال را بده: ledcWrite(0, usToDuty(us)). فرق این دو نسخه را در آموزش PWM با ledc مفصل گفتهایم. برای حسابهای duty و فرکانس هم ماشینحساب PWM به کار میآید.
تغذیهی سروو: جایی که بیشتر پروژهها خراب میشوند
سروو موقع شروع حرکت، مخصوصاً وقتی باری روی بازویش هست، در یک لحظه جریان زیادی میکشد: یک SG90 کوچک تا چند صد میلیآمپر و یک MG996R تا بیش از یک آمپر. اگر این جریان از همان USB بیاید که ESP32 را روشن نگه داشته، ولتاژ یک لحظه افت میکند و ESP32 با پیام Brownout detector was triggered در سریال مانیتور ریست میشود. این قانونها را رعایت کن:
- هرگز سروو را از 3V3 تغذیه نکن. هم ولتاژش کم است و هم رگولاتور برد این جریان را نمیدهد.
- یک SG90 بدون بار: از VIN (۵ ولت USB) مشکلی ندارد. یک خازن ۴۷۰ میکروفاراد بین سیم قرمز و قهوهای، نزدیک سروو، افت لحظهای را جبران میکند.
- دو سروو یا بیشتر، یا سرووهای فلزی مثل MG996R: منبع ۵ تا ۶ ولتی جدا با حداقل ۲ آمپر بگذار. سیم قرمز سروو به مثبت منبع، و منفی منبع به GND برد ESP32. بدون زمین مشترک، سیگنال معنی ندارد.
- سیگنال ۳٫۳ ولتی برای سرووهای رایج کافی است و مبدل سطح لازم نیست.
دربارهی انتخاب منبع تغذیه برای پروژهها، راهنمای منبع تغذیهی آردوینو نکتههای خوبی دارد که برای ESP32 هم صادق است.
اجرا در شبیهساز
در تینکرکد فارسی برد ESP32، سروو و پتانسیومتر را بگذار، سیمکشی جدول را انجام بده و کد روش ۱ (ESP32Servo) را اجرا کن. با چرخاندن ولوم، بازوی سروو همزمان میچرخد و زاویه در سریال و نمودار دیده میشود. روش ۲ را روی برد واقعی امتحان کن. خواندن مثالها رایگان است و اجرای ESP32 به اشتراک Plus نیاز دارد. همین مدار با آردوینو اونو بهصورت رایگان در پروژهی آمادهی پتانسیومتر کنترل سروو هست و درس «فرمان با ولوم» منطق map را قدمبهقدم درس میدهد. اگر wokwi.com برایت کند باز میشود، این شبیهساز روی اینترنت ملی هم کار میکند.
اشکالهای رایج
- خطای «This library only supports boards with an AVR...»: هنوز
Servo.hرا include کردهای. ESP32Servo را نصب کن و include را عوض کن. - ESP32 با حرکت سروو ریست میشود: تغذیه کم است. خازن بگذار یا منبع جدا با زمین مشترک.
- سروو اصلاً تکان نمیخورد: سیگنال را به یکی از پایههای ۳۴ تا ۳۹ وصل کردهای که فقط ورودیاند، یا GND مشترک نیست.
- سروو فقط تا نصف راه میرود: در
mapهنوز ۱۰۲۳ نوشتهای. ADC در ESP32 تا ۴۰۹۵ میرود. - سروو مدام میلرزد: نویز ADC است؛ شرط حداقل تغییر را نگه دار یا چند نمونه میانگین بگیر.
- بعد از اضافه کردن سروو، LED که با ledc کم و زیاد میشد خراب شد: هر دو از واحد ledc استفاده میکنند و فرکانسهایشان با هم تداخل کرده است. در ESP32Servo هر سروو کانال خودش را میگیرد؛ LED را روی پایه و کانال دیگری بگذار.
نسخهی آردوینوی همین آموزش را در سروو موتور با آردوینو و نسخهی میکروپایتون را در سروو با پیکو ببین. قدم بعدی جذاب: سروو را از گوشی کنترل کن، با ترکیب همین کد و وبسرور ESP32. همهی آموزشها در صفحهی ESP32.
سروو و پتانسیومتر را در تینکرکد فارسی بچرخان 🦾سؤالهای رایج
چرا کتابخانهی Servo.h روی ESP32 کامپایل نمیشود؟
کتابخانهی Servo که همراه آردوینو IDE است برای تایمرهای تراشههای AVR نوشته شده و ESP32 را نمیشناسد. بهجایش کتابخانهی ESP32Servo را از Library Manager نصب کن؛ دستورهایش تقریباً همانهاست.
سروو را به کدام پایهی ESP32 وصل کنم؟
هر پایهای که خروجی میشود و strapping نیست؛ مثلاً GPIO13، 18، 19، 23، 25، 26 یا 27. پایههای 34 تا 39 فقط ورودیاند و سروو را حرکت نمیدهند.
میشود سروو را از پایهی 3V3 ESP32 تغذیه کرد؟
نه. سروو با ۵ ولت کار میکند و موقع حرکت جریان زیادی میکشد. یک SG90 را میشود از پایهی VIN (۵ ولت USB) تغذیه کرد و سرووهای بزرگتر منبع ۵ یا ۶ ولتی جدا با زمین مشترک میخواهند.
آیا سیگنال ۳٫۳ ولتی ESP32 برای سروو کافی است؟
برای بیشتر سرووهای رایج مثل SG90 و MG996R بله؛ آنها پالس ۳٫۳ ولتی را بهخوبی تشخیص میدهند. فقط زمین ESP32 و زمین تغذیهی سروو باید به هم وصل باشند.