Skocz do zawartości

Line Followe - problem z programem


programek

Pomocna odpowiedź

Witam wszystkich 😉

Jest to mój pierwszy post na tym forum.

Od jakiegoś czasu próbuje zaprogramować robota ( line follower )

Tu jest schemat i pcb:

Napisałem taki program:

main.c

/*
* main.c
*
*  Created on: 30 sty 2015
*      Author: Dominik
*/


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

#include "LCD/lcd44780.h"
#include "ADC/adc.h"

#define IN1 (1<<PC6)
#define IN2 (1<<PC7)
#define IN3 (1<<PC5)
#define IN4 (1<<PC4)

#define MUX_A (1<<PA1)
#define MUX_B (1<<PA0)

#define SET_A PORTA |= MUX_A
#define CLR_A PORTA &= ~ MUX_A;

#define SET_B PORTA |= MUX_B
#define CLR_B PORTA &= ~ MUX_B;

#define MUX_X (1<<PA3)
#define MUX_Y (1<<PA2)

//#define KEY (1<<PC3)
#define linia 850

void silnik_L ( uint8_t kierunek, uint8_t predkosc );
void silnik_R ( uint8_t kierunek, uint8_t predkosc );

void pomiar_czujnik ( uint8_t czujnik );
void napiecie_lipol ( void );

uint16_t wynik=0;
uint8_t predkosc = 45;

int main(void) {

//	PORTC |= KEY;  // podciągamy klawisz do VCC

DDRC |= IN1| IN2 | IN3 | IN4;  // wyjscia do sterowania silnikami
DDRD |= (1<<PD4) | (1<<PD5);  // wyjscia PWM

DDRA |= MUX_A | MUX_B;  // wejscia adresowe ( multiplekser ) - jako wyjscia


lcd_init();  // inicjalizaja lcd
lcd_cls();

lcd_str("start...");
_delay_ms(500);

// inicjalizacja ADC
ADCSRA |= (1<<ADEN); // włącz ADC
ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // preskaler = 128
ADMUX |= REF_VCC;	// ustawiamy wewn. źr odn. VCC


   // ustawienia TIMER1 w Fast PWM
   TCCR1A |= (1<<WGM10)|(1<<WGM11);                // Fast PWM 10-bitowy
   TCCR1B |= (1<<WGM12);                   // Fast PWM 10-bitowy
   TCCR1A |= (1<<COM1B1)|(1<<COM1A1);	 		// OC1A,OC1B  are cleared on TOP
   TCCR1B |= (1<<CS10);   				// preskaler = 1


accu1_vol.ref_adc = 780;	// zmierzona wartość ADC  ( 7,42 V )
accu1_vol.ref_v = 742;		// wartość mierzonego napięcia  ( 7,42 V )

napiecie_lipol();     // sprawdzanie napiecia akumulatora

_delay_ms ( 2000 );
lcd_cls();

uint8_t zmienna;
uint8_t wartosc;
float aktualna_pozycja;
float roznica = 0;

   while(1)
   {

   	zmienna = 0;
   	wartosc = 0;
   	aktualna_pozycja=0;
   	roznica=0;

   	for( uint8_t i = 1; i <10; i++ )
   	{
   		pomiar_czujnik(i);
   		if ( (linia-100) < wynik && wynik < (linia + 100) )
   		{
   			zmienna++;
   			wartosc += i;
   		}
   	}


   	aktualna_pozycja = wartosc / zmienna;
   	if(aktualna_pozycja>20)aktualna_pozycja=0; // gdy wsszystkie czujniki sa nad biala
   	roznica = (4.5 - aktualna_pozycja) * 12;       // powierzchnia to zmienna aktualna poz. 
                                                                            //ma wartosc 255 wiec ja zeruje
   	if(aktualna_pozycja==0) roznica = 0;

       silnik_L(0,predkosc-roznica);
       silnik_R(0,predkosc+roznica);

   }
}


/*
*  przod => kierunek = 0
*  tyl => kierunek = 1
*
*  predkosc w %
*/
void silnik_L ( uint8_t kierunek, uint8_t predkosc )
{
if ( kierunek == 0 )
{
	PORTC |= IN3;
	PORTC &= ~IN4;
}
else if ( kierunek == 1 )
{
	PORTC |= IN4;
	PORTC &= ~IN3;
}

OCR1A = (1023 / 100) * predkosc;
}

