Skocz do zawartości

Problem ze sterowaniem przez bluetooth, robotem linefollower.


RexJoker

Pomocna odpowiedź

Hej!

Mam problem z moim sterowaniem przez bluetooth,robotem lf. Otóż podłączając bluetooth do robota ,a następnie łączę się z modułem za pomocą aplikacji : "Bluetooth spp pro" i po wpisaniu jakiegokolwiek znaku z systemu ASCII i wysłaniu jej robotu od razu reaguje na niego poprzez wyłączenie się.Nie mam pojęcia czemu mogło by tak być. Wszystkie podłączenia modułu z uC (ATMega644PA) są dobre, natomiast sam robot dobrze działa bo robię na nim próby na czarnej linii. Chciałbym aby ten moduł działał bo ogromnie by to ułatwiło sprawę w eksperymentowaniu regulatora PD ,którego zaimplementowałem w robocie. Dodaję kod całego programu:

 #define F_CPU 8000000UL
#define FOSC 8000000
#include <util/delay.h>
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <avr/interrupt.h>
#define LED1 (1<<PD2)
#define LED2 (1<<PD3)
#define LED3 (1<<PC4)
#define LED4 (1<<PC5)
#define LED5 (1<<PC6)
#define LED6 (1<<PC7)
#define CR1 (1<<PA6)
#define CR2 (1<<PA5)
#define CR3 (1<<PA4)
#define CR4 (1<<PA3)
#define CR8 (1<<PA2)
#define CR7 (1<<PA1)
#define CR6 (1<<PA0)
#define CR12 (1<<PB4)
#define CR11 (1<<PB3)
#define CR10 (1<<PB2)
#define CR9 (1<<PB1)
#define CR5 (1<<PB0)
#define DIRA1 (1<<PC0)
#define DIRA2 (1<<PC1)
#define DIRB1 (1<<PC2)
#define DIRB2 (1<<PC3)
#define PWMP OCR1B
#define PWML OCR1A
int Tab_czuj[13]={0};
int regulacja=0,memer=0, wyp=40, ba=0, pop_blad = 0, Kp = 30, Kd = 50, V_zad = 100;
volatile uint8_t wychodzace;
volatile int jazda = 1, petla=1;
volatile uint8_t dir;
void LEDCZUJ_INIT();
void Tabc_licz();
void MPLF();
void PWM();
void USART_Init(void)
{
UCSR0A|=_BV(U2X0);   //podwójna prędkosc transmisji
UBRR0H=0;
UBRR0L=12;    //baudrate 9600
UCSR0B=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); //włączenie transmisji i odbioru
UCSR0C=(1<<UCSZ00)|(1<<UCSZ01);  //tryb asynchroniczny, 8 bitowa ramka danych
}
void USART_Transmit(void)   //Wysylanie danych do telefonu.
{
while((UCSR0A & (1<<UDRE0)) == 0){
UDR0= wychodzace;}
}
void Blu(volatile uint8_t dir)  //Obsluga komend z blu
{
switch(dir)
{
	case 97:
		jazda=1;
		break;
	case 98:
		jazda=0;
		break;
	case 99:
		Kp+=1;
		break;
	case 100:
		Kp+=5;
		break;
	case 101:
		Kp-=1;
		break;
	case 102:
		Kp-=5;
		break;
	case 103:
		Kd+=1;
		break;
	case 104:
		Kd+=5;
		break;
	case 105:
		Kd-=1;
		break;
	case 106:
		Kd-=5;
		break;
}
}
int main(void){
volatile uint8_t dir;
DDRC |= DIRA1;
DDRC |= DIRA2;
DDRC |= DIRB1;
DDRC |= DIRB2;
DDRD |= (1<<PD5);
DDRD |= (1<<PD4);
PORTD &= ~(1<<PD5);
PORTD &= ~(1<<PD4);
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM10); // Fast PWM
TCCR1B = (1<<CS10) | (1<<WGM12); //Fast PWM
OCR1A = OCR1B = 0; //Fast PWM
TCCR0A |= (1<<WGM01); //Przerwanie czasowe Timer
TCCR0B |= (1<<CS02)|(1<<CS00); //CLK
OCR0A=78; //Timer
TIMSK0 |=(1<<OCIE0A); //Timer
sei(); //Globalne przerwania
_delay_ms(1000);
LEDCZUJ_INIT();
USART_Init();
while(1){
	dir=UDR0;
	Blu(dir);
	if(petla && jazda){
		MPLF();
		petla=0;
	}
}
return 0;
}
void LEDCZUJ_INIT(){
DDRA &= ~CR2;
DDRA &= ~CR1;
DDRA &= ~CR3;
DDRA &= ~CR4;
DDRA &= ~CR8;
DDRA &= ~CR7;
DDRA &= ~CR6;
DDRB &= ~CR12;
DDRB &= ~CR11;
DDRB &= ~CR10;
DDRB &= ~CR9;
DDRB &= ~CR5;
DDRD |= LED1;
DDRD |= LED2;
DDRC |= LED3;
DDRC |= LED4;
DDRC |= LED5;
DDRC |= LED6;
}
void Tabc_licz(){
if(!(PINA & CR1)) Tab_czuj[1]=0;
else Tab_czuj[1]=1;
if(!(PINA & CR2)) Tab_czuj[2]=0;
else Tab_czuj[2]=1;
if(!(PINA & CR3)) Tab_czuj[3]=0;
else Tab_czuj[3]=1;
if(!(PINA & CR4)) {Tab_czuj[4]=0; PORTC |= LED6;}
else {Tab_czuj[4]=1; PORTC &= ~LED6;}
if(!(PINA & CR5)) {Tab_czuj[5]=0; PORTC |= LED5;}
else {Tab_czuj[5]=1; PORTC &= ~LED5;}
if(!(PINA & CR6)) {Tab_czuj[6]=0; PORTC |= LED4;}
else {Tab_czuj[6]=1; PORTC &= ~LED4;}
if(!(PINA & CR7)) {Tab_czuj[7]=0; PORTD |= LED1;}
else {Tab_czuj[7]=1; PORTD &= ~LED1;}
if(!(PINA & CR8)) {Tab_czuj[8]=0; PORTD |= LED2;}
else {Tab_czuj[8]=1; PORTD &= ~LED2;}
if(!(PINA & CR9)) {Tab_czuj[9]=0; PORTC |= LED3;}
else {Tab_czuj[9]=1; PORTC &= ~LED3;}
if(!(PINA & CR10))Tab_czuj[10]=0;
else Tab_czuj[10]=1;
if(!(PINA & CR11)) Tab_czuj[11]=0;
else Tab_czuj[11]=1;
if(!(PINA & CR12)) Tab_czuj[12]=0;
else Tab_czuj[12]=1;
}
int blad(){
int err=0, ilosc =0 ,waga=2, prev_err = 0;
int przestrzelony = 0;
int tab_wagi[13]={-15,-10,-7,-5,-3,-1,1,3,5,7,10,15};
	  if(przestrzelony)                    // zmniejszenie wag czujników w przypadku przestrzelenia zakrętu
	 waga =1;
for(int i=0; i<12; i++)
{
	err += Tab_czuj[i]*tab_wagi[i]*waga;        // wagi kolejnych czujników * waga
	ilosc += Tab_czuj[i];            // czujniki[i] ma warto?? 1/0
}
err /= ilosc;   
if(ilosc != 0)
{
	 err /= ilosc;
	 prev_err = err;
 }
 else
 {
	 if(prev_err < -20)
	 {
		 err = -40;
		 przestrzelony = 1;                // ustawienie flagi - przestrzelony, linia po lewej
	 }
	 else if(prev_err > 20)
	 {
		 err = 40;
		 przestrzelony = 2;                // ustawienie flagi - przestrzelony, linia po prawej
	 }
	 else
	 err = 0;
 }

 if(przestrzelony == 1 && err >= 0)        // zerowanie flagi przestrzelenia zakrętu po powrocie na środek linii
	przestrzelony = 0;
 else if(przestrzelony == 2 && err <= 0)
	przestrzelony = 0;

 return err;
}
int PD()
{
int rozniczka = ba - pop_blad;
pop_blad = ba;
return Kp*ba + Kd*rozniczka;
}
int licznik=0;
void PWM(int lewy , int prawy)
{
if(lewy >= 0)
{
	if(lewy>255)
	lewy = wyp;
	PORTC |= DIRA2;  //EN12 1
	PORTC &= ~DIRA1; //EN11 0
}
else
{
	if(lewy<-255)
	lewy = -wyp;
	PORTC &= ~DIRA2; //EN12 0
	PORTC |= DIRA1; //EN11 1
}

if(prawy >= 0)
{
	if(prawy>255)
	prawy = wyp;
	PORTC |= DIRB1; //EN22 1
	PORTC &= ~DIRB2; //EN21 0
}
else
{
	if(prawy<-255)
	prawy = -wyp;
	PORTC &= ~DIRB1; //EN22 0
	PORTC |= DIRB2; //EN21 1
}

PWML = abs(lewy);
PWMP = abs(prawy);
}
void MPLF(){
Tabc_licz();
ba=blad();
int regulacja = PD();
PWM(V_zad + regulacja, V_zad - regulacja);
}
ISR(TIMER0_COMPA_vect)			// obs³uga przerwania od Timera 0
{
petla = 1;
} 

