آموزش ساخت ربات Pick and Place توسط میکروکنترلر ARM

الکترونیک و رباتیک -> ماژول ها و سنسور ها 2380 3 کاربر آکادمی پارتینه

بازوی رباتیکی از جذاب‌ترین سازه‌های مهندسی است که ساختار آن الهام گرفته از بازوی انسان می‌باشد. از بازوی‌های روباتیکی معمولاً در خطوط مونتاژ به منظور انجام کارهایی از قبیل جوشکاری ، حفاری ، نقاشی و ... استفاده می‌شود. در سال‌های اخیر همزمان با پیشرفت تکنولوژی از بازوهای رباتیکی پیشرفته با دقت بسیار بالا تحت عنوان ربات جراح در جراحی نیز استفاده می‌شود. در این آموزش از میکروکنترلر ARM7-LPC2148 برای کنترل ربات و از 4 سروو موتور برای حرکت مفاصل بازوی رباتیکی استفاده می‌شود. بدنه ربات توسط پرینتر سه بعدی، پرینت شده است.

 

مواد اولیه :
# عنوان تعداد لینک
0 میکروکنترلر ARM7-LPC2148 1 لینک خرید
1 سروو موتور SG-90 4 لینک خرید
2 پتانسیومتر 10k 4 لینک خرید
3 آداپتور 5 ولت 1 آمپر 1 لینک خرید
4 مقاومت 10k 4 لینک خرید
5 مقاومت 2.2k 4 لینک خرید
6 برد بورد 1 لینک خرید

مرحله 1 : آماده‌سازی بازوی رباتیکی پرینت شده

بازوی رباتیکی استفاده شده در این آموزش توسط EEZYbotARM ارائه شده و فایل G-code آن در وب سایت Thingiverse موجود است. روش کامل ساخت بازوی این بازوی رباتیکی سه بعدی و جزئیات مونتاژ آن در این لینک موجود است. در تصویر بالا این بازوی رباتیکی سه بعدی بعد از مونتاژ، همراه با چهار سروو موتور نشان داده شده است.

مرحله 2 : اتصالات و دیاگرام مداری

در دیاگرام زیر نحوه اتصال قطعات به پردازنده ARM نشان داده شده است. برای تغذیه سروو موتور از یک آداپتور جداگانه 5 ولت و برای تغذیه شستی و پتانسیومتر از ولتاژ 3.3 میکروکنترلر LPC2148 استفاده شده است. چهار پتانسیومتر به چهار پین ADC میکروکنترلر، همچنین چهار پین PWM میکروکنترلر به چهار پین PWM سروو موتور نیز متصل شده اند. چهار شستی به منظور انتخاب هر کدام از موتورها جهت حرکت در نظر گرفته شده‌اند. شستی‌های متصل شده به GPIO میکروکنترلر از طریق مقاومت‌های 10کیلو اهم پول‌آپ شده‌اند. همچنین از چهار نشانگر LED برای نشان دادن وضعیت سروو موتورها استفاده شده است.

مرحله 3 : کدنویسی و تنظیمات نرم‌افزاری

  • تبدیل  آنالوگ به دیجیتال (ADC) توسط LPC2148

برای تعیین مقدار Duty Cycle درمدولاسیون پهنای باند (PWM) ، جهت کنترل موقعیت سروو موتور لازم است از تبدیل آنالوگ به دیجیتال استفاده شود. از آنجا که چهار پتانسیومتر برای کنترل چهار سروو موتور در نظر گرفته شده، چهار کانال ADC میکروکنترلر LPC2148 مورد استفاده قرار می‌گیرد. در این پروژه از پین‌های (P0.25, P0.28, P0.29, P0.30) یعنی به ترتیب کانال‌های  4،1،2،3 در LPC2148 استفاده می‌شود.

  • تولید سیگنال PWM برای سروو موتور با استفاده از LPC2148

برای کنترل موقعیت سروو موتور نیاز به سیگنال‌های PWM است. در این مکانیزم چهار سروو موتور برای حرکت چهار مفصل بازو استفاده شده، بنابراین به چهار کانال PWM  نیاز است که در اینجا از پین‌های (P0.1, P0.7, P0.8, P0.21) یعنی به ترتیب کانال‌های 5،4،2،3 در LPC2148 استفاده می‌شود.

  • پیکربندی پورت‌های LPC2148

از رجیسترPINSEL1 برای فعال کردن کانال‌های ADC0.4 ، ADC0.1 ، ADC0.2 ، ADC0.3 یعنی پین‌های P0.25 ، P0.28 ، P0.29 ،  P0.30. استفاده می‌شود.

