Thứ Năm, 29 tháng 11, 2018

Giao tiếp động cơ Servo

Giới thiệu

Động cơ Servo
Động cơ servo là một thiết bị điện được sử dụng để điều khiển chính xác góc quay. Nó được sử dụng khi cần điều khiển chính xác, như trong trường hợp điều khiển cánh tay robot.
  • Nó bao gồm một động cơ phù hợp với mạch điều khiển để điều khiển vị trí chính xác của trục động cơ.
  • Nó là một hệ thống vòng khép kín.
  • Góc quay của mô tơ servo được điều khiển bằng cách áp dụng tín hiệu PWM cho nó.
  • Bằng cách thay đổi độ rộng của tín hiệu PWM, chúng ta có thể thay đổi góc quay và hướng của động cơ.
Để biết thêm thông tin về Động cơ Servo và cách sử dụng, hãy tham khảo chủ đề Mô tơ Servo trong phần cảm biến và mô-đun.

Tạo PWM bằng PIC18F4550

Servo SG90 có thời gian chu kỳ nhiệm vụ thực tế cho -90 ° đến +90 quay khác với lý tưởng.
Tại ~ 0.6ms (chu kỳ nhiệm vụ 3%), chúng tôi nhận được vị trí trục ở -90 ° của vòng quay của nó.
Tại ~ 1.4ms (chu kỳ nhiệm vụ 7%), chúng tôi nhận được vị trí trục ở 0 ° (trung tính) của vòng quay của nó.
Tại ~ 2.4ms (chu kỳ nhiệm vụ 12%), chúng tôi nhận được vị trí trục tại + 90 ° vòng quay của nó.

Để điều khiển động cơ servo ở giữa -90 ° đến + 90 ° xoay. Chúng ta cần tạo ra dạng sóng PWM là 50Hz với chu kỳ làm việc thay đổi từ ~ 0.6ms đến ~ 2.4ms. Chúng ta có thể sử dụng chế độ PWM nhanh của PIC18F4550 sử dụng Timer1.
Để biết thêm thông tin về cách tạo PWM trong PIC18F4550 và cách sử dụng nó, hãy tham khảo PWM PIC18F4550 .

Sơ đồ giao thoa

Giao diện PIC18F4550 với Động cơ Servo
PIC18F4550 với Động cơ Servo

Thí dụ
Bây giờ hãy lập trình PIC18F4550 để tạo ra 50Hz PWM để điều khiển Động cơ Servo ở góc giữa -90 ° đến + 90 °.

Chương trình cho Servo

/* 
 * Servo control using PIC
 */

#include <pic18f4550.h>
#include <stdio.h>
#include <math.h>
#include "Configuration_header_file.h"

#define MINTHR              8000
#define RESOLUTION          488

#define InternalOsc_8MHz    8000000
#define InternalOsc_4MHz    4000000
#define InternalOsc_2MHz    2000000
#define InternalOsc_1MHz    1000000
#define InternalOsc_500KHz  500000
#define InternalOsc_250KHz  250000
#define InternalOsc_125KHz  125000
#define InternalOsc_31KHz   31000

#define Timer2Prescale_1    1
#define Timer2Prescale_4    4
#define Timer2Prescale_16   16

void PWM_Init()            /* Initialize PWM */
{
    TRISCbits.TRISC2 = 0;  /* Set CCP1 pin as output for PWM out */
    CCP1CON = 0x0C;        /* Set PWM mode */
}

int setPeriodTo(unsigned long FPWM)/* Set period */
{
    int clockSelectBits, TimerPrescaleBits;
    int TimerPrescaleValue;
    float period;
    unsigned long FOSC, _resolution = RESOLUTION;

    if (FPWM < MINTHR)    {TimerPrescaleBits = 2; TimerPrescaleValue = Timer2Prescale_16;}
    else                  {TimerPrescaleBits = 0; TimerPrescaleValue = Timer2Prescale_1;}

    if (FPWM > _resolution)               {clockSelectBits = 7; FOSC = InternalOsc_8MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 6; FOSC = InternalOsc_4MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 5; FOSC = InternalOsc_2MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 4; FOSC = InternalOsc_1MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 3; FOSC = InternalOsc_500KHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 2; FOSC = InternalOsc_250KHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 1; FOSC = InternalOsc_125KHz;}
    else                                  {clockSelectBits = 0; FOSC = InternalOsc_31KHz;}

    period = ((float)FOSC / (4.0 * (float)TimerPrescaleValue * (float)FPWM)) - 1.0;
    period = round(period);

    OSCCON = ((clockSelectBits & 0x07) << 4) | 0x02;
    PR2 = (int)period;
    T2CON = TimerPrescaleBits;
    TMR2 = 0;
    T2CONbits.TMR2ON = 1;  /* Turn ON Timer2 */
    return (int)period;
}

