Skocz do zawartości

[Dla początkujących] Przepis na robota - w pełni programowalny Line Follower


Nawyk

Pomocna odpowiedź

Witam

Napisałem sobie program w c .

Gdy odpale robota włącza się lewe koło.

Gdy zakryje mu czujnik lewy, włącza się prawe koło - tak ma być.

Nie potrafie tego zdiagnozować z prawym czujnikiem, ponieważ prawe się cały czas obraca i jak zakryje lewy czujnik to koło dalej się obraca..

Problem jest w tym, że gdy zakryje mu czujnik lewy i prawy to dopiero wtedy zaczynają działać dwa koła...

Czy moglibyście zerknąć na kod i podpowiedzieć gdzie robie błąd?




/*
* Line Follower.c
*
* Created: 2016-05-17 14:24:31
* Author : Admin
*/

#include <avr/io.h>

typedef struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} _io_reg;

#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
#define PWM_lewy OCR1A
#define PWM_prawy OCR1B
#define EnPWMb REGISTER_BIT(PORTB,2)
#define EnPWMa REGISTER_BIT(PORTB,1)
#define Silnik_prawy_a REGISTER_BIT(PORTD,0)
#define Silnik_prawy_b REGISTER_BIT(PORTD,1)
#define Silnik_lewy_a REGISTER_BIT(PORTD,2)
#define Silnik_lewy_b REGISTER_BIT(PORTD,3)
#define Dioda REGISTER_BIT(PORTD,6)


const uint8_t Granica=200;

volatile uint8_t czujnik_srodkowy;
volatile uint8_t czujnik_prawy;
volatile uint8_t czujnik_lewy;
unsigned W;

int read_adc(uint8_t numer)
{
ADMUX &= 0xf0;
ADMUX |= numer;
ADCSRA|=(1<<ADSC);
while(!(ADCSRA & (1<<ADIF)));
ADCSRA &= ~((1<<ADSC)|(1<<ADIF));
return ADCW;
}
void wczytaj_stany()
{
W=read_adc(3);
czujnik_prawy=W;
W=read_adc(4);
czujnik_srodkowy=W;
W=read_adc(5);
czujnik_lewy=W;
}
int main(void)
{
//PWM
TCCR1A|=(1<<WGM10);
TCCR1B|=(1<<WGM12);
TCCR1A|=(1<<COM1A1)|(1<<COM1B1);
TCCR1B|=(1<<CS10);
TCCR1B|=(1<<CS12);
//
ADMUX|=(1<<REFS0);
ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);


Dioda=1;
Silnik_lewy_a=1;
Silnik_lewy_b=0;//JAZDA W PRZOD
Silnik_prawy_a=1;
Silnik_prawy_b=0;//JAZDA W PRZOD
DDRD=0xff; //wyjscie portD
DDRB=0xff; //wyjscie portB

while (1)
	{
		wczytaj_stany();
		if (czujnik_srodkowy>Granica) {
			PWM_lewy=255;
			PWM_prawy=255;
		}
		else if (czujnik_lewy>Granica){
			PWM_lewy=255;
			PWM_prawy=0;
		}
		else if (czujnik_prawy>Granica){
			PWM_lewy=0;
			PWM_prawy=255;
		}
		else
		{
			PWM_lewy=255;
			PWM_prawy=255;
		}


	}
}



Dzięki

@@@@@@@@@@edit

Już wiem gdzie miałem błąd. W definicji do preprocesora... Gotowy kod wyżej

Już niby wszystko działa ale nadal mam problem gdy najade środkowym czujnikiem na linie to działa tlyko kolo lewe a prawe stoji.

Proszę o ewentualne podpowiedzi co tu jest źle. Dzięki

Link do komentarza
Share on other sites

konop93, sprawdziłeś, czy granica jest odpowiednia? Zrób prosty warunek, który będzie uruchamiał diodę tylko, gdy czujnik znajdzie się nad czarną linią. Jeśli koła się kręcą, gdy zakryjesz skrajne czujniki, to wygląda na to, że Twoje odczyty są zanegowane - czyt. działają poprawnie dla czarnego tła i białej linii.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Wykonałem warunek z diodą i czujniki działają.

A jak sprawdzić Granice?

Ogólnie to przez ten czas przesiedziałem nad programem i według mnie problem będzie w konfiguracji ADC.

Obecny kod:

/*
* Line Follower.c
*
* Created: 2016-05-17 14:24:31
* Author : Admin
*/

#include <avr/io.h>
#include <util/delay.h>

#define PWM_lewy OCR1A    	//EN1,2
#define PWM_prawy OCR1B		//EN3,4
//#define EnPWMP (1<<PB2)
//#define EnPWML (1<<PB1)
#define Silnik_prawy_a PORTD|=(1<<PD1)//(1<<PD0) //input4
#define Silnik_prawy_b PORTD&=~(0<<PD0) //input3
#define Silnik_lewy_a PORTD|=(1<<PD3)//(1<<PD3)  //input1
#define Silnik_lewy_b PORTD&=~(0<<PD2)//(1<<PD2)  //input2
#define Dioda PORTD|=(1<<PD6)

