Interaktivni miš za kućne ljubimce

Tehnička škola Daruvar

Ideja nam je bila napraviti igračku miša koji bi bježao od mačke. Da bismo to ostvarili koristili smo 4 ultrazvučna senzora blizine i 2 kontinuirana servo motora. Senzori bi izračunali udaljenost od predmeta refleksije i zatim uz pomoć logike u kodu „miš“ odlučuje gdje će se kretati. Također se preko mobilnog uređaja može upravljati sa „mišem“ uz aplikaciju Blynk uz uvjet da je Arduino spojen na Internet tj. WiFi. Ispod presvlake „miša“ su postavljene mikro-sklopke koje se aktiviraju pritiskom na određene dijelove „miša“.

Video snimka

Izrada projekta

Arduino je usađen u pločicu preko socketa i na pločicu su nalemljeni ostali komponenti poput regulatora napona (7805) koji nam je potreban kako bi Arduino doveli konstantnih 5V. Ostali komponenti su punovalni ispravljač, koji nam jednostavno dopušta da bateriju spojimo obrnutog polaritet. Ostali komponenti su nalemljeni na žičice koje smo izvukli iz UTP kabela.

Kostur miša je konstruiran od bakrene žice debljine 2 mm i oblikovano tako da bi dobili okvir u kojem možemo postaviti Arduino i sve komponente i kako bi naš miš izgledao kao miš

Mobilna aplikacija

Na “screenshot”-u su prikazane sve komande koje sadrži početni ekran u našoj aplikaciji. To uključuje joystick za upravljanje Arduina i 2 tipke za zujalicu i automatsku navigaciju.

Joystick widget nam daje 2 varijable. Svaka varijabla pripada X i Y osi pojedinačno. Zajedno daju nam točku u koordinatnom sustavu koja odgovara trenutnoj lokaciji joystick-a u aplikaciji. Zatim uz pomoć tih varijabli u kodu određujemo u kojem smjeru se korisnik želi kretati.

Tipka radi na toggle principu što znači da se tipka ne treba držati kako bi ostala u jednom stanju. Može se reći da je tipka bistabilna. Uz pomoć te tipke omogućujemo ili onemogućujemo automatsku navigaciju “miša”.

Tipka je također bistabilna. Koristi se da aktivira zujalicu po želji korisnika aplikacije.

Shema projekta

Za napajanje Arduina koristimo 2 baterije 18650 koje idu na punovalni ispravljač koji služi samo da možemo spojiti baterije u bilo kojem polaritetu. Zatim se taj napon ispravlja na 5V. Za dvije svjetleće diode koristimo napajanje iz baterije pa koristimo tranzistor za napajanje. Ultrazvučni senzori su spojeni tako da im je trigger zajednički, a echo izlazi su svaki spojen na svoj ulaz u Arduino. Zujalica je također spojena preko napajanja baterije pa koristimo tranzistor za napajanje. Servo motori su spojeni također na bateriju a signal ulazi su spojeni na izlaze Arduina. Mikrosklopke su paralelno spojene tako da iako se jedna aktivira će se aktivirati.

Arduino program

#define #include 
#include 

// Autorizacijski kod za aplikaciju Blynk
char auth[] = "76c58709e359487890ee11bee42e04b1";

// Podatci za WiFi
char ssid[] = "Hotspotzabudale";
char pass[] = "lozinka1234";

//Blynk kontrolne varijable
int stanjeGumba;
int joystickX;
int joystickY;
int tipkaBuzzer;

// Ultrazvucni senzor
int trig = 10;

//Ulazi za echo od senzora
int echoFL = 6;
int echoFR = 7;
int echoBL = 8;
int echoBR = 9;

//Varijable za spremanje trajanja
long trajanjeFL;
long trajanjeFR;
long trajanjeBL;
long trajanjeBR;

//Varijable za spremanje udaljenosti
int udaljenostFL;
int udaljenostFR;
int udaljenostBL;
int udaljenostBR;

// Rep
#include
int randPos;
int randDelay;