void silnik_R ( uint8_t kierunek, uint8_t predkosc )
{
if ( kierunek == 0 )
{
	PORTC |= IN2;
	PORTC &= ~IN1;
}
else if ( kierunek == 1 )
{
	PORTC |= IN1;
	PORTC &= ~IN2;
}

OCR1B = (1023 / 100) * predkosc;
}

void pomiar_czujnik ( uint8_t czujnik )
{
switch ( czujnik )
{
	case 1: CLR_A; SET_B; break;  //
	case 2: CLR_A; CLR_B; break;  //
	case 3: SET_A; SET_B; break;  //  Y
	case 4: SET_A; CLR_B; break;  //

	case 5: CLR_A; SET_B; break;  //
	case 6: SET_A; CLR_B; break;  //  X
	case 7: CLR_A; CLR_B; break;  //
	case 8: SET_A; SET_B; break;  //
}

_delay_ms(1);

wynik=0;

if ( czujnik > 0 && czujnik < 5 ) wynik = pomiar( PA2 ); // dokonujemy pomiaru na PA2
if ( czujnik > 4 && czujnik < 9 ) wynik = pomiar( PA3 ); // dokonujemy pomiaru na PA3

}

void napiecie_lipol ( void )
{
uint16_t wynik=0;

lcd_locate(0,0);
lcd_str("Napiecie");

wynik = pomiar( PA7 );		// dokonujemy pomiaru na kanale PA7
get_vol( wynik, &accu1_vol );	// zamiana ADC na napięcie

lcd_locate(1,1);

lcd_str( accu1_vol.v1 );	// jednostki i dziesiątki zmierzonego napięcia
lcd_str( "." );
lcd_str( accu1_vol.v2 );	// część ułamkowa zmierzonego napięcia
lcd_str( " V       ");
}

adc.c

/*
* adc.c
*
*  Created on: 9 lut 2015
*      Author: Dominik
*/


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

#include "adc.h"

uint16_t min=1024, max, diff;

// pomiar napięcia
uint16_t pomiar( uint8_t kanal ) {

ADMUX = (ADMUX & 0b11111000) | kanal;

ADCSRA |= (1<<ADSC);  // start konwersji

while( ADCSRA & (1<<ADSC) );

return ADCW;
}


// zamiana ADC na napięcie
void get_vol( uint16_t adc, TVOL * voltage ) {


voltage->adc_mid = adc;

uint16_t wynik = ( adc * (uint32_t)voltage->ref_v ) / voltage->ref_adc;

div_t divmod = div(wynik, 100);
itoa( divmod.quot, voltage->v1, 10 );
itoa( divmod.rem, voltage->v2, 10);

if( divmod.rem < 10 ) {
	voltage->v2[0]='0';
	voltage->v2[1]=divmod.rem+'0';
}

voltage->v1[2]=0;
voltage->v2[2]=0;
}

adc.h

/*
* adc.h
*
*  Created on: 9 lut 2015
*      Author: Dominik
*/

#ifndef ADC_ADC_H_
#define ADC_ADC_H_

// definicje bitów odpowiedzialnych za wybór źródła odniesienia
#define REF_256 (1<<REFS1)|(1<<REFS0)
#define REF_VCC (1<<REFS0)

// typ strukturalny na potrzeby przeliczania napięć z ADC do stringów
// v1 - część przed przecinkiem
// v2 - część po przecinku
typedef struct {
uint16_t adc_mid;	// uśredniona wartość ADC
uint16_t ref_adc;	// środkowy zakres wartości ADC odpowiadającej zmierzonemu niżej napięciu
uint16_t ref_v;		// środkowy zakres napięcia * 100 (czyli np dla 6,5V ---> 650)
char v1[3];
char v2[3];
} TVOL;

TVOL accu1_vol;

uint16_t pomiar( uint8_t kanal );
void get_vol( uint16_t adc, TVOL * voltage );

#endif /* ADC_ADC_H_ */

Wgrałem kod do robota, ustawiłem na trasie. Robot przejeżdża 1 lub 3/4 okrążenia :/

Nie wiem czy za wolno dokonje pomiarów, czy za słabo reaguje na moment gdy robot zaczyna zjeżdżać z trasy.

Proszę o pomoc....