const uint8_t Granica=50;

volatile uint8_t czujnik_srodkowy;
volatile uint8_t czujnik_prawy;
volatile uint8_t czujnik_lewy;
unsigned int W;

int read_adc(uint8_t numer)
{
   //ADMUX &= 0xf0;
   ADMUX |= numer;
   ADCSRA|=(1<<ADSC); //ADC start conversion

   while(ADCSRA & (1<<ADIF)); //flaga przerwania od kontrolera
   ADCSRA &= ~((1<<ADSC)|(1<<ADIF));
   return ADCW;
}
void wczytaj_stany()
{
   W=read_adc(3);
   W=read_adc(3);
   //_delay_ms(500);
   czujnik_prawy=W;

   W=read_adc(4);
   W=read_adc(4);
   //_delay_ms(500);
   czujnik_srodkowy=W;

   W=read_adc(5);
   W=read_adc(5);
   //_delay_ms(500);
   czujnik_lewy=W;
}
int main(void)
{
   //KONFIGURACJA PWM
   TCCR1A|=(1<<WGM10);
   TCCR1B|=(1<<WGM12);
   TCCR1A|=(1<<COM1A1)|(1<<COM1B1);
   TCCR1B|=(1<<CS10);
   TCCR1B|=(1<<CS12);
   //adc
  ADMUX|=(1<<REFS0); 
   ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 


   Dioda;
   DDRD=0xff; //wyjscie portD
   DDRB=0xff; //wyjscie portB

   Silnik_lewy_a;
   Silnik_prawy_a;


   while (1)
       {
           wczytaj_stany();

           if (czujnik_srodkowy>Granica) {

               PWM_lewy=255;
               PWM_prawy=255;

           }
           else if (czujnik_lewy>Granica){
               PWM_lewy=0;
               PWM_prawy=255;

           }
           else if (czujnik_prawy>Granica){
               PWM_lewy=255;
               PWM_prawy=0;

           }
           else
           {
               PWM_lewy=255;
               PWM_prawy=255;
           }
       }
}


Czy mógłbyś rzucić fachowym okiem na funkcje odpowiedzialną za konfiguracje ADC?

Dzięki

@@@@EDIT

Efekt kodu jest taki, że jeździ jak mu się podoba, albo jest za czuły, albo zle skonfigurowany... nie mam pojecia..

Link do komentarza
Share on other sites

Spróbuj ustawić granicę na start około 500-800 🙂

A i dobrze jest ustawić PWM na około połowę, czyli np 122, a potem zmieniać i patrzyć czy wszystko działa jak należy 🙂

jak dam granice na większą np 250 to działa tylko koło lewe... rzadko kiedy się włączy prawe...

nie mam pojęcia co już tam moge mieć źle....

To mój obecny kod:



/*
* Line Follower.c
*
* Created: 2016-05-17 14:24:31
* Author : Admin
*/

#include <avr/io.h>
#include <util/delay.h>
//#define F_CPU 100000L
#define PWM_lewy OCR1A    	//EN1,2
#define PWM_prawy OCR1B		//EN3,4
//#define EnPWMP (1<<PB2)
//#define EnPWML (1<<PB1)
#define Silnik_prawy_a PORTD|=(1<<PD1)//(1<<PD0) //input4
#define Silnik_prawy_b PORTD&=~(0<<PD0) //input3
#define Silnik_lewy_a PORTD|=(1<<PD3)//(1<<PD3)  //input1
#define Silnik_lewy_b PORTD&=~(0<<PD2)//(1<<PD2)  //input2
#define Dioda PORTD|=(1<<PD6)

const uint8_t Granica=50;

volatile uint8_t czujnik_srodkowy;
volatile uint8_t czujnik_prawy;
volatile uint8_t czujnik_lewy;
int W;