//Deklariranje servo-a
Servo rep;
Servo servoL;
Servo servoD;

// Buzzer
int buzzer = 5;
int n;

//Deklariranje izlaza za oci
int oci = A3;

// Microswitch
int microswitch = 11;

void setup() {

//Pokretanje Serial Monitor-a
Serial.begin(9600);

//Deklariranje izlaza
pinMode(oci,OUTPUT);
pinMode(trig,OUTPUT);

//Deklariranje ulaza
pinMode(echoFL,INPUT);
pinMode(echoFR,INPUT);
pinMode(echoBL,INPUT);
pinMode(echoBL,INPUT);

//Spajanje servo-a na izlaze
rep.attach(4);
rep.write(90);

servoL.attach(2);
servoD.attach(3);

//Postavljanje servo-a u stanje mirovanja
servoL.write(90);
servoD.write(90);

// Buzzer
pinMode(buzzer,OUTPUT);

// Microswitch
pinMode(microswitch,INPUT_PULLUP);

//Oci
analogWrite(oci, 255);

//Povezivanje na WiFi 
Serial.println("Inicializacija uspjesna, povezivanje...");
Blynk.begin(auth, ssid, pass);
Serial.println("Blynk spojen!");


Serial.println("Pocetak rada!");
}

void loop() {
  Blynk.run(); //Govori Blynk library-u da provjeri dali korisnik nesto unosi preko aplikacije
  Buzzer(); //Poziva funckciju Buzzer
  repic(); //Poziva funkciju repic
  if (stanjeGumba == 1) //Ako je automatska navigacija ukljucena izvrsi sljedece
  {
    dohvatiSenzore(); //Pozivanje funkcije dohvatiSenzore
    //----- LOGIKA ZA AUTOMATSKO UPRAVLJANJE -----\\
    while (udaljenostFL <= 30) //Dok je predmet refleksije udaljen za 20 od senzora cini slijedece...
    { 
      Serial.println("Kontakt iza!"); //Ispis na Serial monitor
      servoD.write(20); //Pisemo na izlaze servo motora
      servoL.write(160);
      Buzzer(); //pozivamo funkciju Buzzer
      dohvatiSenzore(); //Pozivamo funkciju dohvatiSenzore
      Serial.print("udaljenostFL = ");
      Serial.println(udaljenostFL);
    }
    
    while (udaljenostBR <= 30) //Dok je predmet refleksije udaljen za 20 od senzora cini slijedece...
    {
      Serial.println("Kontakt naprijed!"); //Ispis na Serial monitor
      servoD.write(160); //Pisemo na izlaze servo motora
      servoL.write(20);
      Buzzer(); //Pozivamo funkciju Buzzer
      dohvatiSenzore(); //Pozivamo funkciju dohvatiSenzore
      Serial.print("udaljenostBR = ");
      Serial.println(udaljenostBR);
    }
    
    while (udaljenostBL <= 30) //Dok je predmet refleksije udaljen za 20 od senzora cini slijedece...
    {
      Serial.println("Kontakt desno!"); //Ispis na Serial monitor
      servoD.write(20); //Pisemo na izlaze servo motora
      servoL.write(20);
      Buzzer(); //pozivamo funkciju Buzzer
      dohvatiSenzore(); //Pozivamo funkciju dohvatiSenzore
      Serial.print("udaljenostBL = ");
      Serial.println(udaljenostBL);
      
    }
    
    while (udaljenostFR <= 30) //Dok je predmet refleksije udaljen za 20 od senzora cini slijedece... { Serial.println("Kontakt lijevo!"); //Ispis na Serial monitor servoD.write(160); servoL.write(160); Buzzer(); dohvatiSenzore(); Serial.print("udaljenostFR = "); Serial.println(udaljenostFR); } servoD.write(90); servoL.write(90); } //Ako automatska navigacija je ugasena onda kod ceka unos od korisnika } void repic() { //Generiramo nasumicni broj od 55 do 125 randPos = random(55, 125); //Na servo pisemo nasumicni broj i na toliko stupnjeva ce se servo okrenuti rep.write(randPos); //Nasumicni broj koji se koristi za kasnjenje kako bi pokreti izgledali nasumicni vise randDelay = random(250, 500); delay(randDelay); } void dohvatiSenzore() { //Odasiljemo signal preko Trigger izlaza na senzoru digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); //Izracunavamo trajanje povratka sa funkcijom pulseIn trajanjeFL = pulseIn(echoFL, HIGH); //Izracunavamo udaljenost senzora od predmeta refleksije udaljenostFL = trajanjeFL*0.034/2; //Malo kasnjenje kako bi se smirilo sve i kako nebi na nekom drugom senzoru dobili odaziv senzora prije delay(10); ////Odasiljemo signal preko Trigger izlaza na senzoru digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); //Izracunavamo trajanje povratka sa funkcijom pulseIn trajanjeFR = pulseIn(echoFR, HIGH); //Izracunavamo udaljenost senzora od predmeta refleksije udaljenostFR = trajanjeFR*0.034/2; //Malo kasnjenje kako bi se smirilo sve i kako nebi na nekom drugom senzoru dobili odaziv senzora prije delay(10); //Odasiljemo signal preko Trigger izlaza na senzoru digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); //Izracunavamo trajanje povratka sa funkcijom pulseIn trajanjeBL = pulseIn(echoBL, HIGH); //Izracunavamo udaljenost senzora od predmeta refleksije udaljenostBL = trajanjeBL*0.034/2; //Malo kasnjenje kako bi se smirilo sve i kako nebi na nekom drugom senzoru dobili odaziv senzora prije delay(10); //Odasiljemo signal preko Trigger izlaza na senzoru digitalWrite(trig, LOW); delayMicroseconds(2); digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); //Izracunavamo trajanje povratka sa funkcijom pulseIn trajanjeBR = pulseIn(echoBR, HIGH); //Izracunavamo udaljenost senzora od predmeta refleksije udaljenostBR = trajanjeBR*0.034/2; //Malo kasnjenje kako bi se smirilo sve i kako nebi na nekom drugom senzoru dobili odaziv senzora prije delay(10); //---- ISPISUJEMO UDALJENOST SVIJU SENZORA NA SERIAL MONITOR ---- // Serial.print("FL : "); Serial.print(udaljenostFL); Serial.print(" FR : "); Serial.print(udaljenostFR); Serial.print(" BL : "); Serial.print(udaljenostBL); Serial.print(" BR : "); Serial.print(udaljenostBR); // -------------------------------------------------------------- // Serial.println(""); Buzzer(); //Pozivamo funkciju Buzzer } void Buzzer() { while (digitalRead(microswitch)==LOW || tipkaBuzzer == 1) //Ako je pritisnuta sklopka na misu ili tipka na aplikaciji { //Smanjujemo svjetlinu oci na 128 analogWrite(oci, 128); //Pisemo ton za Buzzer analogWrite(buzzer,200); delay(100); //Uz pomoc petlje postepeno smanjuje ton i mijenjamo osvjetljenje ledica for( n=250; n>=50; n=n-3){
    analogWrite(buzzer,n);
    delay(3);
    analogWrite(oci,n*3);
   } 

  //Pisemo ton na buzzer
  analogWrite(buzzer,100);
  delay(100);
  analogWrite(buzzer,0);
  //Vracamo ledice na puni intenzitet
  analogWrite(oci, 255);
  //Dohvacamo vrijednosti sa aplikacije u slucaju da smo ugasili buzzer
  Blynk.run();
}

}

