اموزش راه اندازی کنترل سروو موتور با سیگنال PWM میکروکنترلر AVR

اموزش راه اندازی کنترل سروو موتور با سیگنال PWM میکروکنترلر AVR ، اگر تا به حال با میکروکنترلرهای AVR مثل ATmega8 یا ATmega328 کار کرده باشید، احتمالاً به این نقطه رسیدهاید که بخواهید یک سروو موتور را حرکت بدهید. شاید برای یک بازوی رباتیک باشد، شاید برای یک پروژه دوربین پنتیلت، یا حتی یک درب هوشمند خانگی. نکته جالب اینجاست که کنترل سروو موتور با AVR در نگاه اول ساده به نظر میرسد، اما وقتی وارد جزئیات تایمرها، رجیسترها و محاسبات پالس میشوید، متوجه میشوید که چند نکته ظریف وجود دارد که اگر رعایت نشوند، سروو موتور شما یا اصلاً حرکت نمیکند، یا میلرزد، یا زاویهاش دقیق نیست.
در این مقاله قصد دارم تجربهای کاملاً کاربردی و مرحلهبهمرحله از راهاندازی سروو موتور با AVR و سیگنال PWM را با شما به اشتراک بگذارم؛ از مبانی فیزیکی کار سروو گرفته تا کدنویسی واقعی روی ATmega، تنظیم تایمرها، محاسبه دقیق مقدار OCR، و رفع مشکلات رایجی که تقریباً هر کسی در این مسیر با آنها روبرو میشود.
سروو موتور چیست و چرا با موتورهای DC معمولی فرق دارد؟
سروو موتور در واقع یک موتور DC کوچک است که با یک سیستم دندهکاهنده (Gearbox) و یک پتانسیومتر بازخورد (Feedback Potentiometer) ترکیب شده. این ترکیب باعث میشود سروو موتور بتواند زاویه دقیقی را نگه دارد، برخلاف موتورهای DC ساده که فقط میچرخند و متوقف نمیشوند در یک نقطه مشخص.
داخل بدنه سروو، یک مدار کنترلی کوچک وجود دارد که به طور مداوم زاویه فعلی شفت را با زاویهای که از طریق پالس PWM درخواست شده مقایسه میکند و بر اساس اختلاف این دو، موتور DC داخلی را میچرخاند تا به زاویه هدف برسد. این حلقه بازخورد داخلی همان چیزی است که سروو را از یک موتور معمولی متمایز میکند و دقیقاً همین ویژگی است که کنترل آن را هم ساده و هم حساس میکند.
سروو موتورهای رایج مثل SG90 یا MG995 معمولاً در بازه ۰ تا ۱۸۰ درجه کار میکنند، هرچند مدلهای خاصی هم وجود دارند که تا ۳۶۰ درجه یا حتی چرخش پیوسته (Continuous Rotation) را پشتیبانی میکنند.
اصول سیگنال PWM برای کنترل سروو
نکتهای که خیلی از تازهکارها را گیج میکند این است: PWM که برای کنترل سروو استفاده میشود، با PWM معمولی که برای کنترل روشنایی LED یا سرعت موتور DC به کار میرود، از نظر مفهومی فرق دارد. در کنترل LED، درصد دیوتیسایکل (Duty Cycle) مهم است، اما در سروو موتور، عرض واقعی پالس بر حسب میلیثانیه است که تعیینکننده زاویه است.
استاندارد رایج صنعتی برای سروو موتورهای آنالوگ به این شکل است:
- فرکانس پالس: ۵۰ هرتز (یعنی هر پالس هر ۲۰ میلیثانیه تکرار میشود)
- عرض پالس ۱ میلیثانیه: معادل زاویه ۰ درجه
- عرض پالس ۱.۵ میلیثانیه: معادل زاویه ۹۰ درجه (نقطه وسط)
- عرض پالس ۲ میلیثانیه: معادل زاویه ۱۸۰ درجه
این بازهها بین برندهای مختلف کمی فرق میکند و بعضی سروو موتورها بازهای بین ۰.۵ تا ۲.۵ میلیثانیه را هم میپذیرند تا زاویه کامل ۱۸۰ درجه را پوشش دهند. به همین دلیل توصیه میکنم همیشه دیتاشیت سروو موتور خودتان را چک کنید، چون خیلی از مشکلات “زاویه دقیق نیست” از همینجا شروع میشود.
چرا AVR برای این کار مناسب است؟
میکروکنترلرهای AVR مثل خانواده ATmega دارای تایمرهای سختافزاری (Hardware Timers) با قابلیت PWM هستند که میتوانند بدون دخالت مداوم پردازنده، پالسهای دقیق و پایدار تولید کنند. این یعنی حتی اگر برنامه اصلی شما مشغول انجام کارهای دیگری باشد، تایمر همچنان پالس PWM را با دقت بالا تولید میکند. این ویژگی برخلاف روشهای نرمافزاری (Software PWM با delay) است که در آنها هر تاخیر کوچک در کد میتواند باعث لرزش یا ناپایداری سروو شود.
اکثر پروژههای آموزشی از ATmega8، ATmega16، یا ATmega328 (همان تراشهای که در آردوینو اونو استفاده میشود) برای این منظور استفاده میکنند. در ادامه من روی ATmega328 با فرکانس کریستال ۱۶ مگاهرتز تمرکز میکنم، چون هم در دسترسترین گزینه است و هم منابع آموزشی زیادی برایش وجود دارد.
آشنایی با تایمر ۱ (Timer1) در AVR برای تولید PWM سروو
برای کنترل سروو موتور، معمولاً از تایمر ۱ استفاده میشود، چون این تایمر ۱۶ بیتی است (برخلاف تایمر ۰ و ۲ که ۸ بیتی هستند) و رزولوشن بسیار بالاتری برای محاسبه عرض پالس در اختیار میگذارد. با تایمر ۸ بیتی، دقت زاویهبندی سروو به شدت افت میکند و حرکت موتور به جای نرم بودن، پلهای و ناهموار میشود.
برای تولید PWM با فرکانس ۵۰ هرتز، باید تایمر را در حالت Fast PWM با ICR1 به عنوان مقدار TOP پیکربندی کنید. این حالت به شما اجازه میدهد فرکانس پایه پالس را کاملاً دلخواه تنظیم کنید، که برای رسیدن دقیق به ۵۰ هرتز ضروری است.
محاسبه مقادیر پریسکالر و ICR1
فرمول کلی برای محاسبه فرکانس در حالت Fast PWM با TOP = ICR1 اینطور است:
Frequency = F_CPU / (Prescaler × (1 + ICR1))
با فرض کریستال ۱۶ مگاهرتزی و پریسکالر ۸، برای رسیدن به ۵۰ هرتز داریم:
50 = 16,000,000 / (8 × (1 + ICR1))
1 + ICR1 = 16,000,000 / (8 × 50) = 40000
ICR1 = 39999
پس با پریسکالر ۸ و ICR1 برابر با ۳۹۹۹۹، دقیقاً به فرکانس ۵۰ هرتز میرسیم. این یعنی هر واحد از رجیستر OCR1A معادل:
20ms / 40000 = 0.0005ms = 0.5 میکروثانیه
بنابراین برای تنظیم عرض پالس ۱.۵ میلیثانیه (زاویه ۹۰ درجه)، مقدار OCR1A باید برابر ۳۰۰۰ باشد (چون ۱۵۰۰ میکروثانیه تقسیم بر ۰.۵ میکروثانیه میشود ۳۰۰۰).
کد کامل راهاندازی سروو با AVR (زبان C، بدون کتابخانه آردوینو)
در ادامه یک نمونه کد کامل برای ATmega328 با کریستال ۱۶ مگاهرتز آوردهام که سروو موتور را روی پایه OC1A (که در آردوینو اونو معادل پین دیجیتال ۹ است) کنترل میکند:
#include <avr/io.h>
#include <util/delay.h>
void servo_init(void) {
DDRB |= (1 << PB1); // پایه OC1A را به عنوان خروجی تنظیم کن
// حالت Fast PWM با TOP = ICR1، خروجی روی OC1A غیرمعکوس
TCCR1A = (1 << COM1A1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); // پریسکالر 8
ICR1 = 39999; // برای فرکانس 50Hz با کریستال 16MHz
}
void servo_set_angle(uint8_t angle) {
if (angle > 180) angle = 180;
// نگاشت زاویه 0 تا 180 به عرض پالس 1000 تا 2000 میکروثانیه
uint16_t pulse_us = 1000 + ((uint32_t)angle * 1000) / 180;
// تبدیل میکروثانیه به مقدار OCR1A (هر واحد = 0.5 میکروثانیه)
OCR1A = pulse_us * 2;
}
int main(void) {
servo_init();
while (1) {
servo_set_angle(0);
_delay_ms(1000);
servo_set_angle(90);
_delay_ms(1000);
servo_set_angle(180);
_delay_ms(1000);
}
}
این کد را میتوانید مستقیماً با avr-gcc کامپایل کرده و روی تراشه بریزید، یا اگر از محیط Atmel Studio استفاده میکنید، همین ساختار بدون تغییر خاصی کار میکند.
نکتهای که تجربه شخصی به من یاد داده: تابع servo_set_angle را طوری بنویسید که همیشه محدوده ورودی را چک کند (مثل خط if (angle > 180) در کد بالا). یک بار در یک پروژه، به خاطر نبود همین چک ساده، مقدار زاویه از یک باگ در کد بالادستی به بیش از ۲۵۵ رسید و باعث شد سروو با فشار زیاد به انتهای دنده برخورد کند و در نهایت دنده پلاستیکی داخلش بشکند. اینجور جزئیات کوچک، در عمل خیلی مهمتر از چیزی هستند که در تئوری به نظر میرسند.
اتصال سختافزاری: نکاتی که در آموزشها کمتر گفته میشود
از نظر سیمکشی، سروو موتور معمولاً سه سیم دارد:
- سیم قرمز: تغذیه مثبت (معمولاً ۵ ولت)
- سیم قهوهای یا مشکی: زمین (GND)
- سیم نارنجی یا زرد: سیگنال PWM
نکته مهمی که خیلی وقتها نادیده گرفته میشود این است: هیچوقت سروو موتور را مستقیماً از پین تغذیه برد AVR یا آردوینو تغذیه نکنید، مخصوصاً اگر بیش از یک سروو دارید یا سرووی که استفاده میکنید (مثل MG995) جریان بالایی میکشد. جریان راهاندازی (Stall Current) سروو موتور میتواند به راحتی به چند صد میلیآمپر یا حتی بیشتر برسد و این جریان میتواند باعث افت ولتاژ کل مدار شود، که نتیجهاش ریست شدن ناخواسته میکروکنترلر یا رفتار عجیب و غیرقابل پیشبینی است.
توصیه عملی من: از یک منبع تغذیه جداگانه ۵ ولت (یا ولتاژی که سروو نیاز دارد) برای تغذیه سروو استفاده کنید، و فقط زمین (GND) منبع تغذیه سروو را به زمین برد AVR وصل کنید تا رفرنس مشترک داشته باشند. این یک نکته ساده است، اما باعث میشود بسیاری از مشکلات عجیب و غریب که در انجمنهای آنلاین دیده میشوند، از ابتدا رخ ندهند.
مشکلات رایج و راهحل آنها
سروو موتور میلرزد یا نویز دارد
این معمولاً به یکی از این دلایل برمیگردد:
- افت ولتاژ ناشی از تغذیه ضعیف: همانطور که گفتم، از منبع تغذیه جداگانه استفاده کنید.
- فرکانس PWM نادرست: اگر فرکانس دقیقاً ۵۰ هرتز نباشد، بعضی سروو موتورها (مخصوصاً مدلهای دیجیتال) رفتار ناپایدار نشان میدهند.
- نویز الکتریکی روی خط سیگنال: اگر سیم سیگنال طولانی است، یک خازن سرامیکی کوچک (حدود ۱۰۰ نانوفاراد) بین سیگنال و زمین نزدیک ورودی سروو میتواند کمک کند.
زاویه دقیق نیست
اگر متوجه شدید زاویه واقعی سروو با زاویهای که در کد ست کردهاید فرق دارد، محتملترین دلیل این است که بازه پالس سروو شما (مثلاً ۱ تا ۲ میلیثانیه) با بازه واقعی که در دیتاشیت آن سروو خاص آمده، یکسان نیست. بعضی سروو موتورهای ارزانقیمت بازهای مثل ۰.۹ تا ۲.۱ میلیثانیه دارند. بهترین راه، کالیبراسیون دستی است: چند مقدار مختلف OCR1A را امتحان کنید و زاویه واقعی را با یک نقاله (Protractor) اندازه بگیرید، سپس معادله نگاشت خودتان را بر اساس داده واقعی تنظیم کنید.
سروو اصلاً حرکت نمیکند
قبل از شک کردن به کد، این موارد را چک کنید:
- آیا پایه انتخابی واقعاً به تایمر و کانال PWM درستی متصل است؟ (روی ATmega328، OC1A فقط روی PB1 فعال میشود)
- آیا
DDRBبرای آن پین به درستی به عنوان خروجی تنظیم شده؟ - آیا تغذیه سروو واقعاً وصل است و ولتاژ کافی میرسد؟
- آیا فیوزهای (Fuse Bits) میکروکنترلر با فرکانس کریستالی که در کد فرض کردهاید مطابقت دارند؟ این یکی از رایجترین اشتباهاتی است که باعث میشود همه محاسبات فرکانس PWM بههم بریزد.
کنترل چند سروو موتور همزمان
اگر پروژه شما نیاز به کنترل بیش از یک سروو دارد (مثلاً برای یک بازوی رباتیک با چند مفصل)، میتوانید از هر دو کانال تایمر ۱ (یعنی OC1A و OC1B) استفاده کنید که به شما اجازه میدهد دو سروو را مستقل از هم کنترل کنید، بدون اینکه به کد نرمافزاری اضافی نیاز داشته باشید. برای بیش از دو سروو، معمولاً باید سراغ روشهای دیگری مثل استفاده از تایمرهای اضافی، یا تولید نرمافزاری پالس با استفاده از وقفههای Compare Match و چرخش بین چند خروجی (تکنیکی که به آن Software Multiplexed PWM هم گفته میشود) بروید.
سوالات متداول
از نظر فنی امکانپذیر است، اما به شدت توصیه نمیشود. این روش پردازنده را کاملاً درگیر تولید پالس میکند و اجازه انجام هیچ کار دیگری را در همان زمان نمیدهد، و معمولاً پایداری کمتری نسبت به روش سختافزاری دارد.
چون تایمر ۱ در اکثر تراشههای AVR رایج ۱۶ بیتی است و رزولوشن بسیار بالاتری برای تنظیم دقیق عرض پالس در اختیار میگذارد، در حالی که تایمر ۰ و ۲ معمولاً ۸ بیتی هستند.
نه لزوماً. این یک استاندارد رایج است اما بعضی مدلها بازه متفاوتی دارند. همیشه بهتر است دیتاشیت سروو خاص خودتان را چک کنید یا آن را بهصورت عملی کالیبره کنید.
بله، اما دقت زاویهبندی به شدت کاهش مییابد و حرکت سروو ممکن است پلهای و ناهموار به نظر برسد، مخصوصاً در زوایای میانی.
یک منبع تغذیه جداگانه با ولتاژ مناسب (معمولاً ۵ تا ۶ ولت) و جریان کافی (بسته به تعداد و نوع سروو، معمولاً چند آمپر) بهترین گزینه است. همیشه زمین مشترک بین منبع تغذیه سروو و برد AVR را فراموش نکنید.
جمعبندی
کنترل سروو موتور با AVR در نهایت به سه چیز خلاصه میشود: درک درست از رابطه بین عرض پالس و زاویه، پیکربندی صحیح تایمر برای تولید فرکانس دقیق ۵۰ هرتز، و رعایت نکات سختافزاری ساده اما حیاتی مثل تغذیه جداگانه. وقتی این سه اصل رعایت شوند، سروو موتور شما نرم، دقیق و قابلاعتماد حرکت میکند، دقیقاً همان چیزی که برای یک پروژه رباتیک یا اتوماسیون خوب لازم است.
اگر تازه شروع کردهاید، پیشنهاد میکنم ابتدا با یک سروو ساده مثل SG90 و کد بالا تمرین کنید، رفتار آن را با مقادیر مختلف OCR1A مشاهده کنید، و بعد به سراغ پروژههای پیچیدهتر مثل کنترل چند سروو یا ترکیب آن با حسگرهای بازخورد بروید. تجربه عملی در این زمینه از هر مقاله یا آموزشی مهمتر است.
اگر این مقاله اموزش راه اندازی کنترل سروو موتور با سیگنال PWM میکروکنترلر AVR برای شما مفید بود، آن را با دوستان خود به اشتراک بگذارید و برای مشاهده آموزشهای بیشتر به سایت ما سر بزنید
مطلب پیشنهادی
آموزش کامل تابع millis در آردوینو ؛ خداحافظی با delay و کدنویسی همزمان
دیدگاههای محترمانه: لطفاً نظرات خود را با رعایت احترام به دیگران و به صورت محترمانه ارسال کنید. از بهکار بردن زبان توهینآمیز، تهدیدآمیز یا نژادپرستانه خودداری کنید.
حفظ حریم خصوصی: از درج اطلاعات شخصی خود یا دیگران مانند شماره تماس، آدرس و هرگونه اطلاعات حساس خودداری کنید.
محتوای تبلیغاتی: ارسال دیدگاههای تبلیغاتی، لینکهای خارجی یا هر نوع محتوای تجاری که مرتبط با موضوع نباشد، ممنوع است.
موافقت با قوانین: با ارسال دیدگاه خود، شما تأیید میکنید که قوانین فوق را خوانده و با آنها موافقید. تیم ما حق دارد نظرات غیرمجاز را حذف کند.
پروژه های پیشنهادی
پروژه ریموت کنترل کدلرن حرفه ای
مشاهده پروژهپروژه امپلی فایر صوتی استریو با TDA2030
مشاهده پروژهپروژه قفل دیجیتال با ماژول RFID RC522
مشاهده پروژه