Tak jak pisałem, siedzę już kilka dni nad kodem i nic mi nie wychodzi.

Tu jest filmik jak to działa:

https://www.youtube.com/watch?v=YD71L31Z6So&feature=youtu.be

Z góry dzięki za pomoc 😉

Link do komentarza
Share on other sites

Dwie moje uwagi:

1. Mała...

W pomiar_czujnik masz delay_ms(1), co powoduje, że automatycznie tracisz kilka ms. Postaraj się to zoptyamlizować chociażby używając delay_us(500)... dodatkowo w pętli głównej mierzysz od i=1 do i<10... czyli 1,2,3,4,5,6,7,8,9... a masz 8 czujników?

Zmniejszając delay zmniejszysz czas wykonywania każdego cyklu i tym samym zwiększy się prędkość reakcji robota na zmianę kierunku linii.

2. Duża

Twoja główna pętla:

while(1)
   {

       zmienna = 0;
       wartosc = 0;
       aktualna_pozycja=0;
       roznica=0;

       for( uint8_t i = 1; i <10; i++ )
       {
           pomiar_czujnik(i);
           if ( (linia-100) < wynik && wynik < (linia + 100) )
           {
               zmienna++;
               wartosc += i;
           }
       }


       aktualna_pozycja = wartosc / zmienna;
       if(aktualna_pozycja>20)aktualna_pozycja=0; // gdy wsszystkie czujniki sa nad biala
       roznica = (4.5 - aktualna_pozycja) * 12;       // powierzchnia to zmienna aktualna poz.
                                                                            //ma wartosc 255 wiec ja zeruje
       if(aktualna_pozycja==0) roznica = 0;

       silnik_L(0,predkosc-roznica);
       silnik_R(0,predkosc+roznica);

   } 

Powoduje, że jak nie widzisz linii to jedziesz prosto.

Jak nie ma linii (zmienna = 0) powinieneś zachować kierunek jazdy (czyli jak ostatnio skręcaliśmy w prawo to nadal tam skręcamy, bo tam uciekła linia).

Najprościej to zrobić zmieniając jedną linię:

aktualna_pozycja = wartosc / zmienna;

na

if (zmienna>0) aktualna_pozycja = wartosc / zmienna;
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Czesc, gratulacje konstrukcji, wazne, ze wszystkie peryferia Ci dzialaja. Co do zachowania Twojego robota, moim zdaniem problem lezy w przestrzelaniu zakretow. Chodzi dokladnie to, ze robot zachowuje sie przewidywalnie, pod warunkiem, ze nie wylecial czujnikami poza linie(zaden czujnik nie widzi lini). Dlatego powinines dodac do kodu, zapamietywanie, po ktorej stronie znajdowal sie robot po wyleceniu z lini.

Tutaj tak naprawde jest problem, ktory pojawil sie juz w fazie projektowania. Czujniki masz rozmieszczone w formie linijki. Zatem jedyna droga do poprawnego odczytu ostatnio przestrzelonego zakretu, to zapamietanie skrajnych czujnikow. W swoim MacLinerze2.0 mialem ten sam problem. Pomysly mialem trzy:

*implementujac regulator PD, mamy informacje w postaci zmiennej o nazwie np. "Uchyb"- czyli przechowuje tam wartosc, ktora jest odlegloscia od czujnika srodkowego(Uchyb=0-aktulana_pozycja), czujniki mialy wartosc od -9 do +9. Kiedy czujniki znajdowaly sie poza linia(robot przestrzelil zakret), to sprawdzalem jaka byla wartosc uchybu przed przestrzeleniem. Jesli ujemna skrec w lewo, jesli dodatnia to w prawo, jesli blad rowny byl wartosci zero, to oznaczalo, ze mamy przerwe w trasie(jedna z przeszkod w LF z przeszkodami). W taki sposob robot calkiem dobrze robot sobie radzil. Niestety byly takie ulozenia robota/trasy, ze blad wydzodzil 0, mimo, ze byl zakret i robot wypadajac jechal prosto, zamiast podjac manewr powrotu na linie.

*Kolejny pomysl- zaczne sprawdzac skrajne czujniki. Polegalo na tym, ze w kazdym obiegu petli do zmiennych dawalem odpowiednia informacje o stanie czujnika lewego i prawego. Pomysl fajny i ciekawy, ale powyzej jakiejs predkosci program mi sie nie wyrabial no i klopot, byc moze klopot lezal po stronie oswietlenia.

