Automatické autíčko: Rozdiel medzi revíziami
Zo stránky SensorWiki
Riadok 47: | Riadok 47: | ||
<tab name="AVR C-code"><source lang="c++" style="background: LightYellow;"> | <tab name="AVR C-code"><source lang="c++" style="background: LightYellow;"> | ||
#include <avr/io.h> | #include <avr/io.h> | ||
#include <avr/interrupt.h> | |||
#include <util/delay.h> | |||
// Line Tracking IO define | |||
#define LT_R !(PIND & (1 << PD2)) | |||
#define LT_M !(PIND & (1 << PD4)) | |||
#define LT_L !(PINB & (1 << PB2)) | |||
#define ENA PD5 | |||
#define ENB PD6 | |||
#define IN1 PD7 | |||
#define IN2 PB0 | |||
#define IN3 PB1 | |||
#define IN4 PB3 | |||
#define carSpeed 82 | |||
#define otocka 180 | |||
#define STOJ 250 | |||
volatile unsigned long millis_count = 0; | |||
ISR(TIMER0_COMPA_vect) { | |||
millis_count++; | |||
} | |||
void forward() { | |||
OCR0A = carSpeed; | |||
OCR0B = carSpeed; | |||
PORTD |= (1 << IN1) | (1 << IN4); | |||
PORTB &= ~((1 << IN2) | (1 << IN3)); | |||
} | |||
void Mleft() { | |||
OCR0A = otocka; | |||
OCR0B = otocka; | |||
PORTD |= (1 << IN2) | (1 << IN4); | |||
PORTB &= ~((1 << IN1) | (1 << IN3)); | |||
} | |||
void Mright() { | |||
OCR0A = otocka; | |||
OCR0B = otocka; | |||
PORTB |= (1 << IN1) | (1 << IN3); | |||
PORTD &= ~((1 << IN2) | (1 << IN4)); | |||
} | |||
void stop() { | |||
OCR0A = 0; | |||
OCR0B = 0; | |||
PORTD &= ~((1 << IN1) | (1 << IN2) | (1 << IN4)); | |||
PORTB &= ~(1 << IN3); | |||
} | |||
void setup() { | |||
DDRD &= ~((1 << PD2) | (1 << PD4)); // Set PD2, PD4 as inputs | |||
DDRB &= ~(1 << PB2); // Set PB2 as input | |||
DDRD |= ((1 << ENA) | (1 << ENB) | (1 << IN1)); // Set PD5-PD7 as outputs | |||
DDRB |= ((1 << IN2) | (1 << IN3) | (1 << IN4)); // Set PB0-PB1 as outputs | |||
// Initialize timer for millis() | |||
TCCR0A |= (1 << WGM01); // CTC mode | |||
OCR0A = 249; // 1ms at 16MHz | |||
TIMSK0 |= (1 << OCIE0A); // Enable compare match interrupt | |||
sei(); // Enable global interrupts | |||
TCCR0B |= (1 << CS01) | (1 << CS00); // Start Timer0 with prescaler 64 | |||
// PWM setup for ENA and ENB pins (OC0A and OC0B) | |||
TCCR0A |= (1 << COM0A1) | (1 << COM0A0) | (1 << COM0B1) | (1 << COM0B0); // Set non-inverting mode for OC0A and OC0B | |||
TCCR0A |= (1 << WGM00) | (1 << WGM01); // Fast PWM mode | |||
} | |||
int main() { | |||
setup(); | |||
while(1) { | |||
if (LT_M) { | |||
forward(); | |||
// Reset the time when line detected | |||
millis_count = 0; | |||
} else if (LT_R) { | |||
Mright(); | |||
while (LT_R); | |||
} else if (LT_L) { | |||
Mleft(); | |||
while (LT_L); | |||
} else if (!LT_L && !LT_M && !LT_R) { | |||
// If no line detected for more than 700ms | |||
if (millis_count > 700) { | |||
stop(); // Stop the car | |||
_delay_ms(1000); // Wait for 1 second | |||
if (LT_L || LT_M || LT_R) continue; // If line detected, continue | |||
Mleft(); // Else, turn left | |||
_delay_ms(120); // Wait for turn to complete | |||
if (LT_L || LT_M || LT_R) continue; | |||
Mleft(); | |||
_delay_ms(100); | |||
if (LT_L || LT_M || LT_R) continue; | |||
Mleft(); | |||
_delay_ms(100); | |||
if (LT_L || LT_M || LT_R) continue; | |||
Mright(); | |||
_delay_ms(400); | |||
stop(); | |||
_delay_ms(1000); | |||
if (LT_L || LT_M || LT_R) continue; | |||
Mright(); | |||
_delay_ms(100); | |||
if (LT_L || LT_M || LT_R) continue; | |||
Mright(); | |||
_delay_ms(100); | |||
} | |||
} else { | |||
forward(); | |||
millis_count = 0; | |||
} | |||
} | |||
return 0; | |||
} | } | ||
Verzia z 21:13, 29. apríl 2024
Záverečný projekt predmetu MIPS / LS2024 - Meno Priezvisko
Automatické autíčko sledujúce čiernu čiaru
Sledovanie čiary je základnou technikou používanou v rôznych odvetviach robotiky, vrátane priemyselných robotov, autonómnych vozidiel, ale aj v domácich aplikáciách, ako sú napríklad čistiace roboty. Táto technika umožňuje vozidlám efektívne navigovať v prostredí, kde sú k dispozícii jednoduché vizuálne orientačné body, ako je napríklad čiara na zemi.
V tejto práci sa zameriame na implementáciu sledovania čiary v prostredí AVR, pričom sa budeme venovať nielen samotnému algoritmu sledovania čiary, ale aj analýze vplyvu rôznych parametrov a technických obmedzení na výkon a spoľahlivosť systému. Na základe tejto analýzy budeme schopní navrhnúť a implementovať optimalizovaný algoritmus sledovania čiary, ktorý bude schopný účinne navigovať v rôznych prostrediach a podmienkach.
Zadanie úlohy
Rozhodli sme sa pre náš záverečný projekt z MIPS vytvoriť autíčko, ktoré sleduje čiernu čiaru. Autíčko musí absolvovať celú dráhu zloženú z rôznych zatáčok a prerušení tejto čiary, ktoré musí zvládnuť.
Literatúra:
Popis autíčka
Analýza a opis riešenia
Ako teda autíčko funguje? Úlohu sledovania čiary zabezpečujú tri IR senzory, ktoré fungujú na princípe odrazenia sa signálu z IR led diódy do Photo diódy. Ak je podklad pod autíčkom čierny, tak sa od podkladu signál neodrazí a Photo dióda ho nezachytí. Akonáhle ale autíčko prejde mimo jeho stanovenej dráhy (mimo čiernej čiary) tak je naprogramované najprv zotrvať sekundu na jeho mieste a potom vybrať si smer rovno alebo pravý, ľavý. Pričom vždy jeden z týchto smerov ho navedie naspäť na dráhu.
Postup ako sa robot vracia späť na dráhu je jednoduchý. V našom funguje aj tak že vedia obe ľavé kolesa sa otáčať jedným smerom a kolesa vpravo do protismeru takže je veľmi efektívny pri otáčaní a zatáčaní.
Schéma zapojenia autíčka: Štyri motory sú napojene na napäťový menič L298N, ktorý rozdeľuje napätie do motorčekov. Je napájaný na 12V do arduina. Tri IR senzory sú potom napojené do PINOV 2,4,10.
Algoritmus a program
Zdrojový kód do autíčka v prostredí AVR
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
// Line Tracking IO define
#define LT_R !(PIND & (1 << PD2))
#define LT_M !(PIND & (1 << PD4))
#define LT_L !(PINB & (1 << PB2))
#define ENA PD5
#define ENB PD6
#define IN1 PD7
#define IN2 PB0
#define IN3 PB1
#define IN4 PB3
#define carSpeed 82
#define otocka 180
#define STOJ 250
volatile unsigned long millis_count = 0;
ISR(TIMER0_COMPA_vect) {
millis_count++;
}
void forward() {
OCR0A = carSpeed;
OCR0B = carSpeed;
PORTD |= (1 << IN1) | (1 << IN4);
PORTB &= ~((1 << IN2) | (1 << IN3));
}
void Mleft() {
OCR0A = otocka;
OCR0B = otocka;
PORTD |= (1 << IN2) | (1 << IN4);
PORTB &= ~((1 << IN1) | (1 << IN3));
}
void Mright() {
OCR0A = otocka;
OCR0B = otocka;
PORTB |= (1 << IN1) | (1 << IN3);
PORTD &= ~((1 << IN2) | (1 << IN4));
}
void stop() {
OCR0A = 0;
OCR0B = 0;
PORTD &= ~((1 << IN1) | (1 << IN2) | (1 << IN4));
PORTB &= ~(1 << IN3);
}
void setup() {
DDRD &= ~((1 << PD2) | (1 << PD4)); // Set PD2, PD4 as inputs
DDRB &= ~(1 << PB2); // Set PB2 as input
DDRD |= ((1 << ENA) | (1 << ENB) | (1 << IN1)); // Set PD5-PD7 as outputs
DDRB |= ((1 << IN2) | (1 << IN3) | (1 << IN4)); // Set PB0-PB1 as outputs
// Initialize timer for millis()
TCCR0A |= (1 << WGM01); // CTC mode
OCR0A = 249; // 1ms at 16MHz
TIMSK0 |= (1 << OCIE0A); // Enable compare match interrupt
sei(); // Enable global interrupts
TCCR0B |= (1 << CS01) | (1 << CS00); // Start Timer0 with prescaler 64
// PWM setup for ENA and ENB pins (OC0A and OC0B)
TCCR0A |= (1 << COM0A1) | (1 << COM0A0) | (1 << COM0B1) | (1 << COM0B0); // Set non-inverting mode for OC0A and OC0B
TCCR0A |= (1 << WGM00) | (1 << WGM01); // Fast PWM mode
}
int main() {
setup();
while(1) {
if (LT_M) {
forward();
// Reset the time when line detected
millis_count = 0;
} else if (LT_R) {
Mright();
while (LT_R);
} else if (LT_L) {
Mleft();
while (LT_L);
} else if (!LT_L && !LT_M && !LT_R) {
// If no line detected for more than 700ms
if (millis_count > 700) {
stop(); // Stop the car
_delay_ms(1000); // Wait for 1 second
if (LT_L || LT_M || LT_R) continue; // If line detected, continue
Mleft(); // Else, turn left
_delay_ms(120); // Wait for turn to complete
if (LT_L || LT_M || LT_R) continue;
Mleft();
_delay_ms(100);
if (LT_L || LT_M || LT_R) continue;
Mleft();
_delay_ms(100);
if (LT_L || LT_M || LT_R) continue;
Mright();
_delay_ms(400);
stop();
_delay_ms(1000);
if (LT_L || LT_M || LT_R) continue;
Mright();
_delay_ms(100);
if (LT_L || LT_M || LT_R) continue;
Mright();
_delay_ms(100);
}
} else {
forward();
millis_count = 0;
}
}
return 0;
}
#include <avr/io.h>
void adc_init(void); // A/D converter initialization
unsigned int adc_read(char a_pin);
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:
Zdrojový kód: zdrojaky.zip
Overenie
Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku záverečnej obrazovky pred resetom. Vypísaný je tu priemerný čas a najlepší čas.
Video:
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.