#define AD04 (1<<18) //Select AD0.4 function for P0.25
#define AD01 (1<<24) //Select AD0.1 function for P0.28
#define AD02 (1<<26) //Select AD0.2 function for P0.29
#define AD03 (1<<28) //Select AD0.3 function for P0.30
PINSEL1 |= AD04 | AD01 | AD02 | AD03 | (1<<10);

همچنین به منظور فعال‌سازی کانال‌های PWM یعنی ( PWM3, PWM2, PWM4 ) از پین‌های P0.1, P0.7, P0.8  استفاده می‌شود.

PINSEL0 = 0x000A800A;  

 توسط رجیستر PINSEL2، پین‌های GPIO پورت یک، برای اتصال LEDها و شستی‌ها فعال می‌شوند. برای تعریف نشانگرهای LED به عنوان پین‌های خروجی و شستی‌ها به عنوان ورودی، از رجیستر IODIR1 استفاده می‌شود. (0 برای ورودی و 1 برای خروجی)

IODIR1 = ((0<<17)|(0<<18)|(0<<19)|(0<<20)|(1<<28)|(1<<29)|(1<<30)|(1<<31));

شماره پین‌ها نیز به صورت زیر تعریف می شود.

#define SwitchPinNumber1 17   // (Connected with P1.17)
#define SwitchPinNumber2 18   // (Connected with P1.18)
#define SwitchPinNumber3 19   // (Connected with P1.19)
#define SwitchPinNumber4 20   // (Connected with P1.20)
#define LedPinNumber1    28    // (Connected with P1.28)
#define LedPinNumber2    29    // (Connected with P1.29)
#define LedPinNumber3    30    // (Connected with P1.30)
#define LedPinNumber4    31    // (Connected with P1.31)
  • تنظیمات مبدل ADC

در این مرحله مود و کلاک ADC با استفاده از رجیستر AD0CR_setup تنظیم می‌شود.

unsigned long AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | PowerUP; //Setting up ADC Mode
#define CLKDIV (15-1)                       
#define BURST_MODE_OFF (0<<16)              // 1 for on and 0 for off
#define PowerUP (1<<21)
  • تنظیمات مدولاسیون پهنای پالس (PWM)

در گام اول با استفاده از رجیستر PWMTCR کانتر PWM را غیر فعال کرده و مقدار پیش‌تقسیم کننده‌ای (Prescaler) به تایمر PWM اختصاص داده می‌شود.

PWMTCR = 0x02;          
PWMPR =  0x1D;