*Tutaj mamy rozwiazanie eliminujace ten klopot w sposob hardware'owy. Zamiast bawiac sie programem, wystarczy linijke czujnikow ulozyc po okregu. Genialny pomysl! Wszystko nagle zaczyna dzialac, za kazdym razem kiedy robot wypada z trasy, ostatnim rzecza jaka robot "zobaczy" to wlasnie ktorys ze skrajnych czujnikow. Ze wzgledu, ze ja musialem dolutowac na kynar skrajne czujniki, bo plytke mialem juz zrobiona, to czasem w najgorszych momentach (finaly 😋), skrajne czujniki przestawaly dzialac 😃.

Powodzenia z robotem, daj znac co zamierzasz 😉

Wybaczcie, ale mam angielskiego linuxa 🙁, za bledy jesli sie pojawily takze przepraszam.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Ewentualnie ze swojej strony sprawdziłbym czy próg wykrywania linii jest wystarczająco 'ostry' czy stabilny. W sensie czy nie masz sytuacji takiej, że któryś z czujników jest nad linią, a robot myśli, że nie jest ze względu na błędny próg.

I taki pomysł na interpolację i sztuczne zwiększenie rozdzielczości, stosowane m. in. w 2pi lub ARJ Grabo:

1. Normalizacja odczytów ADC czujników - nie widzi linii 0, widzi linię 1024 (lub inna liczba, ważne, żeby był to odczyt z ADC, ze stanami pośrednimi). Najprościej po uruchomieniu robota obrócić się o 90* (tak, by na pewno wszystkie czujniki były poza linią), zrobić odczyty i odjąć tę wartość od normalnego pomiaru (trzeba też zrobić zabezpieczenie, żeby nie przejechać na wartości ujemne, ani większe od 1024 - 2 ify).

2. Liczenie pozycji - w zasadzie tylko średnia ważona. Otrzymamy wtedy dokładną pozycję nad linią, z rozdzielczością dużo większą, niż tylko 8 progowanych czujników - od -512 do +512.

#define SENSORS_NUMBER 8 //ilosc czujnikow

int scale[SENSORS_NUMBER]; //nie odwolujemy sie bezposrednio, HERMETYZACJA
int sensor[SENSORS_NUMBER]; //nie odwolujemy sie bezposrednio, HERMETYZACJA


/*funkcje zewnetrzne - musisz je sam napisac i zainclude'owac - dlatego extern (od external ;) )*/
extern void scaleInit(); //funkcja inicjalizująca tablicę wag konkretnymi wagami
extern int getNormalized(int channel); //funkcja zwracająca znormalizowaną (patrz post) wartość czujnika

/*funkcje w tym  pliku, tylko deklaracje w tym miejscu, zeby bylo czytelniej*/
void initScale(); //TO WYWOLAC!!!
void getSensorTab() //funkcja wypelniajaca tablice czujnikow wartosciami (nie uzywamy jej, HERMETYZACJA)
int getError();	//funkcja liczaca blad (nie uzywamy jej, HERMETYZACJA)
int getPosition(); //funkcja najpierw pobierajaca odczyty z czujnikow i liczaca pozycje (kat) nad linia (TEJ UZYWAMY)


/*definicje*/
void initScale(){ //skaluje od -512 do 512
int i;
for(i=0;i<SENSORS_NUMBER;i++){
	scale[i]=(i-(SENSORS_NUMBER/2))*1024/SENSORS_NUMBER;	
}
}
void getSensorTab(){
int i;	
for(i=0;i<SENSORS_NUMBER;i++){
	sensor[i]=getNormalized(i);
}
}

int getError(){
int i,error_up, error_down; //up - licznik, down - mianownik
for(i=0;i<SENSORS_NUMBER;i++){
	error_up+=sensor[i]*scale[i];
	error_down+=sensor[i];
}
return error_up/error_down;
}

int getPosition(){
getSensorTab();
return getError();
}

Musisz dodać swoje funkcje oznaczone jako extern. Może nie będzie to na 100% rozwiązanie Twojego problemu, ale myślę, że opcja warta zastanowienia - odpada problem progowania.

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

Jak na razie to w programie zmieniłem tylko tego delay'a, poprawiłem pętlę for i zamieniłem to:

aktualna_pozycja = wartosc / zmienna;

na to

if (zmienna>0) aktualna_pozycja = wartosc / zmienna;

Nie rozumiem tylko o co chodzi koledze booby, mógłbyś napisać trochę jaśniej? (jestem początkujący)

Zauważyłem jeszcze jedno dziwne zachowanie u robota (sorry za obrazek, ale chciałem coś na szybko namalować):

Załóżmy że czarna linia, to taśma po której jeździ robot, a zielone kropki to czujniki.

Kilka razy trafił mi się taki przypadek, że robot skrócił sb zakręt ( czyli pojechał tak jak jest zaznaczona strzałka ) i gdy dojeżdża do czarnej linii to reaguje czujnik najbardziej wysunięty na prawo, czyli lewy silnik przyśpiesza, a prawy zwalnia co skutkuje tym że robot całkowicie odbija z trasy... :/

Link do komentarza
Share on other sites

Tutaj odpowiedz na Twoje problemy:

zauwaz, ze MacLiner2.0 zareagowal podobnie do Twojego robota.

Polecam raz jeszcze przeczytac to co pisalem wyzej, zapomnialem wspomniec, iz duzo takze daje szybkosc wykonywania sie petli. to wlasnie jej czas determinuje, to co jaki dystans robot bedzie analizowal tor, ale patrzac na caloksztalt, Twoj robot jeszcze nie jest tak szybki aby to przeszkadzalo.

P.S przy okazji zachecam do lajkowania mojego fanpage'a 😉

Link do komentarza
Share on other sites

implementujac regulator PD, mamy informacje w postaci zmiennej o nazwie np. "Uchyb"- czyli przechowuje tam wartosc, ktora jest odlegloscia od czujnika srodkowego(Uchyb=0-aktulana_pozycja), czujniki mialy wartosc od -9 do +9. Kiedy czujniki znajdowaly sie poza linia(robot przestrzelil zakret), to sprawdzalem jaka byla wartosc uchybu przed przestrzeleniem. Jesli ujemna skrec w lewo, jesli dodatnia to w prawo, jesli blad rowny byl wartosci zero, to oznaczalo, ze mamy przerwe w trasie(jedna z przeszkod w LF z przeszkodami). W taki sposob robot calkiem dobrze robot sobie radzil. Niestety byly takie ulozenia robota/trasy, ze blad wydzodzil 0, mimo, ze byl zakret i robot wypadajac jechal prosto, zamiast podjac manewr powrotu na linie.

Zrobiłem tak jak napisałeś:

/*
* main.c
*
*  Created on: 30 sty 2015
*      Author: Dominik
*/


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

#include "LCD/lcd44780.h"
#include "ADC/adc.h"

#define IN1 (1<<PC6)
#define IN2 (1<<PC7)
#define IN3 (1<<PC5)
#define IN4 (1<<PC4)

#define MUX_A (1<<PA1)
#define MUX_B (1<<PA0)

#define SET_A PORTA |= MUX_A
#define CLR_A PORTA &= ~ MUX_A;

#define SET_B PORTA |= MUX_B
#define CLR_B PORTA &= ~ MUX_B;

#define MUX_X (1<<PA3)
#define MUX_Y (1<<PA2)

//#define KEY (1<<PC3)
#define linia 850

void silnik_L ( uint8_t kierunek, uint8_t predkosc );
void silnik_R ( uint8_t kierunek, uint8_t predkosc );

void pomiar_czujnik ( uint8_t czujnik );
void napiecie_lipol ( void );

uint16_t wynik=0;
uint8_t predkosc = 45;

