Skocz do zawartości

Line Follower, zakręt 90 stopni


Granathar

Pomocna odpowiedź

W jaki sposób sprawić, by robot był w stanie pokonywać zakręty 90 stopni? Zakładam, że pasowałoby mu wrzucić coś, co sprawi, by wykonywał ostatnią znaną dyrektywę, ale nie bardzo wiem jak to zrobić na tym etapie.

Obecnie robot chodzi na tym programie (UWAGA! To są silniki BLDC!), przepraszam za to, że jest dosyć słabo czytelny:

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

#define LED_ON_0 PORTD |= _BV(0) ; 
#define LED_ON_1 PORTD |= _BV(1) ; PORTD |= _BV(5)
#define LED_ON_2 PORTD |= _BV(2) ; PORTD |= _BV(5) ; PORTD |= _BV(6) 
#define LED_ON_3 PORTD |= _BV(3) ; PORTD |= _BV(6) 
#define LED_ON_4 PORTD |= _BV(4) ; 
#define LED_OFF PORTD &= ~_BV(0) ; PORTD &= ~_BV(1); PORTD &= ~_BV(2); PORTD &= ~_BV(3); PORTD &= ~_BV(4) ; PORTD &= ~_BV(5); PORTD &= ~_BV(6) 
//int vL;
//int vP;

volatile unsigned char polozenie_wirnika_L = 1;
volatile unsigned char polozenie_wirnika_P = 1;

volatile int pomiar[5];
volatile uint8_t kanal = 0;

ISR(ADC_vect) //przerwanie od ADC
{
pomiar[kanal] = ADCH; 					// 8 starszych bitów jako wynik
++kanal; 								// przejdź do następnego kanału
if (kanal > 4) 							// jeżeli czujnik PP to przejdź do LL konwersja leci od nowa
{
kanal = 0;
}

switch (kanal) // wybór kanału do odczytu
{
	case (0): //LL - lewy skrajny
	ADMUX &= ~_BV(0);
	ADMUX &= ~_BV(1);
	ADMUX &= ~_BV(2);
	break;

	case (1): //L - lewy wewnetrzny
	ADMUX |= _BV(0);
	ADMUX &= ~_BV(1);
	ADMUX &= ~_BV(2);
	break;

	case (2): // C - centralny
	ADMUX &= ~_BV(0);
	ADMUX |= _BV(1);
	ADMUX &= ~_BV(2);
	break;

	case (3): // P - prawy wewnetrzny
	ADMUX |= _BV(0);
	ADMUX |= _BV(1);
	ADMUX &= ~_BV(2);
	break;

	case (4): // PP - prawy stakjny
	ADMUX &= ~_BV(0);
	ADMUX &= ~_BV(1);
	ADMUX |= _BV(2);
	break;
}
ADCSRA |= _BV(ADSC); // start konwersji

}

void bldc_komutacja_L(void)
{

switch (polozenie_wirnika_L++)
{
	case (1): //komutacja 1
	PORTB |= _BV(0);
	PORTB |= _BV(1);
	PORTB &=~_BV(2);
	break;

	case (2): //komutacja 2
	PORTB |= _BV(0);
	PORTB &=~_BV(1);
	PORTB &=~_BV(2);
	break;

	case (3): //komutacja 3
	PORTB |= _BV(0);
	PORTB &=~_BV(1);
	PORTB |= _BV(2);
	break;

	case (4): //komutacja 4
	PORTB &=~_BV(0);
	PORTB &=~_BV(1);
	PORTB |= _BV(2);
	break;

	case (5): //komutacja 5
	PORTB &=~_BV(0);
	PORTB |= _BV(1);
	PORTB |= _BV(2);
	break;

	case (6): //komutacja 6
	PORTB &=~_BV(0);
	PORTB |= _BV(1);
	PORTB &=~_BV(2);

	polozenie_wirnika_L = 1; //komutacja od początku

	break;
}
//_delay_ms(vL);
}

void bldc_komutacja_P(void)
{
switch (polozenie_wirnika_P++)
{
	case (1): //komutacja 1
	PORTB &=~_BV(3);
	PORTB |= _BV(4);
	PORTB &=~_BV(5);
	break;

	case (2): //komutacja 2
	PORTB &=~_BV(3);
	PORTB |= _BV(4);
	PORTB |= _BV(5);
	break;

	case (3): //komutacja 3
	PORTB &=~_BV(3);
	PORTB &=~_BV(4);
	PORTB |= _BV(5);
	break;

	case (4): //komutacja 4
	PORTB |= _BV(3);
	PORTB &=~_BV(4);
	PORTB |= _BV(5);
	break;

	case (5): //komutacja 5
	PORTB |= _BV(3);
	PORTB &=~_BV(4);
	PORTB &=~_BV(5);
	break;

	case (6): //komutacja 6
	PORTB |= _BV(3);
	PORTB |= _BV(4);
	PORTB &=~_BV(5);

	polozenie_wirnika_P = 1; 		//komutacja od początku

	break;
}
//_delay_ms(vP);
}

void init_adc(void) 					//KONFIGURACJA ADC
{
ADCSRA |= _BV(ADPS2) | _BV(ADPS1); // preskaler 64
ADCSRA |= _BV(ADIE); 				// przerwania aktywne
ADMUX |= _BV(REFS0); 				// napięcie odniesienia z AVCC
ADMUX |= _BV(ADLAR); 				// wynik w postaci 8-bitowej
ADCSRA |= _BV(ADEN); 				// przetwornik aktywny
}

void port_conf(void)				 	//konfiguracja portów
{
DDRC = 0x00; 						// wszystkie linie wejścia, aktywne ADC
PORTC = 0x00;
DDRB = 0xff; 						// wyjścia - silniki
DDRD = 0xff; 						// wyjścia - led
}

int main(void)
{
sei(); 								//globalne odblokowanie przerwan
port_conf();
init_adc();
ADCSRA |= _BV(ADSC); 				//start konwersji

/*OCR1A = 30000; //Określenie do ilu ma zliczać timer T1 zmiana tej wartości powoduje zmianę częstotliwości komutacji
TCCR1A = 0x00; //Ustawienie trybu pracy timera T1
TCCR1B = (1 << WGM12) | (1 << CS12); //Ustawienie trybu pracy timera T1
TIFR = (1 << OCF1A); //Ustawienie flagi OCF1A w stan wysoki
TIMSK = (1 << OCIE1A); //Uaktywnienie przerwania zgodne porównianie A dla timera T1
*/


while(1)
{

	if (pomiar[0] > 150) 			//jeśli zmierzone napięcie jest większe niż ustawiona czułość to znaczy że pod czujnikiem jest czarna linia - czujnik wyrył czarną linię
{
	LED_ON_0; 						// dioda led ON
//	vL=7;
//	vP=12;
	bldc_komutacja_L();		
	_delay_ms(6);
//	bldc_komutacja_P();
//	_delay_ms(15);
}
	else if (pomiar[1] > 150)
{
	LED_ON_1; 						// dioda led ON
//	vL=8;
//	vP=10;
	bldc_komutacja_L();
	_delay_ms(7);
//	bldc_komutacja_P();
//	_delay_ms(15);
}

	else if (pomiar[2] > 150)
{
	LED_ON_2; 						// dioda led ON
//	vL=8;
//	vP=8;
	bldc_komutacja_L();
	bldc_komutacja_P();
	_delay_ms(9);
}

	else if (pomiar[3] > 150)
{
	LED_ON_3; 						// dioda led ON
//	vP=8;
//	vL=10;	
	bldc_komutacja_P();
	_delay_ms(7);
//	bldc_komutacja_L();
//	_delay_ms(15);
}

	else if (pomiar[4] > 150)
{
	LED_ON_4; 						// dioda led ON
//	vP=7;
//	vL=12;
	bldc_komutacja_P();
	_delay_ms(6);
//	bldc_komutacja_L();
//	_delay_ms(15);
}
else 							//czujnik nie wykrył czarnej linii
{
	LED_OFF; 						// diody led OFF
//	vL=8;
//	vP=8;
	bldc_komutacja_L();
	bldc_komutacja_P();
	_delay_ms(9);
}	
}
return 0;
}

Co można zmienić w tym programie, by umożliwić mu pokonywanie zakrętów 90 stopniowych? Sprawa jest o tyle bardziej skomplikowana, że są to silniki BLDC.

Na daną chwilę robot fajnie śmiga nawet po ostrych zakrętach, ale niestety zakręt 90 stopni (bez żadnego zaokrąglenia linii) jest poza jego możliwościami.

Link do komentarza
Share on other sites

Musisz pamiętać, gdzie ostatnio widziałeś linię:

- po prawej stronie od środkowego czujnika

- po lewej stronie od środkowego czujnika

Jak tylko stracisz linię z widzenia czujników, sprawdzasz gdzie była ostatnio i skręcasz w tamtą stronę.

Link do komentarza
Share on other sites

Już nieaktualne 😉 Wprowadziłem dodatkowe warunki do przerwania i jeśli widzą trzy czujniki z lewa albo prawa, to wpada w nieskończoną pętlę, która trwa tak długo, aż nie znajdzie linii czujnikiem z drugiej strony.

Działa jak burza.

Link do komentarza
Share on other sites

Ale nie zawsze to zadziała, ogólnie powinno się unikać pisania specjalnych fragmentów tylko pod kąty proste w takich konstrukcjach.

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

Generalnie tak, ale musiałbym wtedy raczej przerobić dosyć mocno ten program. Problem jest właśnie w tym, że on ma czujniki wrzucone w przerwanie - więc zawsze jest "up to date" (a już nie chciałem tego zmieniać). Wtedy też pasowałoby mu dać priorytety na czujnikach, żeby nie zaczął wariować którą dyrektywę ma wykonać.

Ot najprostszą metodą było po prostu wrzucenie dodatkowej pętli w przerwanie (wtedy eliminujemy to, że zawsze ma aktualne informacje z czujników i w ten sposób się zachowuje), bo pokonuje wszystkie zakręty - za wyjątkiem właśnie czystego 90 stopni.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.