Dodaje też schemat robota LF. Wiem ,że w schemacie znajduje się uC Atmega644A,jednakże pinout jest taki sam jak w przypadku -||- PA . Dodam jeszcze informację ,że posiadam moduł Bluetooth z botland : Moduł Bluetooth 2.1 XM-15B 3,3V/5V .

Proszę o pomoc.

Dziękuje.

Link do komentarza
Share on other sites

Krok pierwszy: spróbuj ograniczyć problem do możliwie najmniejszego zakresu.

po wpisaniu jakiegokolwiek znaku z systemu ASCII i wysłaniu jej robotu od razu reaguje na niego poprzez wyłączenie się

Czyli co, wypada wtyczka od akumulatora zasilającego?

Link do komentarza
Share on other sites

Może masz na myśli, że robot się resetuje?

Jest to spowodwane tym, że masz włączone używanie przerwania do odbioru znaku z uarta:

UCSR0B=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);

Chodzi o RXCIE0.

Jak najbardziej możesz tego używać, ale musisz dodać obsługę przerwania czyli instrukcja ISR i odpowiedni wektor.

Domyślnie wszystkie wywołania przerwania powodują reset systemu i dlatego każdy wysłany znak kończy się resetem. Dopiero po podpięciu odpowiedniego kodu pod przerwanie program będzie działał dobrze. W kodzie przerwania możesz rozpoznawać znak i odpowiednio zmieniać zachowanie robota...

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

