PRJ-03Oson60 daqiqa8 ta detalSimulyatorda bor

Toʻsiqni aylanib oʻtuvchi robot

Mashinaga HC-SR04 ultratovush datchigi qoʻshiladi. U oldinga yuradi, biror narsa 25 sm dan yaqin boʻlsa, orqaga yuradi, oʻngga buriladi va yana oldinga yuradi.

Robot nima qiladi

Robot oldinga yuradi. Toʻsiq 25 sm dan yaqin boʻlsa, u 0,3 soniya orqaga yuradi, 0,38 soniya joyida oʻngga aylanadi va yana oldinga yuradi.

VideoYouTubeʼda

Bu robot xona boʻylab oʻzi yuradi va yoʻlidagi har qanday narsadan burilib ketadi. Old tomonga oʻrnatilgan ultratovush datchigi robot oldidagi masofani oʻlchaydi. Biror narsa 25 sm dan yaqin boʻlsa, robot orqaga yuradi, oʻngga buriladi va yana oldinga yuradi. HC-SR04 masofani qanday oʻlchashini, holatlar mashinasi (state machine) robot ishini qanday tartibga solishini va millis() robotga yurib turib oʻlchash imkonini qanday berishini oʻrganasiz. Bu oson loyiha, u taxminan 60 daqiqa vaqt oladi.

Nima kerak

Ushbu loyiha uchun detallarHammasi toʻplamda bor: Arduino bilan 2WD robot-mashina toʻplami

Bu Birinchi yurish loyihasidagi mashina, faqat old tomoniga HC-SR04 ultratovush datchigi qoʻshilgan. Mashinangiz allaqachon boʻlsa, Marketdagi «Toʻsiqlarni aylanib oʻtish» qoʻshimchasini koʻring.

Qanday ishlaydi

1 Sezish: HC-SR04 masofani oʻlchaydi. 2 Oʻylash: Arduino Uno sketchingizni bajaradi. 3 Harakat: L298N motorlarni aylantiradi.

HC-SR04 masofani qanday oʻlchaydi

HC-SR04 ning old tomonida ikkita dumaloq qism bor. Biri ultratovush yuboradi: bu 40 kHz chastotali tovush, u odam eshita olmaydigan darajada yuqori. Ikkinchisi aks-sadoni tinglaydi. Bitta oʻlchash quyidagicha boʻladi:

  1. Uno TRIG pinini 10 mks davomida HIGH qiladi, datchik esa qisqa ultratovush signalini yuboradi.
  2. Datchik ECHO pinini HIGH qiladi va tinglaydi.
  3. Aks-sado qaytib kelganda datchik ECHO ni yana LOW qiladi.

Demak, tovush narsagacha borib-qaytishi uchun qancha vaqt kerak boʻlsa, ECHO shuncha vaqt HIGH boʻlib turadi. 20 °C da tovush taxminan 343 m/s tezlikda tarqaladi. Masofaning har bir santimetri uchun tovush borib-qaytib 2 sm yoʻl bosadi va bunga taxminan 58 mks ketadi. Shuning uchun santimetrdagi masofa mikrosekunddagi ECHO vaqtini 58 ga boʻlganga teng. Masalan, 1450 mks boʻlsa, 1450 / 58 = 25 sm.

Datchikning cheklovlari bor:

Cheklov Robot uchun nimani bildiradi
Oʻlchash oraligʻi taxminan 2 sm dan 4 m gacha bundan yaqin yoki uzoq narsalar notoʻgʻri qiymat beradi yoki umuman qiymat bermaydi
Tovush dastasining kengligi taxminan 15 gradus dastadan chetdagi narsalar koʻrinmaydi
Yumshoq yoki qiya sirtlar tovush yutiladi yoki burchak ostida chetga ketadi, shuning uchun aks-sado qaytmaydi
Signallar orasida taxminan 60 ms eski aks-sadolar soʻnishi uchun vaqt kerak

Holatlar mashinasi

Har bir lahzada robot uchta ishdan aynan bittasini bajaradi. Ularning har biri holat deyiladi:

Holat Motorlar Holat qachon tugaydi Keyingi holat
Drive (yurish) drive(190, 190): oldinga biror narsa 25 sm dan yaqin boʻlganda Back
Back (orqaga) drive(-160, -160): orqaga 300 ms oʻtganda Turn
Turn (burilish) drive(170, -170): joyida oʻngga aylanadi 380 ms oʻtganda Drive

Holatlar mashinasi shunday tuzilgan dastur: unda holatlar roʻyxati, har bir holatda robot nima qilishi va keyingi holatga oʻtish qoidalari bor. Har bir holat alohida, shuning uchun robotning xatti-harakatini oʻqish ham, oʻzgartirish ham oson.

Kutmasdan oʻlchash

loop() hech qachon delay() ni chaqirmaydi. U soniyasiga minglab marta bajariladi va har safar ikkita ishni qiladi:

  1. Vaqti kelgan boʻlsa, oʻlchaydi. Oxirgi oʻlchovdan beri 60 ms oʻtgan boʻlsa, masofani oʻlchaydi va natijani chiqaradi.
  2. Joriy holatni bajaradi. Motorlarni sozlaydi va holatni tugatish kerakmi, yoʻqmi, tekshiradi.

Qancha vaqt oʻtganini bilish uchun sketch millis() dan foydalanadi: bu Uno ishga tushganidan beri oʻtgan millisekundlar soni. Faqat oʻlchashning oʻzi biroz kutadi, chunki pulseIn() aks-sadoni kutadi. 25 sm narida turgan toʻsiq uchun bu taxminan 1,5 ms davom etadi. Oʻlchash oraligʻida hech narsa boʻlmasa, u 25 ms dan keyin kutishni toʻxtatadi. Bu qisqa kutish paytida motorlar ishlashda davom etadi.

Nega Back holati uchun shunchaki delay(300) yozib qoʻyilmaydi? Chunki shu kutish davomida robot koʻr boʻlib qoladi. Holatlar mashinasi bilan esa u har qanday holatda har 60 ms da oʻlchaydi. Bu sketch Back va Turn holatlarida oʻlchovlardan hali foydalanmaydi, lekin siz foydalanishingiz mumkin: birinchi topshiriqda robot yoʻl ochilishi bilanoq burilishni toʻxtatadi.

Yigʻish

1. Simulyatorda robotni tanlang

Oʻyinda boshidanoq bor boʻlgan Obstacle avoider mashinasining yuqori plastinasi (qavati) old qismida HC-SR04 allaqachon oʻrnatilgan. Uning simlari bu sahifadagidek ulanmagan, shuning uchun 2-qadamda ularni qaytadan ulaysiz.

Haqiqiy yigʻishda: «Birinchi yurish» loyihasidagi mashinangizdan boshlang. HC-SR04 ni old tomonga tekis, ikkala dumaloq qismi toʻgʻri oldinga qaraydigan qilib oʻrnating. U pastga qarasa, polni koʻradi. Yuqoriga qarasa, past toʻsiqlarni koʻrmay qoladi.

2. Datchikni ulang

QayerdanQayergaNima uchun
Batareya +L298N +12VMotorlar quvvati: toʻrtta AA batareyadan taxminan 6 V
Batareya -L298N GNDBatareya minusi
L298N +5VUno 5VDrayver stabilizatori Unoni quvvatlaydi: taxminan 4,4 V
L298N GNDUno GNDUmumiy yer: signallarga bir xil 0 V kerak
Uno D5L298N ENAChap motor tezligi (PWM); ENA jumperi olib qoʻyilgan
Uno D4L298N IN1Chap motor yoʻnalishi
Uno D7L298N IN2Chap motor yoʻnalishi
Uno D8L298N IN3Oʻng motor yoʻnalishi
Uno D12L298N IN4Oʻng motor yoʻnalishi
Uno D6L298N ENBOʻng motor tezligi (PWM); ENB jumperi olib qoʻyilgan
Chap motor M+L298N OUT1
Chap motor M-L298N OUT2
Oʻng motor M+L298N OUT4Ataylab almashtirilgan: bu motor koʻzgudagidek oʻrnatilgan
Oʻng motor M-L298N OUT3Ataylab almashtirilgan: bu motor koʻzgudagidek oʻrnatilgan
HC-SR04 VCCL298N +5VDatchik uchun 5 V
HC-SR04 GNDUno GNDYer (GND)
Uno D9HC-SR04 TRIGOʻlchashni boshlaydi: 10 mks impuls
Uno D10HC-SR04 ECHOAks-sadoning borib-qaytish vaqtiga teng impuls

Mashinaning ulanishi «Birinchi yurish» loyihasidagidek qoladi. Datchik toʻrtta sim bilan ulanadi: VCC L298N ning +5V klemmasiga, GND Unoning GND pinlaridan biriga, TRIG D9 ga, ECHO esa D10 ga. L298N ning +5V klemmasida Unoni taʼminlaydigan oʻsha 5 V bor, chunki u Unoning 5V piniga sim bilan ulangan.

Haqiqiy yigʻishda: +5V klemmasida Unoga boradigan sim allaqachon bor. Datchikning VCC simini oʻsha klemmaga, uning yoniga kiriting, keyin vintni burab mahkamlang. TRIG va ECHO ni ikki marta tekshiring, chunki ularni adashtirib qoʻyish oson.

3. Yuklang va sinab koʻring

«Kod» boʻlimini oching, shu sahifadagi ObstacleAvoider sketchini qoʻying, «Tekshirish» tugmasini, keyin «Yuklash» tugmasini bosing.

Haqiqiy yigʻishda: mashinani gʻildiraklari havoda turadigan qilib quti ustiga qoʻying, USB kabelni ulang va sketchni yuklang. Serial Monitor (port monitori) oynasini 9600 bod tezlikda oching. Qoʻlingizni datchik oldida harakatlantiring: sonlar qoʻlingiz harakatiga qarab oʻzgaradi. Qoʻlingiz 25 sm dan yaqinroq boʻlganda gʻildiraklar avval orqaga, keyin joyida oʻngga burilishdagidek aylanadi.

4. Robotni yurgizing

Toʻsiqlari bor arenada robotni ishga tushiring. Robot biror narsa 25 sm dan yaqin kelguncha yuradi, keyin orqaga yuradi, buriladi va yana oldinga yuradi. Serial Monitor oynasini oching: robot har 60 ms da santimetrdagi bitta masofani chiqaradi. 400 qiymati aks-sado qaytmaganini, yaʼni taxminan 4 m ichida hech narsa yoʻqligini bildiradi. Masofa jonli koʻrsatkichda ham koʻrinadi.

Haqiqiy yigʻishda: USB kabelni uzing va mashinani polga, bir nechta quti yoki kitob orasiga qoʻying. Qattiq, tekis narsalar eng yaxshi aks-sado beradi.

5. Sonlarni sozlang

Sozlama Nimani belgilaydi Sinab koʻring
STOP_CM = 25 toʻsiq qanchalik yaqin kela olishini robot narsalarga urilsa, 35
CRUISE = 190 oldinga yurish tezligini xotirjamroq robot uchun 150
BACK_MS = 300 qancha vaqt orqaga yurishini tor joylarda kattaroq qiymat
TURN_MS = 380 qancha vaqt aylanishini kattaroq burilish uchun 600

Tezroq robot uchun STOP_CM kattaroq boʻlishi kerak, chunki u toʻxtashi uchun koʻproq masofa talab qiladi.

Kod

ObstacleAvoider.ino
// Obstacle avoider: drive ahead; when something is close, back off and turn.
// Written without delay() in loop(): a state machine and millis() timers,
// so the robot keeps measuring while it moves.
// L298N: ENA -> D5, IN1 -> D4, IN2 -> D7 (left), ENB -> D6, IN3 -> D8, IN4 -> D12 (right)
// HC-SR04: TRIG -> D9, ECHO -> D10

const byte ENA = 5, IN1 = 4, IN2 = 7;
const byte ENB = 6, IN3 = 8, IN4 = 12;
const byte TRIG = 9, ECHO = 10;

const int CRUISE = 190;               // forward speed, 0..255
const int STOP_CM = 25;               // closer than this: avoid it
const unsigned long PING_MS = 60;     // the HC-SR04 needs a pause between pings
const unsigned long BACK_MS = 300;
const unsigned long TURN_MS = 380;

