vish
18.05.2005, 17:43
Hallo zusammen!
Ich zerbreche mir schon seit Wochen den Kopf, weshalb mein Roboter der Linie nicht folgen möchte. Ich fasse mal kurz die wichtigsten Daten des Roboters zusammen:
* Batteriespannung 9,6V (8 Akkus)
* 5,1V Logikspannung (Schaltung mit Schaltregler L4960)
* 18V über Spannungsverdopplung für den Motortreiber (Ganz normale L298 Schaltung)
* 2 Faulhaber Motoren
* AVR mega16 Grundschaltung @ 7,3728 MHz (https://www.roboternetz.de/phpBB2/album_pic.php?pic_id=153)
* Liniensensor mit 8 CNY70's am ADC des µC
Die Grundschaltung funktioniert, ebenso mein Liniensensor.
Beim Motortreiber bin ich mir nicht sicher ob der 100%ig funktioniert. Er treibt die Motoren zwar wunderbar, d.h. wenn ich die Enable Eingänge ganz normal auf High schalte drehen sich die Motoren und auf Low drehen sie sich eben nicht.
Doch bei der PWM will es einfach nicht hinhauen.
Den mega16 habe ich bereits einmal ausgetauscht, was jedoch keine Verbesserung brachte.
Hier der Code:
linienfolger.c mit der main() Funktion:
#include <avr/io.h>
#include <stdint.h>
#include <avr/delay.h>
#define trigger 512 // Schwellwert für get_adc_bit
#define verdammtschnell 1024
#define sehrschnell 854
#define schnell 684
#define mittel 514
#define langsam 344
#define sehrlangsam 174
#define verdammtlangsam 1
// Motordrehrichtung:
#define vorwaerts (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4)
uint8_t channel = 0; // A/D Konverter Channel
uint16_t adc_result;
struct
{
uint8_t sen1:1;
uint8_t sen2:1;
uint8_t sen3:1;
uint8_t sen4:1;
uint8_t sen5:1;
uint8_t sen6:1;
uint8_t sen7:1;
uint8_t sen8:1;
} sensor;
int8_t line_position; // Linienposition (-127 - +127)
int main(void)
{
init_pwm(); // Initialisiere Timer1 mit PWM
init_adc(); // Initialisiere A/D Konverter
DDRC = (1 << PC7) | (1 << PC6) | (1 << PC5) | (1 << PC4); // Datenleitungen für L298
for (;;) // Endlosschleife
{
// Sensorwerte holen:
sensor.sen1 = get_adc_bit(channel,trigger); // Rückgabewert: 1 Bit
channel++; // Nächsten Channel
sensor.sen2 = get_adc_bit(channel,trigger);
channel++;
sensor.sen3 = get_adc_bit(channel,trigger);
channel++;
sensor.sen4 = get_adc_bit(channel,trigger);
channel++;
sensor.sen5 = get_adc_bit(channel,trigger);
channel++;
sensor.sen6 = get_adc_bit(channel,trigger);
channel++;
sensor.sen7 = get_adc_bit(channel,trigger);
channel++;
sensor.sen8 = get_adc_bit(channel,trigger);
channel = 0; // Channel zurücksetzen
// Errechne Linienposition:
line_position = sensor.sen1 * (-4) + sensor.sen2 * (-3) + sensor.sen3 * (-2) + sensor.sen4 * (-1) + sensor.sen5 * (1) + sensor.sen6 * (2) + sensor.sen7 * (3) + sensor.sen8 * (4);
switch (line_position)
{
// Siehe case -7:
case -4:
PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
OCR1A = verdammtschnell; // Rechts: Volle Kraft
OCR1B = verdammtlangsam; // Links: Stop
break;
// Linie befindet sich weit rechts -> Motoren vorwärts, links Stop
case -7:
PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
OCR1A = verdammtschnell; // Rechts: Volle Kraft
OCR1B = verdammtlangsam; // Links: Stop
break;
case -9:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = sehrlangsam;
break;
case -5:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = langsam;
break;
case -6:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = mittel;
break;
case -3:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = schnell;
break;
case -2:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = sehrschnell;
break;
case 0:
PORTC = vorwaerts;
OCR1A = OCR1B = verdammtschnell;
break;
case 2:
PORTC = vorwaerts;
OCR1A = sehrschnell;
OCR1B = verdammtschnell;
break;
case 3:
PORTC = vorwaerts;
OCR1A = schnell;
OCR1B = verdammtschnell;
break;
case 6:
PORTC = vorwaerts;
OCR1A = mittel;
OCR1B = verdammtschnell;
break;
case 5:
PORTC = vorwaerts;
OCR1A = langsam;
OCR1B = verdammtschnell;
break;
case 9:
PORTC = vorwaerts;
OCR1A = sehrlangsam;
OCR1B = verdammtschnell;
break;
case 7:
PORTC = vorwaerts;
OCR1A = verdammtlangsam;
OCR1B = verdammtschnell;
break;
case 4:
PORTC = vorwaerts;
OCR1A = verdammtlangsam;
OCR1B = verdammtschnell;
break;
default:
PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
OCR1A = OCR1B = verdammtlangsam;
break;
}
}
return 0;
}
PWM:
#include <avr/io.h>
#include <stdint.h>
void init_pwm(void);
void init_pwm(void)
{
DDRD = (1 << PD4) | (1 << PD5); // OCR1A und B an PD4 und 5 (mega16)
PORTD = ~(1 << PD4) & ~(1 << PD5);
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1A0) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10); // 10 Bit Pwm, invertierend
TCCR1B = (1<<CS11) | (1<<CS10); // Prescaler 64
}
Und zu guter Letzt noch die adc.c um den Liniensensor auszuwerten:
#include <avr/io.h>
#include <stdint.h>
void init_adc(void);
void disable_adc(void);
void get_adc_char(uint8_t channel);
uint16_t get_adc_int(uint8_t channel);
uint8_t get_adc_bit(uint8_t channel, uint16_t trigger);
void init_adc(void)
{
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1); // ADC Anschalten, Prescaler von 64 (7378200/64=115200 Hz oder 115.2 kHz
}
void disable_adc(void)
{
ADCSRA &= ~(1 << ADEN); // Disable ADC
}
uint16_t get_adc_int(uint8_t channel)
{
uint16_t result = 0;
ADMUX = channel; // Channel auswählen
ADCSRA |= (1<<ADSC); // Konvertierung starten
while (ADCSRA & (1<<ADSC)); // Warte bis ADSC gelöscht wird --> Konvertierung fertig
result = ADC;
return result;
}
void get_adc_print(uint8_t channel)
{
uint16_t result = 0;
unsigned char sresult[4];
ADMUX = channel; // Channel auswählen
ADCSRA |= (1<<ADSC); // Konvertierung starten
while (ADCSRA & (1<<ADSC)); // Warte bis ADSC gelöscht wird --> Konvertierung fertig
result = ADC;
itoa(result, sresult, 10);
print_string_usart(sresult);
}
uint8_t get_adc_bit(uint8_t channel, uint16_t trigger)
{
uint16_t result = 0;
ADMUX = channel; // Channel auswählen
ADCSRA |= (1<<ADSC); // Konvertierung starten
while (ADCSRA & (1<<ADSC)); // Warte bis ADSC gelöscht wird --> Konvertierung fertig
result = ADC;
if (result >= trigger)
{
return 1;
}
else
{
return 0;
}
}
Achja, mir ist gerade noch eingefallen, dass ich die Überprüfung der Sensoren bisher nur mit einem Bascomprogramm erledigt habe, es könnte also sein, dass mein ADC Code nicht funktioniert.
Wäre echt nett, wenn mir jemand helfen könnte!
Grüße,
Jonas
Ich zerbreche mir schon seit Wochen den Kopf, weshalb mein Roboter der Linie nicht folgen möchte. Ich fasse mal kurz die wichtigsten Daten des Roboters zusammen:
* Batteriespannung 9,6V (8 Akkus)
* 5,1V Logikspannung (Schaltung mit Schaltregler L4960)
* 18V über Spannungsverdopplung für den Motortreiber (Ganz normale L298 Schaltung)
* 2 Faulhaber Motoren
* AVR mega16 Grundschaltung @ 7,3728 MHz (https://www.roboternetz.de/phpBB2/album_pic.php?pic_id=153)
* Liniensensor mit 8 CNY70's am ADC des µC
Die Grundschaltung funktioniert, ebenso mein Liniensensor.
Beim Motortreiber bin ich mir nicht sicher ob der 100%ig funktioniert. Er treibt die Motoren zwar wunderbar, d.h. wenn ich die Enable Eingänge ganz normal auf High schalte drehen sich die Motoren und auf Low drehen sie sich eben nicht.
Doch bei der PWM will es einfach nicht hinhauen.
Den mega16 habe ich bereits einmal ausgetauscht, was jedoch keine Verbesserung brachte.
Hier der Code:
linienfolger.c mit der main() Funktion:
#include <avr/io.h>
#include <stdint.h>
#include <avr/delay.h>
#define trigger 512 // Schwellwert für get_adc_bit
#define verdammtschnell 1024
#define sehrschnell 854
#define schnell 684
#define mittel 514
#define langsam 344
#define sehrlangsam 174
#define verdammtlangsam 1
// Motordrehrichtung:
#define vorwaerts (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4)
uint8_t channel = 0; // A/D Konverter Channel
uint16_t adc_result;
struct
{
uint8_t sen1:1;
uint8_t sen2:1;
uint8_t sen3:1;
uint8_t sen4:1;
uint8_t sen5:1;
uint8_t sen6:1;
uint8_t sen7:1;
uint8_t sen8:1;
} sensor;
int8_t line_position; // Linienposition (-127 - +127)
int main(void)
{
init_pwm(); // Initialisiere Timer1 mit PWM
init_adc(); // Initialisiere A/D Konverter
DDRC = (1 << PC7) | (1 << PC6) | (1 << PC5) | (1 << PC4); // Datenleitungen für L298
for (;;) // Endlosschleife
{
// Sensorwerte holen:
sensor.sen1 = get_adc_bit(channel,trigger); // Rückgabewert: 1 Bit
channel++; // Nächsten Channel
sensor.sen2 = get_adc_bit(channel,trigger);
channel++;
sensor.sen3 = get_adc_bit(channel,trigger);
channel++;
sensor.sen4 = get_adc_bit(channel,trigger);
channel++;
sensor.sen5 = get_adc_bit(channel,trigger);
channel++;
sensor.sen6 = get_adc_bit(channel,trigger);
channel++;
sensor.sen7 = get_adc_bit(channel,trigger);
channel++;
sensor.sen8 = get_adc_bit(channel,trigger);
channel = 0; // Channel zurücksetzen
// Errechne Linienposition:
line_position = sensor.sen1 * (-4) + sensor.sen2 * (-3) + sensor.sen3 * (-2) + sensor.sen4 * (-1) + sensor.sen5 * (1) + sensor.sen6 * (2) + sensor.sen7 * (3) + sensor.sen8 * (4);
switch (line_position)
{
// Siehe case -7:
case -4:
PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
OCR1A = verdammtschnell; // Rechts: Volle Kraft
OCR1B = verdammtlangsam; // Links: Stop
break;
// Linie befindet sich weit rechts -> Motoren vorwärts, links Stop
case -7:
PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
OCR1A = verdammtschnell; // Rechts: Volle Kraft
OCR1B = verdammtlangsam; // Links: Stop
break;
case -9:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = sehrlangsam;
break;
case -5:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = langsam;
break;
case -6:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = mittel;
break;
case -3:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = schnell;
break;
case -2:
PORTC = vorwaerts;
OCR1A = verdammtschnell;
OCR1B = sehrschnell;
break;
case 0:
PORTC = vorwaerts;
OCR1A = OCR1B = verdammtschnell;
break;
case 2:
PORTC = vorwaerts;
OCR1A = sehrschnell;
OCR1B = verdammtschnell;
break;
case 3:
PORTC = vorwaerts;
OCR1A = schnell;
OCR1B = verdammtschnell;
break;
case 6:
PORTC = vorwaerts;
OCR1A = mittel;
OCR1B = verdammtschnell;
break;
case 5:
PORTC = vorwaerts;
OCR1A = langsam;
OCR1B = verdammtschnell;
break;
case 9:
PORTC = vorwaerts;
OCR1A = sehrlangsam;
OCR1B = verdammtschnell;
break;
case 7:
PORTC = vorwaerts;
OCR1A = verdammtlangsam;
OCR1B = verdammtschnell;
break;
case 4:
PORTC = vorwaerts;
OCR1A = verdammtlangsam;
OCR1B = verdammtschnell;
break;
default:
PORTC = (0 << PC7) | (1 << PC6) | (1 << PC5) | (0 << PC4);
OCR1A = OCR1B = verdammtlangsam;
break;
}
}
return 0;
}
PWM:
#include <avr/io.h>
#include <stdint.h>
void init_pwm(void);
void init_pwm(void)
{
DDRD = (1 << PD4) | (1 << PD5); // OCR1A und B an PD4 und 5 (mega16)
PORTD = ~(1 << PD4) & ~(1 << PD5);
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1A0) | (1<<COM1B0) | (1<<WGM11) | (1<<WGM10); // 10 Bit Pwm, invertierend
TCCR1B = (1<<CS11) | (1<<CS10); // Prescaler 64
}
Und zu guter Letzt noch die adc.c um den Liniensensor auszuwerten:
#include <avr/io.h>
#include <stdint.h>
void init_adc(void);
void disable_adc(void);
void get_adc_char(uint8_t channel);
uint16_t get_adc_int(uint8_t channel);
uint8_t get_adc_bit(uint8_t channel, uint16_t trigger);
void init_adc(void)
{
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1); // ADC Anschalten, Prescaler von 64 (7378200/64=115200 Hz oder 115.2 kHz
}
void disable_adc(void)
{
ADCSRA &= ~(1 << ADEN); // Disable ADC
}
uint16_t get_adc_int(uint8_t channel)
{
uint16_t result = 0;
ADMUX = channel; // Channel auswählen
ADCSRA |= (1<<ADSC); // Konvertierung starten
while (ADCSRA & (1<<ADSC)); // Warte bis ADSC gelöscht wird --> Konvertierung fertig
result = ADC;
return result;
}
void get_adc_print(uint8_t channel)
{
uint16_t result = 0;
unsigned char sresult[4];
ADMUX = channel; // Channel auswählen
ADCSRA |= (1<<ADSC); // Konvertierung starten
while (ADCSRA & (1<<ADSC)); // Warte bis ADSC gelöscht wird --> Konvertierung fertig
result = ADC;
itoa(result, sresult, 10);
print_string_usart(sresult);
}
uint8_t get_adc_bit(uint8_t channel, uint16_t trigger)
{
uint16_t result = 0;
ADMUX = channel; // Channel auswählen
ADCSRA |= (1<<ADSC); // Konvertierung starten
while (ADCSRA & (1<<ADSC)); // Warte bis ADSC gelöscht wird --> Konvertierung fertig
result = ADC;
if (result >= trigger)
{
return 1;
}
else
{
return 0;
}
}
Achja, mir ist gerade noch eingefallen, dass ich die Überprüfung der Sensoren bisher nur mit einem Bascomprogramm erledigt habe, es könnte also sein, dass mein ADC Code nicht funktioniert.
Wäre echt nett, wenn mir jemand helfen könnte!
Grüße,
Jonas