Domyślnie wszystkie wywołania przerwania powodują reset systemu i dlatego każdy wysłany znak kończy się resetem. Dopiero po podpięciu odpowiedniego kodu pod przerwanie program będzie działał dobrze. W kodzie przerwania możesz rozpoznawać znak i odpowiednio zmieniać zachowanie robota...

O najprawdopodobnie to jest moim rozwiazaniem tego problemu. Biorę się za pisanie wektoru.

Krok pierwszy: spróbuj ograniczyć problem do możliwie najmniejszego zakresu.

Po zmianie w switch'u ,żeby nie było żadnej możliwej opcji usunąłem cały fragment z case'ami i nic nie poprawiło ,więc jest to wina resetu jak kolega napisał. Raczej kabelek od zasilania się nie odpinał. Zapewniam 🙂

[ Dodano: 07-12-2016, 01:28 ]

Jeszcze mam jedno pytanie, nawiązujac do całego kodu

void USART_Transmit(void)   //Wysylanie danych do telefonu.
{
while((UCSR0A & (1<<UDRE0)) == 0){
UDR0= wychodzace;}
}
void Blu(volatile uint8_t dir)  //Obsluga komend z blu
{
switch(dir)
{
	case 98:
		jazda=1;
		break;
	case 99:
		jazda=0;
		OCR1A = OCR1B = 0; 
		break;
	case 100:
		Kp+=1;
                       Kp=wychodzace;
                       USART_Transmit()
		break;
	case 101:
		Kp-=1;
                       Kp=wychodzace;
                       USART_Transmit()
		break;
	case 102:
		Kd+=1;
                       Kd=wychodzace;
                       USART_Transmit()
		break;
	case 103:
		Kd-=1;
                       Kd=wychodzace;
                       USART_Transmit()
		break;
	case 104:
		Kp+=5;
                       Kp=wychodzace;
                       USART_Transmit()
		break;
	case 105:
		Kp-=5;
                       Kp=wychodzace;
                       USART_Transmit()
		break;
	case 106:
		Kd+=5;
                       Kd=wychodzace;
                       USART_Transmit()
		break;
	case 107:
		Kd-=5;
                       Kd=wychodzace;
                       USART_Transmit()
		break;
	case 108:
		silniki=1;
		break;
	case 109:
		silniki=0;
		OCR1A = OCR1B = 0; 
		break;
}
}

To czy w taki sposób mogę wysyłać dane o wartosci wzmocnienia kd i kp do mojego telefonu? Czy w inny sposób?

Co do problemu został rozwiązany 🙂 Dziękuje.

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

1. Dlaczego kp/kd = wychodzace, zamiast wychodzace = Kp/Kd

2. wychodzace jest typu uint8_t , czyli 8 bitów bez znaku. Kd/Kp definiujesz jako int, czyli dla atmegi 16bitowa wartość ze znakiem.

Najlepiej wysłać to jako dwa znaki i wtedy będziesz musiał po stronie komórki takie dwa znaki połączyć w jedną liczbę spowrotem.

Czyli kod w stylu:

wychodzace = Kp; // domyślnie procesor bierze 8 niższych bitów i kopiuje do wychodzące
USART_Transmit();
wychodzace = Kp >> 8; // >> 8 to przesunięcie wartości o 8 bitów, więc kompilator skopiuje do wychodzace 8 wyższych bitów
USART_Transmit();

To spowoduje, że jak w Kp masz wartość np 1024 , czyli hex 0x0400 to prześlesz przez BT dwa bajty 0x00 i 0x04 , co po złożeniu ponownie da 0x0400

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...