enum class State : byte { Drive, Back, Turn };
State state = State::Drive;
unsigned long stateStart = 0;
unsigned long lastPing = 0;
int distanceCm = 400;

void setMotor(byte enablePin, byte inA, byte inB, int speed) {
  speed = constrain(speed, -255, 255);
  digitalWrite(inA, speed > 0);
  digitalWrite(inB, speed < 0);
  analogWrite(enablePin, abs(speed));
}

void drive(int left, int right) {
  setMotor(ENA, IN1, IN2, left);
  setMotor(ENB, IN3, IN4, right);
}

// Distance in centimetres; 400 when no echo came back (nothing within about 4 m).
int readDistanceCm() {
  digitalWrite(TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG, HIGH);            // a 10 microsecond pulse starts a measurement
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  unsigned long us = pulseIn(ECHO, HIGH, 25000UL);  // wait at most 25 ms
  if (us == 0) return 400;
  return us / 58;                      // sound goes there and back: 58 us per cm
}

void enter(State next) {
  state = next;
  stateStart = millis();
  if (next == State::Drive) lastPing = 0;  // measure again before driving on
}

void setup() {
  const byte pins[] = {ENA, IN1, IN2, ENB, IN3, IN4, TRIG};
  for (byte pin : pins) pinMode(pin, OUTPUT);
  pinMode(ECHO, INPUT);
  Serial.begin(9600);
}

void loop() {
  unsigned long now = millis();
  if (now - lastPing >= PING_MS) {
    lastPing = now;
    distanceCm = readDistanceCm();
    Serial.println(distanceCm);
  }

  switch (state) {
    case State::Drive:
      drive(CRUISE, CRUISE);
      if (distanceCm < STOP_CM) enter(State::Back);
      break;
    case State::Back:
      drive(-160, -160);
      if (now - stateStart >= BACK_MS) enter(State::Turn);
      break;
    case State::Turn:
      drive(170, -170);                // spin right on the spot
      if (now - stateStart >= TURN_MS) enter(State::Drive);
      break;
  }
}

Holat va taymerlar

enum class State : byte { Drive, Back, Turn };
State state = State::Drive;
unsigned long stateStart = 0;
unsigned long lastPing = 0;
int distanceCm = 400;

enum class State uchta holatga nom beradi, : byte esa holatni bitta baytga joylaydi. state joriy holatni saqlaydi, robot Drive holatidan boshlaydi. stateStart joriy holat qachon boshlanganini, lastPing esa oxirgi oʻlchov qachon olinganini eslab qoladi. Ikkalasi ham unsigned long turida, millis() ham aynan shu turdagi qiymat qaytaradi. distanceCm 400 dan boshlanadi, bu «hech narsa koʻrinmadi» degani.

readDistanceCm(): bitta oʻlchov

  digitalWrite(TRIG, HIGH);            // a 10 microsecond pulse starts a measurement
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  unsigned long us = pulseIn(ECHO, HIGH, 25000UL);  // wait at most 25 ms
  if (us == 0) return 400;
  return us / 58;                      // sound goes there and back: 58 us per cm

Bu qatorlardan oldin TRIG 2 mks davomida LOW holatda ushlab turiladi, shunda ishga tushirish impulsi toza boshlanadi. pulseIn() ECHO qancha vaqt HIGH boʻlib turganini mikrosekundlarda oʻlchaydi. Agar 25 ms ichida aks-sado qaytmasa, u 0 qaytaradi, funksiya esa 400 qaytaradi. Aks holda funksiya santimetrlarni olish uchun natijani 58 ga boʻladi.

enter(): holatni almashtirish

void enter(State next) {
  state = next;
  stateStart = millis();
  if (next == State::Drive) lastPing = 0;  // measure again before driving on
}

Holat har safar enter() orqali almashadi. U yangi holatni va u boshlangan vaqtni saqlaydi. Robot Drive holatiga qaytganda lastPing = 0 qatori tufayli loop() ning keyingi aylanishida albatta yangi oʻlchov olinadi. Shunday qilib, robot burilishdan keyin oʻlchangan yangi masofaga qarab qaror qabul qiladi.

