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/al...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:
Code:
#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:

Code:
#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:

Code:
#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