int main(void) {

//	PORTC |= KEY;  // podciągamy klawisz do VCC

DDRC |= IN1| IN2 | IN3 | IN4;  // wyjscia do sterowania silnikami
DDRD |= (1<<PD4) | (1<<PD5);  // wyjscia PWM

DDRA |= MUX_A | MUX_B;  // wejscia adresowe ( multiplekser ) - jako wyjscia


lcd_init();  // inicjalizaja lcd
lcd_cls();

lcd_str("start...");
_delay_ms(500);

// inicjalizacja ADC
ADCSRA |= (1<<ADEN); // włącz ADC
ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // preskaler = 128
ADMUX |= REF_VCC;	// ustawiamy wewn. źr odn. VCC


   // ustawienia TIMER1 w Fast PWM
   TCCR1A |= (1<<WGM10)|(1<<WGM11);                // Fast PWM 10-bitowy
   TCCR1B |= (1<<WGM12);                   // Fast PWM 10-bitowy
   TCCR1A |= (1<<COM1B1)|(1<<COM1A1);	 		// OC1A,OC1B  are cleared on TOP
   TCCR1B |= (1<<CS10);   				// preskaler = 1


accu1_vol.ref_adc = 780;	// zmierzona wartość ADC  ( 7,4 V )
accu1_vol.ref_v = 742;		// wartość mierzonego napięcia  ( 7,4 V )

napiecie_lipol();     // sprawdzanie napiecia akumulatora

_delay_ms ( 2000 );
lcd_cls();

uint8_t zmienna;
uint8_t wartosc;

float aktualna_pozycja;
float roznica = 0;

   while(1)
   {

   	zmienna = 0;
   	wartosc = 0;
   	aktualna_pozycja=0;
   	roznica=0;

   	for( uint8_t i = 1; i <9; i++ )
   	{
   		pomiar_czujnik(i);
   		if ( (linia-100) < wynik && wynik < (linia + 100) )
   		{
   			zmienna++;
   			wartosc += i-5;
   		}
   	}


   	if (zmienna>0) // jesli linia jest pod ktoryms z czujnikow
   	{
   		aktualna_pozycja = wartosc / zmienna;
       	roznica = (0 - aktualna_pozycja) * 12;


           silnik_L(0,predkosc-roznica);
           silnik_R(0,predkosc+roznica);
   	}
   	else        // jesli robot wyjechal z trazy
   	{
   		if(aktualna_pozycja < 0)
   		{
   	        silnik_L(0,predkosc - 20);
   	        silnik_R(0,predkosc + 20);
   		}
   		if(aktualna_pozycja > 0)
   		{
   	        silnik_L(0,predkosc + 20);
   	        silnik_R(0,predkosc - 20);
   		}
   	}

   }
}


/*
*  przod => kierunek = 0
*  tyl => kierunek = 1
*
*  predkosc w %
*/
void silnik_L ( uint8_t kierunek, uint8_t predkosc )
{
if ( kierunek == 0 )
{
	PORTC |= IN3;
	PORTC &= ~IN4;
}
else if ( kierunek == 1 )
{
	PORTC |= IN4;
	PORTC &= ~IN3;
}

OCR1A = (1023 / 100) * predkosc;
}

void silnik_R ( uint8_t kierunek, uint8_t predkosc )
{
if ( kierunek == 0 )
{
	PORTC |= IN2;
	PORTC &= ~IN1;
}
else if ( kierunek == 1 )
{
	PORTC |= IN1;
	PORTC &= ~IN2;
}

OCR1B = (1023 / 100) * predkosc;
}

void pomiar_czujnik ( uint8_t czujnik )
{
switch ( czujnik )
{
	case 1: CLR_A; SET_B; break;  //
	case 2: CLR_A; CLR_B; break;  //
	case 3: SET_A; SET_B; break;  //  Y
	case 4: SET_A; CLR_B; break;  //

	case 5: CLR_A; SET_B; break;  //
	case 6: SET_A; CLR_B; break;  //  X
	case 7: CLR_A; CLR_B; break;  //
	case 8: SET_A; SET_B; break;  //
}

_delay_us(500);

wynik = 0;

if ( czujnik > 0 && czujnik < 5 ) wynik = pomiar( PA2 ); // dokonujemy pomiaru na PA2
if ( czujnik > 4 && czujnik < 9 ) wynik = pomiar( PA3 ); // dokonujemy pomiaru na PA3

}

void napiecie_lipol ( void )
{
uint16_t wynik=0;

lcd_locate(0,0);
lcd_str("Napiecie");

wynik = pomiar( PA7 );		// dokonujemy pomiaru na kanale PA7
get_vol( wynik, &accu1_vol );	// zamiana ADC na napięcie

lcd_locate(1,1);

lcd_str( accu1_vol.v1 );	// jednostki i dziesiątki zmierzonego napięcia
lcd_str( "." );
lcd_str( accu1_vol.v2 );	// część ułamkowa zmierzonego napięcia
lcd_str( " V       ");
}