loop(): avval oʻlchash, keyin harakat

  unsigned long now = millis();
  if (now - lastPing >= PING_MS) {
    lastPing = now;
    distanceCm = readDistanceCm();
    Serial.println(distanceCm);
  }

now - lastPing >= PING_MS «60 ms oʻtdimi?» deb soʻraydi. Ayirish shaklida yozilgani uchun bu shart taxminan 49,7 kundan keyin millis() yana 0 dan boshlanganda ham toʻgʻri ishlayveradi.

Keyin har bir holat uchun bittadan case boʻlgan switch keladi. Drive ikkala motorni CRUISE tezligiga qoʻyadi va distanceCm STOP_CM dan kichik boʻlsa, Back holatiga oʻtadi. Back 160 tezlik bilan orqaga yuradi va BACK_MS dan keyin Turn holatiga oʻtadi. Turn robotni joyida oʻngga aylantiradi, bunda chap gʻildirak oldinga, oʻng gʻildirak orqaga aylanadi, TURN_MS dan keyin esa Drive holatiga oʻtadi. setMotor() va drive() «Birinchi yurish» loyihasidagi bilan bir xil.

Agar ishlamasa

  • Serial Monitor doim 400 koʻrsatyapti. Oʻlchash oraligʻida hech narsa yoʻq yoki datchik notoʻgʻri ulangan. VCC va GND ni tekshiring, TRIG D9 ga, ECHO esa D10 ga ulanganini ham tekshiring.
  • Serial Monitor gʻalati belgilar koʻrsatyapti (haqiqiy yigʻish). Unda 9600 bod tanlang, bu Serial.begin(9600) dagi tezlikning aynan oʻzi.
  • Robot burchak ostida duch kelgan devorlarga borib urilyapti. Qiya devor tovushni datchikdan chetga qaytaradi. Pardalar kabi yumshoq narsalar esa tovushni yutadi. STOP_CM ni oshiring yoki CRUISE ni kamaytiring.
  • Oldida hech narsa yoʻq, lekin robot orqaga yuryapti. Datchik polni koʻrayotgan boʻlishi mumkin, shuning uchun uni tekis oʻrnating. Datchik oldida osilib turgan sim ham aks-sado qaytarishi mumkin.
  • Robot stul oyoqlariga yoki quti burchagiga urilyapti. Ingichka narsalar kam tovush qaytaradi, tor dastadan chetdagi narsalar esa koʻrinmaydi. Bu datchikning cheklovi.
  • Gʻildirak notoʻgʻri tomonga aylanyapti. Birinchi yurish loyihasidagidek oʻsha motorning ikkita simini almashtiring.
  • Robot orqaga yura boshlaganda qayta ishga tushib qolyapti. Oldinga yurishdan birdaniga orqaga oʻtish katta tok talab qiladi va batareya kuchlanishi pasayib ketadi. Yangi batareyalar va qisqa quvvat simlaridan foydalaning. Drayver yonida +12V va GND orasiga 100–470 mkF li kondensator ulang, uning - oyogʻi GND ga ulansin. Robotlar nega qayta ishga tushib qolishi haqidagi maqolani oʻqing.

Keyingi qadamlar

Bu robot faqat «ha yoki yoʻq» deb javob beradi: 25 sm dan yaqinmi yoki yoʻqmi. Keyingi loyiha tezlikni tanlash uchun masofaning oʻzidan foydalanadi: bu masofa saqlovchi robot.

Taymerlar va holatlar haqida millis() va holatlar darsida koʻproq bilib oling. Datchik haqida HC-SR04 darsini va ultratovush datchiklari qanday koʻrishi haqidagi maqolani oʻqing.

Yanada yaxshilang

  1. Robot Turn holatidan belgilangan vaqt oʻtgach emas, yoʻl ochilishi bilanoq chiqsin, masalan, masofa 50 sm dan oshganda.
  2. Robot tasodifiy ravishda chapga yoki oʻngga burilsin: random(2) 0 yoki 1 beradi.
  3. Toʻsiq 25 dan 50 sm gacha masofada boʻlsa, robot sekinroq yursin.