void SetDutyCycleTo(float Duty_cycle, int Period)
{
    int PWM10BitValue;

    PWM10BitValue = 4.0 * ((float)Period + 1.0) * (Duty_cycle/100.0);
    CCPR1L = (PWM10BitValue >> 2);
    CCP1CON = ((PWM10BitValue & 0x03) << 4) | 0x0C;
}


void delay(unsigned int val)
{
     unsigned int i,j;
        for(i=0;i<val;i++)
            for(j=0;j<10;j++);
}

int main() 
{
    int Period;
    PWM_Init();                 /* Initialize PWM */
    Period = setPeriodTo(50);   /* 50Hz PWM frequency */
    /* Note that period step size will gradually increase with PWM frequency */
    while(1)
    {
        SetDutyCycleTo(3.0, Period);    /* 3% duty cycle */
        delay(1000);
        SetDutyCycleTo(7.0, Period);    /* 7% duty cycle */
        delay(1000);
        SetDutyCycleTo(12.0, Period);    /* 12% duty cycle */
        delay(1000);
    }
}

Thí dụ
Bây giờ hãy lập trình PIC18F4550 để tạo ra 50Hz PWM để điều khiển Động cơ Servo ở góc giữa -90 ° đến + 90 ° xoay bằng núm chiết bên ngoài.
  • Ở đây chúng tôi đang sử dụng kênh ADC 0 của PIC18F4550 để đọc núm chiết bên ngoài và theo giá trị ADC, chúng tôi đang thay đổi chu kỳ nhiệm vụ của PWM.
  • Tham khảo ADC trong PIC18F4550 để biết thêm thông tin về ADC trong PIC18F4550.
Giao diện PIC18F4550 với Động cơ Servo
 PIC18F4550 với Động cơ Servo + POT

Chương trình cho Servo sử dụng POT

/* 
 * Servo control using POT with PIC
 */

#include <pic18f4550.h>
#include <stdio.h>
#include <math.h>
#include "Configuration_header_file.h"
#include "ADC_Header_File.h"

#define MINTHR              8000
#define RESOLUTION          488

#define InternalOsc_8MHz    8000000
#define InternalOsc_4MHz    4000000
#define InternalOsc_2MHz    2000000
#define InternalOsc_1MHz    1000000
#define InternalOsc_500KHz  500000
#define InternalOsc_250KHz  250000
#define InternalOsc_125KHz  125000
#define InternalOsc_31KHz   31000

#define Timer2Prescale_1    1
#define Timer2Prescale_4    4
#define Timer2Prescale_16   16

void PWM_Init()             /* Initialize PWM */
{
    TRISCbits.TRISC2 = 0;   /* Set CCP1 pin as output for PWM out */
    CCP1CON = 0x0C;         /* Set PWM mode */
}

int setPeriodTo(unsigned long FPWM)/* Set period */
{
    int clockSelectBits, TimerPrescaleBits;
    int TimerPrescaleValue;
    float period;
    unsigned long FOSC, _resolution = RESOLUTION;

    if (FPWM < MINTHR)    {TimerPrescaleBits = 2; TimerPrescaleValue = Timer2Prescale_16;}
    else                  {TimerPrescaleBits = 0; TimerPrescaleValue = Timer2Prescale_1;}

    if (FPWM > _resolution)               {clockSelectBits = 7; FOSC = InternalOsc_8MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 6; FOSC = InternalOsc_4MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 5; FOSC = InternalOsc_2MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 4; FOSC = InternalOsc_1MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 3; FOSC = InternalOsc_500KHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 2; FOSC = InternalOsc_250KHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 1; FOSC = InternalOsc_125KHz;}
    else                                  {clockSelectBits = 0; FOSC = InternalOsc_31KHz;}

    period = ((float)FOSC / (4.0 * (float)TimerPrescaleValue * (float)FPWM)) - 1.0;
    period = round(period);

    OSCCON = ((clockSelectBits & 0x07) << 4) | 0x02;
    PR2 = (int)period;
    T2CON = TimerPrescaleBits;
    TMR2 = 0;
    T2CONbits.TMR2ON = 1;  /* Turn ON Timer2 */
    return (int)period;
}

void SetDutyCycleTo(float Duty_cycle, int Period)/* Set Duty cycle for given period */
{
    int PWM10BitValue;
    
    PWM10BitValue = 4.0 * ((float)Period + 1.0) * (Duty_cycle/100.0);
    CCPR1L = (PWM10BitValue >> 2);
    CCP1CON = ((PWM10BitValue & 0x03) << 4) | 0x0C;
}

int main() 
{
    float Duty_Scale;
    int Period;
    ADC_Init();
    PWM_Init();                 /* Initialize PWM */
    Period = setPeriodTo(50);   /* 50Hz PWM frequency */
    /* Note that period step size will gradually increase with PWM frequency */
    while(1)
    {
        /* Scale Duty Cycle in between 3.0-12.0 */
        Duty_Scale = (((float)(ADC_Read(0)/4.0)*9.0)/255.0) + 3.0;
        SetDutyCycleTo(Duty_Scale, Period);
    }
}

Code

Không có nhận xét nào:

Đăng nhận xét