Robot jeździ trochę lepiej 😃 ale nadal przy małej prędkości często zjeżdża z trasy. Co jeszcze mogę zmienić?

Filmik: LineFollower

Link do komentarza
Share on other sites

Zerknalem na Twoj kod, dodalbym jeszcze warunek:

if(aktualna_pozycja ==0)
     {
           silnik_L(0,predkosc);
           silnik_R(0,predkosc);
     } 

Jest fajny myk jak sprawdzic czy robot zapamietuje po ktorej stronie sie znajdowal. Poloz na lini robota, wlacz go, ale tak, aby caly czas miec nad nim kontrole(utrzymuj go reka 🙂). Teraz daj mu swobodnie jechac i w trakcie spychaj z lini po obu stronach, zobacz jaka jest reakacja 🙂. Jesli robot wraca za kazdym razem jest super, natomiast jezeli po "przepchnieciu go poza linie nie wraca na nia, to bedzie oznaczalo, ze problem lezy prawdopodobnie po stronie czujnikow.

Mialem podobny problem, kiedy po raz pierwszy zbudowalem detekecje lini w oparciu o wykorzystanie wewnetrznego przetwornika ADC. Okazalo sie, ze wewnetrzne rezystory podciagajace kolektory czujnikow podowodwaly problemy. Musialem zrobic nowa plytke z rezystorami zewnetrznymi, problem zaniknal 🙂.

Warto nadmienic, ze w ATmedze 8(innych takze tez) w obudowach SMD, mamy dodatkowe dwa kanaly ADC. Nalezy pamietac, ze nie sa to wejscia/wejscia cyfrowe, lecz jedynie kanal przetwornika, zatem nalezy tam bez wzgledu na wszystko dolaczyc zewnetrzny pull'up.

Jesli masz multimetr, a zakladam, ze kazdy robotyk powinien go posiadac, przelacz go na pomiar napiecia stalego i sprawdz jakie napiecia masz na wyjsciu kolektora swoich czujnikow. Problemem moze byc fakt, ze posiadasz multiplekser. Sprawdz kazdy czujnik po kolei zarowno dla czarnej, jak i dla bialej barwy. Podziel sie wynikami 🙂.

Jeszcze jedna sprawa, Widze, ze napiecie progowe lini masz ustawione na 850, odniesieniem jest wewnetrzne zrodlo =VCC, zatem po szybkich obliczeniach, wychodzi ze przy okolo 4.15v czujnik wychwytuje linie, wydaje sie to ciut przesadzone. W jaki sposob dobrales taka, a nie inna wartosc? obserwacja, czy raz "na pale" ustawiles taka wartosc i potem jej juz nie zmieniales 😃?

Na przyszlosc polecam wyprowadzic sobie zlacze od komunikacji szeregowej UART, pod ktory bedziesz mogl podlaczyc poprzez np. Bluetooth, RF, czy tez komputer swojego robota i zdalnie sprawdzac co sie dzieje we wewnatrz procesora. To naprawda znacznie ulatwia prace!

Swoja droga, super, ze pracujesz w Eclipsie, tez od ostatniego czasu postanowilem sie przerzucic na to srodowisko, z przestarzalego juz AVR Studio 4 🙂. Jak Ci sie w nim pracuje ? Korzystales wczesniej z dobrodziejstw innych programow? 🙂

Link do komentarza
Share on other sites

tego warunku:if(aktualna_pozycja ==0) nie dałem ponieważ nie planowałem przerw w trasie.

wartość adc 850 dobrałem metodą prób i błędów.

Dzisiaj rano chciałem zrobić test i wywaliłem wszystko z pętli głównej i dałem to:

    	pomiar_czujnik(1);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c1 = 1;
   	else c1 = 0;

   	pomiar_czujnik(2);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c2 = 1;
   	else c2 = 0;

   	pomiar_czujnik(3);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c3 = 1;
   	else c3 = 0;

   	pomiar_czujnik(4);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c4 = 1;
   	else c4 = 0;

   	pomiar_czujnik(5);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c5 = 1;
   	else c5 = 0;

   	pomiar_czujnik(6);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c6 = 1;
   	else c6 = 0;

   	pomiar_czujnik(7);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c7 = 1;
   	else c7 = 0;

   	pomiar_czujnik(8);
   	if ( (linia-100) < wynik && wynik < (linia + 100) ) c8 = 1;
   	else c8 = 0;

   	lcd_cls();
   	lcd_locate(0,0);

   	lcd_int(c1);
   	lcd_int(c2);
   	lcd_int(c3);
   	lcd_int(c4);
   	lcd_int(c5);
   	lcd_int(c6);
   	lcd_int(c7);
   	lcd_int(c8);