BLYNK_WRITE(V3) {
  tipkaBuzzer = param.asInt(); //Dohvacamo vrijednost tipke na vritualnom izlazu 3
  if (tipkaBuzzer == 1) {
    //Pozivamo funkciju buzzer i repic
    Buzzer();
    repic();
  }
  if (tipkaBuzzer == 0) {
    //U slucaju da tipka buzzer nije aktivna ne radimo nista
  }
}

BLYNK_READ(V4) {
  float bat = analogRead(A5);
  float struja = bat * (8.2 / 1023.0);
  Blynk.virtualWrite(V4, bat);
}

BLYNK_WRITE(V1) {
  stanjeGumba = param.asInt(); //Dohvacamo vrijednost gumba za automatsku navigaciju
  if (stanjeGumba == 1) {
    //Ako je navigacija ukljucena pokrecemo loop petlju i ispisujemo na serial monitor
    loop();
    Serial.println("Automatska navigacija ukljucena!");
  }
  if (stanjeGumba == 0) {
    //Ako je navigacija iskljucena onda pisemo na serial monitor
    Serial.println("Automatska navigacija iskljucena!");
  }
  Buzzer(); //Pozivamo funkciju buzzer
}

BLYNK_WRITE(V0) {
  if (stanjeGumba == 0) { //Ako je navigacija iskljucena...

  //Dohvacamo osi na Joystick-u na aplikaciji
  joystickX = param[0].asInt(); //Vrijednost X osi
  joystickY = param[1].asInt(); //Vrijednost Y osi

  if (joystickX != 128  || joystickY != 128) { //Ako joystick je pomaknut od sredista 
    //Ispisujemo ocitane vrijednosti na Serial Monitor
    Serial.print("X os: ");
    Serial.println(joystickX);
    Serial.print("Y os: ");
    Serial.println(joystickY);
    
    if (joystickX == 255) { //Ako je joystick pomaknut potpuno u lijevo
      Serial.println("Desno"); //Ispisujemo na serial monitor
      servoD.write(160); //Pisemo na serveo da se vrti najjace u smijeru suprotno od kazaljke na satu
      servoL.write(160); //Pisemo na servo da se vrti najjace u smijeru suprotno od kazaljke na satu
      Buzzer(); //Pozivamo funkciju buzzer
    }
    else if (joystickX == 0) {
      Serial.println("Ljevo"); //Ispisujemo na serial monitor
      servoD.write(20); //pisemo na servo da vrti najjace u smjeru kazaljke na satu
      servoL.write(20); //pisemo na servo da vrti najjace u smjeru kazaljke na satu
      Buzzer(); //Pozivamo funkciju Buzzer
    }
    else if (joystickY == 255) {
      Serial.println("Naprijed"); //Ispisujemo na serial monitor
      servoD.write(20); //pisemo na servo da vrti najjace u smjeru kazaljke na satu
      servoL.write(160); //pisemo na servo da vrti najjace u smjeru suprotnom od kazaljke na satu
      Buzzer(); //Pozivamo funkciju buzzer
    }
    else if (joystickY == 0) {
      Serial.println("Nazad"); //Ispisujemo na serial monitor
      servoD.write(160); //pisemo na servo da vrti najjace u smjeru suprotnom od kazaljke na satu
      servoL.write(20); //pisemo na servo da vrti najjace u smjeru kazaljke na satu
      Buzzer(); //Pozivamo funkciju buzzer
    }
    else {
      Serial.println("Error!!!");
      Serial.print("JoystickX = ");
      Serial.println(joystickX);
      Serial.print("JoystickY = ");
      Serial.println(joystickY);
    }
  }
  if (joystickX == 128 && joystickY == 128) { //Ako je joystick na sredini tj ne korisnik nekoristi ga...
      Serial.println("Joystick nista ili fail!"); //Ispisujemo Debug poruku na serial monitor
      servoD.write(90); //Na servo pisemo da miruje
      servoL.write(90); //Na servo pisemo da miruje
      Buzzer(); //pozivamo funkciju buzzer 
    }
  else {
    Serial.println("Error!!!");
    Serial.print("JoystickX = ");
    Serial.println(joystickX);
    Serial.print("JoystickY = ");
    Serial.println(joystickY);
  }
  }
}

Arduino program ovoga projekta možete preuzeti ovdje.

Autori

Projekt su izradili Teo Opić i Bruno Řehak uz mentorstvo Tomislava Krala iz Tehničke škole Daruvar.

Projekt je prijavljen na temu: Internet of Things: Kućni ljubimci i domaće životinje.

Drugi projekti