int read_adc(uint8_t numer)
{
   ADMUX &= 0xf0;
   ADMUX|=(0<<REFS1)|(1<<REFS0);
   //ADCSRA=(1<<ADEN)|(1<<ADPS2)|(ADPS1)|(ADPS0);
   //ADMUX |= numer;
   if (numer==5){
   	ADMUX|=(1<<MUX2)|(1<<MUX0);
   }
   if (numer==4){
   	ADMUX|=(1<<MUX2);
   }
   if (numer==3){
   	ADMUX|=(1<<MUX0)|(1<<MUX1);
   }


   ADCSRA|=(1<<ADSC)|(1<<ADFR);
   while(!(ADCSRA & (1<<ADIF))); //PETLA TRWA DOPOKI ADSC=1
   ADCSRA &= ~((1<<ADSC)|(1<<ADIF));
   return ADCW;

}
void wczytaj_stany()
{
   W=read_adc(3);
   W=read_adc(3);
   czujnik_prawy=W;

   W=read_adc(4);
   W=read_adc(4);
   czujnik_srodkowy=W;

   W=read_adc(5);
   W=read_adc(5);
   czujnik_lewy=W;
}
int main(void)
{
   //KONFIGURACJA PWM
   TCCR1A|=(1<<WGM10);
   TCCR1B|=(1<<WGM12);
   TCCR1A|=(1<<COM1A1)|(1<<COM1B1);
   TCCR1B|=(1<<CS10);
   TCCR1B|=(1<<CS12);
   //    //ADC start conversion
   ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);



   Dioda;
   DDRD=0xff; //wyjscie portD
   DDRB=0xff; //wyjscie portB

   Silnik_lewy_a;
   Silnik_prawy_a;


   while (1)
       {
           wczytaj_stany();

           if (czujnik_srodkowy>Granica) {

               PWM_lewy=255;
               PWM_prawy=255;

           }
           else if (czujnik_lewy>Granica){
               PWM_lewy=0;
               PWM_prawy=255;

           }
           else if (czujnik_prawy>Granica){
               PWM_lewy=255;
               PWM_prawy=0;

           }
           else
           {
               PWM_lewy=255;
               PWM_prawy=0;
           }
       }
}

Na tym kodzie działa jak sie mu podoba, gry zakryje mu czujnik lewy i środkowy to przeważnie włącza się koło prawe, a powinno lewe. Lewe tylko włączy się w jednym położeniu zakrycia czujnika.

Gdy zakryje mu wszystkie trzy czujniki, to działa raz koło prawe a raz lewe, jak mu się spodoba tak zrobi- a powinny się oba koła wtedy kręcić.

Z tego co zaobserwowałem to dobrze działa na zakrytym czujniku prawym i środkowym-rusza prawym kołem cały czas.

Obstawiam na funkcje wczytaj_stany lub read_adc. Coś z nimi musi być nie tak, nie wiem w czym juz szukać problemu... Już powoli trace siły na ten program.

Gdy wgram program z tego tutaj kursu co udostępnia autor- to wszystko działa jak należy...

Więc pod względem podłączenia jest wszystko git.

Proszę o pomoc 🙂

@@@@@@@@@@@@@@@@@@@@@@@@@@@

Udało się, robot działa. Jest wszystko okej. Tylko jedno co mnie martwi to nie jest na tyle szybki zeby kazdy zakręt pokonać, znacie jakieś sposoby na optymalizacje? Co wplywa na optymalizacje? Preskaler, F_cpu? tak jakby czujniki za wolno zczytywały

Link do komentarza
Share on other sites

Udało się, robot działa. Jest wszystko okej.

Napisz może, co pomogło - zapewne przyda się to również innym konstruktorom w przyszłości.

Tylko jedno co mnie martwi to nie jest na tyle szybki zeby kazdy zakręt pokonać, znacie jakieś sposoby na optymalizacje? Co wplywa na optymalizacje? Preskaler, F_cpu? tak jakby czujniki za wolno zczytywały

Nie ma żadnych szans, że procesor lub odczyty są zbyt wolne. Prędzej algorytm sterujący robotem nie działa tak jak powinien. Ustaw sobie np. jakąś diodę, która będzie zmieniała stan przy każdym odczycie - zobaczysz wtedy, czy są one dokonywane szybko.

Jeśli chodzi o sprawdzenie granicy, to najlepiej będzie uruchomić UART i wysyłać informacje tekstowo do komputera.

Link do komentarza
Share on other sites

wojownikkarate, nie tam nie możesz wlutować zasilania, ponieważ cały prąd popłynąłby wtedy przez diodę, a to by doprowadziło wyłącznie do jej spalenia. Dlaczego nie możesz podłączyć zasilania w tych miejscach, które doradzał autor poradnika?

Link do komentarza
Share on other sites

Witam 🙂

Korzystając ze świąt i czasu wolnego od szkoły/pracy popełniłem prostego Line Follower'a, bazując na tym właśnie artykule. Trochę pozmieniałem w stosunku do wzoru przedstawionego w temacie, jako mózg całej operacji wykorzystałem klona Arduino Pro Mini (5V 16Mhz), a zamiast serw - silniki z przekładnią i kółkami od chińczyka. Arduino robi tutaj jako shield do płytki z mostkiem L293D, którą zaprojektowałem w Eagle i wykonałem termotransferem. Druga płytka z trzema czujnikami CNY70 również została wykonana tą samą metodą.

Po kilku godzinach kombinowania z mocą silników, dobraniem odpowiedniej wartości "granicy", udało się w końcu w miarę go wysterować, chociaż do ideału (czyt. wyżyn moich możliwości) sporo mu brakuje. Ale jak na pierwszy LF jestem zadowolony, mimo iż znalazłem już pierwszy poważny błąd konstrukcji. Rozmieściłem czujniki CNY70 zbyt daleko od siebie przez co robot praktycznie nie ma możliwości zauważenia linii jednocześnie w środkowym i którymś z zewnętrznych czujników, co przekłada się na straszną sinusoidę 🙂

Zresztą zobaczcie sami:

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.