Na LCD miałem 8 cyfr ( każda od innego czujnika ). Wgrałem program do avr położyłem roota na podłodze i miałem osiem zer, następnie położyłem na lini tak że taśma była ustawiona równolegle to linijki z czujnikami. Teoretycznie powinno pojawić się osiem jedynek, ale było ich tylko 6 ( dwa środkowe czujniki tak jakby nie wykrywały linii ). Zmieniłem wartość 850 na #define linia 750 i już ładnie działało.

Na przyszlosc polecam wyprowadzic sobie zlacze od komunikacji szeregowej UART, pod ktory bedziesz mogl podlaczyc poprzez np. Bluetooth, RF, czy tez komputer swojego robota i zdalnie sprawdzac co sie dzieje we wewnatrz procesora. To naprawda znacznie ulatwia prace!

Na płytce mam złącze do UARTA ( koło gniazda KANDA ).

Swoja droga, super, ze pracujesz w Eclipsie, tez od ostatniego czasu postanowilem sie przerzucic na to srodowisko, z przestarzalego juz AVR Studio 4 🙂 . Jak Ci sie w nim pracuje ? Korzystales wczesniej z dobrodziejstw innych programow? 🙂

Jak pierwszy raz chwyciłem w ręce avr to używałem winavr, ale nie polecam.

Potem dowiedziałem się o istnieniu ECLIPSA i bardzo mi się on spodobał 😃

Jest fajny, łatwy w obsłudze i wygodnie się w nim programuje 😉

Poloz na lini robota, wlacz go, ale tak, aby caly czas miec nad nim kontrole(utrzymuj go reka 🙂 ). Teraz daj mu swobodnie jechac i w trakcie spychaj z lini po obu stronach, zobacz jaka jest reakacja 🙂 . Jesli robot wraca za kazdym razem jest super, natomiast jezeli po "przepchnieciu go poza linie nie wraca na nia, to bedzie oznaczalo, ze problem lezy prawdopodobnie po stronie czujnikow.

Wieczorem będę testował 😉

Link do komentarza
Share on other sites

programek jeżeli pomogła zmiana wartości "reagowania" na linię i miałeś z 6 jedynek 8 (przy zmianie na #define linia 750), to może warto byłoby zainteresować się autokalibracją przed przejazdem?

MacGyver jak z czasem chciałem uczyć się C, to po obejrzeniu paru godzin poradników właśnie ze środowiskiem Eclipse mogę go naprawdę polecić, sam go od dłuższego czasu używam i powiem szczerze, że był on moim pierwszym środowiskiem, w którym pisałem programy w C 🙂 Także, polecam.

Link do komentarza
Share on other sites

programek jeżeli pomogła zmiana wartości "reagowania" na linię i miałeś z 6 jedynek 8 (przy zmianie na #define linia 750), to może warto byłoby zainteresować się autokalibracją przed przejazdem?
Troche nie wiem jak się za to zabrać :/
Link do komentarza
Share on other sites

Tu możesz o tym przeczytać, choć ja robię to trochę inaczej.

Ewentualnie tutaj.

Edit: Ale z tego co widzę na filmikach, to musisz dodać takie coś, że jeżeli ostatnio linia widziana po lewej stornie robota i robot przestrzeli zakręt, to musi skręcać w lewo (jak nie ma linii pod czujnikami i zakręt widziany ostatnio po lewej) i analogicznie dla prawej strony. Jak ostatnio widziana po prawej i przestrzeli, to musi skręcać w prawo, dopóki dopóty nie znajdzie się środkowymi czujnikami na linii. Ten zabieg powinien dosyć dobrze pomóc, ponieważ teraz robot jak przestrzeli (nie ma pod sobą linii), to jedzie sobie prosto. Spróbuj wyobrazić sobie to co napisałem wyżej i przeanalizuj. Powodzenia!

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.