در این مرحله حداکثر تعداد شمارش‌ها را در یک چرخه تنظیم می‌شود. این کار در رجیستر (Match 0 (PWMMR0 انجام می‌شود. مقدار 20000 برای تولید یک پالس 20 میلی ثانیه‌ای در نظر گرفته می‌شود.

PWMMR0 = 20000; 

پس از آن مقدار Duty Cycle برای PWMMR4 ، PWMMR2 ، PWMMR3 ، PWMMR5 مشخص می‌شود. در اینجا مقادیر اولیه 0 میلی ثانیه  (Toff) تعیین شده است.

PWMMR4 = 0;               
PWMMR2 = 0;
PWMMR3 = 0;
PWMMR5 = 0;

پس از آن رجیستر کنترلی PWM یعنی رجیستر Match ریست می‌شود.

PWMMCR = 0x00000002;      // Reset on MR0 match
  • انتخاب سروو موتورها جهت چرخش توسط شستی‌ها 

از چهار شستی برای چرخش چهار سروو موتور استفاده شده است. با انتخاب یک شستی تغییر میزان مقاومت پتانسیومتر مربوط به آن مقدار Duty Cycle  تعیین شده و سروو موتور مربوطه موقعیت خود را تغییر می‌دهد. برای به دست آوردن وضعیت شستی داریم:

switchStatus1 = (IOPIN1>>SwitchPinNumber1) & 0x01 ;

بنابراین بسته به اینکه مقدار شستی High باشد، تبدیل ADC صورت گرفته و پس از تبدیل موفقیت‌آمیز مقدار ADC  از بازه‌ی (0 تا 1023) به بازه‌ی  (0 تا 2045) نگاشت شده و سپس مقدار Duty Cycle در پین PWM متصل به سروو موتور (PWMMRx) نوشته می‌شود. همچنین یک نشانگرLED همزمان با High شدن شستی روشن می‌شود. 

if(switchStatus1 == 1)                      
        {  
         IOPIN1 = (1<<LedPinNumber1);             //Make LED1 HIGH
         AD0CR =  AD0CR_setup | SEL_AD01;         //Setup ADC for channel 1
         AD0CR |= START_NOW;                      //Start new Conversion at ADC1
          while( (AD0DR1 & ADC_DONE) == 0 )        //Check for ADC conversion 
         {
          convert1 = (AD0DR1>>6) & 0x3ff;         //Get ADC value
          result1 = map(convert1,0,1023,0,2450);  //Convert ADC values in terms of dutycyle for PWM
          PWMMR5 = result1;                                   //Set Duty Cylce value to PWM5
          PWMLER = 0x20;                          //Enable PWM5
  delay_ms(2);
      }
}
     else
      {
         IOPIN1 = (0<<LedPinNumber1);             //Set LED1 LOW
       }
  • کارکرد بازوی رباتیکی  Pick and Place

پس از آپلود برنامه در LPC2148 یک شستی را فشار داده و پتانسیومتر مربوطه را تغییر دهید تا موقعیت بازوی ربات تغییر کند. هر شستی و پتانسیومتر حرکت سروو موتور را برای حرکت به سمت بالا و پایین، جلو و عقب و یا برای باز و بسته شدن گریپر کنترل می‌کند.
سورس کد و فیلم کوتاهی از پروژه در زیر قرار داده شده است.

#include <lpc214x.h>  

#include <stdint.h>

 

#define SwitchPinNumber1 17 

#define SwitchPinNumber2 18

#define SwitchPinNumber3 19

#define SwitchPinNumber4 20

 

#define LedPinNumber1    28

#define LedPinNumber2    29

#define LedPinNumber3    30

#define LedPinNumber4    31

 

#define AD04 (1<<18) //Select AD0.4 function for P0.25

#define AD01 (1<<24) //Select AD0.1 function for P0.28

#define AD02 (1<<26) //Select AD0.2 function for P0.29

#define AD03 (1<<28) //Select AD0.3 function for P0.30

 

#define SEL_AD04 (1<<4) //Select ADC channel 4

#define SEL_AD01 (1<<1) //Select ADC channel 1

#define SEL_AD02 (1<<2) //Select ADC channel 2

#define SEL_AD03 (1<<3) //Select ADC channel 3

 

#define CLKDIV (15-1)    // 4Mhz ADC clock (ADC_CLOCK=PCLK/CLKDIV) where "CLKDIV-1" is actually used , in our case PCLK=60mhz 

#define BURST_MODE_OFF (0<<16)           // 1 for on and 0 for off

#define PowerUP (1<<21)

#define START_NOW ((0<<26)|(0<<25)|(1<<24))   //001 for starting the conversion immediately

#define ADC_DONE (1UL<<31)

#define VREF 3.3                            //Reference Voltage at VREF Pin

 

volatile int result1=0;

volatile int result2=0;

volatile int result3=0;

volatile int result4=0;

 

volatile int convert1=0;

volatile int convert2=0;

volatile int convert3=0;

volatile int convert4=0;

 

volatile unsigned int  switchStatus1;

volatile unsigned int  switchStatus2;

volatile unsigned int  switchStatus3;

volatile unsigned int  switchStatus4;

 

long map(long x, long in_min, long in_max, long out_min, long out_max)  // Map function to convert range

{

  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;

}

 

void delay_ms(uint16_t j)      /* loop to generate 1 milisecond delay with Cclk = 60MHz */

{

    uint16_t x,i;

               

                for(i=0;i<j;i++)

                {

    for(x=0; x<6000; x++);   

                }

}

 

int main()

{

               

    PINSEL0 = 0x000A800A;   // Configure P0.1,P0.7,P0.8 as PWM3,PWM2,PWM4 pins

    PINSEL2 = 0x00000000;   //Configure the PORT1 Pins as GPIO;

   PINSEL1 |= AD04 | AD01 | AD02 | AD03 | (1<<10); // Configure P0.25,P0.28,P0.29,P0.30 as ADC0.4,   ADC0.1, ADC0.2, ADC0.3 Pins & P0.21 as PWM5

   IODIR1 = ((0<<17)|(0<<18)|(0<<19)|(0<<20)|(1<<28)|(1<<29)|(1<<30)|(1<<31)); //Configure LED pin as output and Switch Pin as input

    unsigned long AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | PowerUP; //Setting up ADC Mode

     PWMTCR = 0x02;          // Reset and disable counter for PWM

     PWMPR =  0x1D;          // Prescale Register value

     PWMMR0 = 20000;         // Time period of PWM wave, 20msec

     PWMMR4 = 0;                          // Initial values of PWM wave 0 msec

     PWMMR2 = 0;

     PWMMR3 = 0;

     PWMMR5 = 0;

     PWMMCR = 0x00000002;           // Reset on MR0 match

     PWMLER = 0x7C;                 // Latch enable for PWM2,PWM4,PWM4 and PWM5

     PWMPCR = 0x7C00;         // Enable PWM2,PWM4,PWM4 and PWM5, single edge controlled PWM

     PWMTCR = 0x09;                 // Enable PWM and counter              

               

   

while(1)

    {

      

       switchStatus1 = (IOPIN1>>SwitchPinNumber1) & 0x01 ;  // Read the switch status

       switchStatus2 = (IOPIN1>>SwitchPinNumber2) & 0x01 ;  // Read the switch status

       switchStatus3 = (IOPIN1>>SwitchPinNumber3) & 0x01 ;  // Read the switch status

       switchStatus4 = (IOPIN1>>SwitchPinNumber4) & 0x01 ;  // Read the switch status

     

if(switchStatus1 == 1)                      //Turn ON/OFF LEDs depending on switch status and start ADC conversion

        { 

                       IOPIN1 = (1<<LedPinNumber1);                  //Make LED1 HIGH

                       AD0CR =  AD0CR_setup | SEL_AD01;         //Setup ADC for channel 1

                       AD0CR |= START_NOW;                               //Start new Conversion at ADC1

                                                                                 

                       while( (AD0DR1 & ADC_DONE) == 0 )        //Check for ADC conversion

                  {

                             convert1 = (AD0DR1>>6) & 0x3ff;         //Get ADC value

                              result1 = map(convert1,0,1023,0,2450);  //Convert ADC values in terms of dutycyle for PWM

                              PWMMR5 = result1;                               //Set Duty Cylce value to PWM5

                              PWMLER = 0x20;                          //Enable PWM5

                               delay_ms(2);

                 }

        }

      else

         {

         IOPIN1 = (0<<LedPinNumber1);             //Set LED1 LOW

         }     

 

if(switchStatus2 == 1)                      //Turn ON/OFF LEDs depending on switch status and start ADC conversion

       { 

                 IOPIN1 = (1<<LedPinNumber2);             //Make LED2 HIGH

                 AD0CR =  AD0CR_setup | SEL_AD02;         //Setup ADC for channel 2

                 AD0CR |= START_NOW;                      //Start new Conversion at ADC2

                               

while( (AD0DR2 & ADC_DONE) == 0 )        //Check for ADC conversion

        {

                     convert2 = (AD0DR2>>6) & 0x3ff;        //Get ADC value

                      result2 = map(convert2,0,1023,0,2450); //Convert ADC values in terms of dutycyle for PWM

                      PWMMR4 = result2;                      //Set Duty Cylce value to PWM4

                      PWMLER = 0x10;                         //Enable PWM4

                      delay_ms(2);

         }

   }  else

            {

                      IOPIN1 = (0<<LedPinNumber2);              //Set LED2 LOW

            }     

                                                 

if(switchStatus3 == 1)                       //Turn ON/OFF LEDs depending on switch status and start ADC conversion

        { 

                     IOPIN1 = (1<<LedPinNumber3);      
		     //Set LED3 HIGH 
		     AD0CR =  AD0CR_setup | SEL_AD03;  
		    //Setup ADC for channel 3                                                                                                                          

                     AD0CR |= START_NOW;                       //Start new Conversion at ADC3

                     while( (AD0DR3 & ADC_DONE) == 0 )         //Check for ADC conversion

                         {

                           convert3 = (AD0DR3>>6) & 0x3ff;         //Get ADC value

                           result3 = map(convert3,0,1023,0,2450);  //Convert ADC values in terms of dutycyle for PWM

                           PWMMR3 = result3;                                 //Set Duty Cylce value to PWM3

                           PWMLER = 0x08;                          //Enable PWM3

                            delay_ms(2);

                              }

     } else

       {

         IOPIN1 = (0<<LedPinNumber3);              //Set LED4 LOW

       }     

 if(switchStatus4 == 1)                      //Turn ON/OFF LEDs depending on switch status and start ADC conversion

       { 

                           IOPIN1 = (1<<LedPinNumber4);              //Set LED4 HIGH

                           AD0CR =  AD0CR_setup | SEL_AD04;          //Setup ADC for channel 4

                           AD0CR |= START_NOW;                       //Start new Conversion at ADC4

                          while( (AD0DR4 & ADC_DONE) == 0 )         //Check for ADC conversion

                             {

                            convert4 = (AD0DR4>>6) & 0x3ff;           //Get ADC value

                            result4 = map(convert4,0,1023,0,2450);    //Convert ADC values in terms of dutycyle for PWM

                             PWMMR2 = result4;                         //Set Duty Cylce value to PWM  
                                                        PWMLER = 0x04;                            //Enable PWM2

                             delay_ms(2);

                        }

        } else

                        {

                                IOPIN1 = (0<<LedPinNumber4);          //Set LED4 LOW

                        }     

         }

      }

Video