Общение

russian-robots@conference.jabber.ru - Чат, в котором можно поболтать об электронике, создании роботов и программировании.
Как мне зайти в чат?

 Обсуждение

Не стесняйтесь оставлять комментарии, мне интересно и важно ваше мнение!
  • Wadimka: Подскажу где взять недорого строчники, идете/едите в любую контору которая ...
  • Vladimir: Об этом датчике я тоже знаю, хотелось с чегото начать изучать МК, а не слеп ...
  • Vladimir: Спсиба
  • Евгений: Стоит поставить инфракрасный датчик движения и не городить ничего :) Литера ...
  • Vladimir: Добрый день Евгений. Это мне для дома в кладовку. При входе на двери стоит ...
  • Евгений: Фотобарьер? По подробнее расскажите.
  • Vladimir: Добрый день. Прошу вас помочь в реализации пректа фотобарер на Tiny45, со с ...
  • Евгений: С таким кодом даже http://caxapa.ru/codebook/?search=BLSH ничего не находит ...
  • Лайнтрейсер на микроконтроллере ATMEGA88

    26th Февраль 2011 | Метки: ,

    UPD: Добавлена схема и исходный код.

    Представляю вашему вниманию робота лайнтрейсера «Спиди».

    Лайнтрейсер "Спиди"

     

    Калибрую датчики линии, слева переходник USB->UART

    Характеристики:

    • Датчики линии: Аналоговые, 2 шт.
    • Микроконтроллер: ATMEGA88, тактовая частота 8Мгц, внутренний генератор.
    • Шасси: 2-х колесное с подруливающим колесом сзади
    • Двигатели: Gekko MR 20:1
    • Драйвер двигателей: LB1838
    • Питание: Li-PO аккумулятор 7.4 v 900 mAh
    • Способ отслеживания линии: Пропорционально-дифференциальный регулятор

    Перед тем как собрать этого лайнтрейсера я опробовал еще 2 конструкции шасси и 2 вида алгоритмов для отслеживания линии. Текущая конструкция шасси оказалась наиболее удачной, робот не встаёт на «дыбы», уверенно вписывается в крутые повороты. Пропорционально дифференциальный алгоритм (далее ПД) это, пожалуй, лучший алгоритм для лайнтрейсера. По сравнению с релейным или пропорциональным алгоритмом, при использовании ПД напрочь отсутствуют вихляния робота из стороны в сторону, из-за чего он быстрее проходит трассу.

    Программа

    Программа написана на Си в Code Vision AVR, исходный код программы:

    #include<mega88.h>
    #include<delay.h>
    #include<stdio.h>
    #include<math.h>
    
    #define led PORTB.1
    #define knopka PINB.2
    #define in1 PORTD.7
    #define in2 PORTB.0
    #define ena1 PORTD.6
    #define ena2 PORTD.5
    #define ir1 PORTC.3
    #define ir3 PORTC.2
    #define ft1 1
    #define ft3 0
    #define ADC_VREF_TYPE 0xE0
    #define speedr OCR0A
    #define speedl OCR0B
    #define max 255
    
    double Kp=0,Kd=0,Y;
    
    int last_error=0,error;
    void motors(int r, int l)
    {
    if(r>0){
    in1=0;
    if(r<max)
    speedr=(unsigned char)r;
    else
    speedr=max;
    }
    else if(r<0) {
    in1=1;
    if(-r<max)
    speedr=(unsigned char)-r;
    else
    speedr=max;
    } else if(r==0){
    speedr=0;
    in1=1;
    }
    //left
    if(l>0){
    in2=0;
    if(l<max)
    speedl=(unsigned char)l;
    else
    speedl=max;
    }
    else if(l<0) {
    in2=1;
    if(-l<max)
    speedl=(unsigned char)-l;
    else
    speedl=max;
    } else if(l==0){
    speedl=0;
    in2=1;
    }
    }
    
    // Read the 8 most significant bits
    // of the AD conversion result
    unsigned char read_adc(unsigned char adc_input)
    {
    ADMUX=adc_input | (ADC_VREF_TYPE &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; 0xff);
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(60);
    // Start the AD conversion
    ADCSRA|=0x40;
    // Wait for the AD conversion to complete
    while ((ADCSRA &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; 0x10)==0);
    ADCSRA|=0x10;
    return ADCH;
    }
    unsigned char s1,s2,s3;
    void getData(void)
    {
    unsigned char temp[2];
    
    //1
    
    temp[0]=read_adc(ft1);
    ir1=1;
    // delay_ms(1);
    temp[1]=read_adc(ft1);
    ir1=0;
    if(temp[1]>temp[0])
    s1=temp[1]-temp[0];
    
    //2
    
    temp[0]=read_adc(ft3);
    ir3=1;
    //delay_ms(1);
    temp[1]=read_adc(ft3);
    ir3=0;
    if(temp[1]>temp[0])
    s3=temp[1]-temp[0];
    }
    
    // USART Receiver interrupt service routine
    interrupt [USART_RXC] void usart_rx_isr(void)
    {
    char data;
    led=1;
    data=UDR0;
    switch(data)
    {
    case 'E':
    getData();
    putchar(abs(s1-s3));
    break;
    case 'L':
    putchar((unsigned char)last_error);
    break;
    case 'z':
    Kp+=0.1;
    break;
    case 'x':
    if(Kp>0.1)
    Kp-=0.1;
    else
    putchar('0');
    break;
    case 'c':
    Kd+=0.1;
    break;
    case 'v':
    if(Kd>0.1)
    Kd-=0.1;
    else
    putchar('0');
    break;
    case '1':
    getData();
    putchar(s1);
    break;
    case '3':
    getData();
    putchar(s3);
    break;
    case 'f':
    TCCR0A=0xA3;
    TCCR0B=0x04;
    motors(max,max);
    break;
    case 'b':
    TCCR0A=0xA3;
    TCCR0B=0x04;
    motors(-max,-max);
    break;
    case 'r':
    TCCR0A=0xA3;
    TCCR0B=0x04;
    motors(max,-max);
    break;
    case 'l':
    TCCR0A=0xA3;
    TCCR0B=0x04;
    motors(-max,max);
    break;
    case 's':
    motors(0,0);
    TCCR0A=0x00;
    TCCR0B=0x00;
    break;
    }
    led=0;
    }
    
    void main (void)
    {
    DDRB.2=1;
    PORTB.2=1;
    while(!knopka);
    DDRB.1=1;
    DDRB.2=0;
    PORTB.2=1;
    DDRD.6=1; //ENA1
    DDRD.5=1; //ENA2
    DDRB.0=1; //IN2
    DDRD.7=1; //IN1
    DDRC.2=1;
    DDRC.3=1;
    DDRC.5=1;
    PORTC.5=0;
    PORTC.2=0;
    PORTC.3=0;
    
    ACSR=0x80;
    ADCSRB=0x00;
    
    // ADC initialization
    // ADC Clock frequency: 1000,000 kHz
    // ADC Voltage Reference: Int., cap. on AREF
    // ADC Auto Trigger Source: None
    // Only the 8 most significant bits of
    // the AD conversion result are used
    // Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
    // ADC4: On, ADC5: On
    DIDR0=0x00;
    ADMUX=ADC_VREF_TYPE &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; 0xff;
    ADCSRA=0x83;
    
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: 31,250 kHz
    // Mode: Fast PWM top=FFh
    // OC0A output: Non-Inverted PWM
    // OC0B output: Non-Inverted PWM
    TCCR0A=0x00;
    TCCR0B=0x00;
    TCNT0=0x00;
    OCR0A=0x00;
    OCR0B=0x00;
    
    // USART initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Receiver: On
    // USART Transmitter: On
    // USART0 Mode: Asynchronous
    // USART Baud Rate: 9600
    UCSR0A=0x00;
    UCSR0B=0x98;
    UCSR0C=0x06;
    UBRR0H=0x00;
    UBRR0L=0x33;
    #asm("sei")
    
    start:
    motors(0,0);
    TCCR0A=0x00;
    TCCR0B=0x00;
    delay_ms(200);
    led=0;
    while(knopka);
    led=1;
    TCCR0A=0xA3;
    TCCR0B=0x04;
    delay_ms(3000);
    while(1)
    {
    if(!knopka)
    goto start;
    getData();
    if(s1>s3)
    error = s1-s3;
    else
    {
    error = s3-s1;
    error = error * (-1);
    }
    Y = Kp * error + Kd*(error - last_error);
    last_error = error;
    motors(max+(int)Y,max-(int)Y);
    }
    }
    

    Настройка сводится к подбору переменных Kp и Kd и MAX. Kd всегда во много раз больше Kp. Для начала можно начать с Kp=2, Kd=50, если робот вихляет, то увеличивать Kd, если все равно продолжает вихлять, то слегка убавить Kp.

    Дефайн MAX отвечает за максимальную скорость двигателей, где 255 – максимальная скорость.

    Схема

    Наконец-то появилась схема робота  :D

     

    Понравилась статья? Нажмите на любую из кнопок:

    0
    1. Саша
      12th Январь 2012 в 16:17

      Да интересный робот!!! Могли бы вы сказать сколько памяти МК занимает данная программа? Также интересно в какой программе вы рисуете схемы?

      Thumb up 0 Thumb down 0

      [Ответить]

      Евгений Reply:

      Программа занимает примерно 2 кб памяти, если убрать лишнее (лишнего там много), то размер сильно уменьшится.
      Схема нарисована в ISIS.

      [Ответить]

    :D :-) :( :o 8O :? 8) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: