שלט רחוק: IR, RF ו-Bluetooth · כל קובץ בעמוד משלו, עם הקוד המלא וכפתור הורדה.Remote control: IR, RF & Bluetooth · one file per page, with the full code and a download button.
⬇ להוריד הכל (zip)Download all (zip)
פנוי → קדימה. חסום → אחורה, פנייה, וממשיכים. אותו חיווט כמו בשיעור 2.Clear → forward. Blocked → back up, turn, carry on. Same wiring as Lesson 2.
/* Robotika – Lesson 3 · LEVEL 0: Finish the self-driving car ---------------------------------------------------------- Last lesson our car only STOPPED in front of an obstacle. A real self-driving car should get itself OUT of trouble: clear ahead -> drive forward blocked -> back up a little, turn away, then carry on Same 4-motor car + L298N H-bridge + front HC-SR04 as Lesson 2. We only add three new moves (backward, turnLeft, turnRight) and a smarter decision. The wiring is EXACTLY the same as Lesson 2. HOW THE MOTORS ARE WIRED (important): The car has 4 motors but only ONE L298N, which has TWO channels. The two LEFT motors are wired together into channel A, and the two RIGHT motors are wired together into channel B. So in code there are only two "sides" to control (left, right) - exactly what the functions below do. Two motors share one channel, so they pull more current: use a proper motor battery, not the Arduino's 5V. (Tip: if the two motors on a side fight each other, flip the two wires of ONE of them so both spin the same way.) Wiring (unchanged from Lesson 2): HC-SR04: Trig -> D9 Echo -> D10 VCC -> 5V GND -> GND L298N channel A (both LEFT motors -> OUT1/OUT2): ENA -> D5 (PWM) IN1 -> D2 IN2 -> D3 L298N channel B (both RIGHT motors -> OUT3/OUT4): ENB -> D6 (PWM) IN3 -> D4 IN4 -> D7 L298N power: motor battery + -> 12V battery - -> GND L298N GND <-> Arduino GND (MUST share ground)*/// --- HC-SR04 (front) ---const int trigPin = 9;const int echoPin = 10;// --- L298N motor driver ---const int ENA = 5; // left speed (PWM)const int IN1 = 2;const int IN2 = 3;const int IN3 = 4;const int IN4 = 7;const int ENB = 6; // right speed (PWM)const int SPEED = 160; // 0..255 – driving speedconst int STOP_CM = 15; // "something is in the way" distance (cm)void setup() { Serial.begin(9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); stopCar(); delay(2000); // wait 2s before we start driving}void loop() { int distanceCm = getDistanceCm(); Serial.print("Distance: "); Serial.print(distanceCm); Serial.println(" cm"); // ---- the decision ---- if (distanceCm <= STOP_CM) { // blocked: get out of trouble stopCar(); delay(200); backward(); delay(400); // reverse a little stopCar(); delay(200); turnRight(); delay(400); // spin away from the obstacle stopCar(); delay(200); // next loop() checks again and drives on if it's now clear } else { forward(); // path is clear -> keep driving }}// ---------- the four moves ----------// Each "side" here = BOTH motors on that side (they share one L298N channel).void forward() { digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); // left side forward digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); // right side forward analogWrite(ENA, SPEED); analogWrite(ENB, SPEED);}void backward() { digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); // left side back digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); // right side back analogWrite(ENA, SPEED); analogWrite(ENB, SPEED);}void turnRight() { digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); // left side forward digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); // right side back -> spins right analogWrite(ENA, SPEED); analogWrite(ENB, SPEED);}void turnLeft() { digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); // left side back digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); // right side forward -> spins left analogWrite(ENA, SPEED); analogWrite(ENB, SPEED);}void stopCar() { analogWrite(ENA, 0); analogWrite(ENB, 0); digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);}// ---------- the sensor ----------int getDistanceCm() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH, 25000); // timeout so we never get stuck if (duration == 0) return 999; // no echo = nothing close = clear return duration * 0.0343 / 2;}
פותחים Serial Monitor (9600), לוחצים ▲ ▼ ◀ ▶ OK ורושמים את הקודים.Open the Serial Monitor (9600), press ▲ ▼ ◀ ▶ OK and write the codes down.
/* Robotika – Lesson 3 · LEVEL 1a: Learn your IR remote's button codes ------------------------------------------------------------------- Before we can DRIVE with the remote, we need to know what number each button sends. Every remote is a little different, so we read them once and write the numbers down. Upload this, open Tools -> Serial Monitor (9600 baud), point the small remote at the receiver and press each button. Copy the HEX code shown for UP / DOWN / LEFT / RIGHT / OK into the next sketch. Library: "IRremote" by shirriff / Armin Joachimsmeyer (Sketch -> Include Library -> Manage Libraries -> search "IRremote") Wiring (IR receiver module, e.g. VS1838 / HX-M121): OUT/S -> D8 VCC/+ -> 5V GND/- -> GND*/#include <IRremote.h>const int IR_RECEIVE_PIN = 8;void setup() { Serial.begin(9600); IrReceiver.begin(IR_RECEIVE_PIN); Serial.println("Point the remote and press buttons...");}void loop() { if (IrReceiver.decode()) { // the "command" byte is the part that changes per button Serial.print("command (HEX): 0x"); Serial.println(IrReceiver.decodedIRData.command, HEX); IrReceiver.resume(); // ready for the next button }}
אותן פונקציות מנוע — רק הקלט השתנה. ממלאים את 5 הקודים משלב 1א.Same motor functions — only the input changed. Fill in the 5 codes from 1a.
/* Robotika – Lesson 3 · LEVEL 1b: Drive the car with an IR remote --------------------------------------------------------------- THE BIG IDEA: the motor functions are the SAME ones from the self-driving car (forward/back/left/right/stop). Last time the SENSOR decided which one to call. Now YOU decide, by pressing a button. Only the INPUT changed. IR = infrared light, just like a TV remote. It needs a clear line of sight to the receiver, and only goes one way (remote -> car). 1) First run level1_ir_read_codes.ino and fill in the 5 codes below. 2) Then upload this. Point the remote at the car and drive. Motors: 4 motors, ONE L298N. Both LEFT motors share channel A, both RIGHT motors share channel B - so the code controls just two sides (as always). Wiring: IR receiver: OUT -> D8 VCC -> 5V GND -> GND L298N ch. A (both LEFT motors): ENA D5, IN1 D2, IN2 D3 L298N ch. B (both RIGHT motors): ENB D6, IN3 D4, IN4 D7*/#include <IRremote.h>const int IR_RECEIVE_PIN = 8;// --- L298N motor driver (same pins as Lesson 2) ---const int ENA = 5, IN1 = 2, IN2 = 3, IN3 = 4, IN4 = 7, ENB = 6;const int SPEED = 160;// >>> FILL THESE IN from level1_ir_read_codes.ino (your remote's codes) <<<const uint8_t BTN_UP = 0x18;const uint8_t BTN_DOWN = 0x52;const uint8_t BTN_LEFT = 0x08;const uint8_t BTN_RIGHT = 0x5A;const uint8_t BTN_OK = 0x1C;unsigned long lastCmd = 0; // when we last heard a buttonconst int HOLD_MS = 200; // keep moving this long after a pressvoid setup() { Serial.begin(9600); IrReceiver.begin(IR_RECEIVE_PIN); pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); stopCar();}void loop() { if (IrReceiver.decode()) { uint8_t cmd = IrReceiver.decodedIRData.command; if (cmd == BTN_UP) forward(); else if (cmd == BTN_DOWN) backward(); else if (cmd == BTN_LEFT) turnLeft(); else if (cmd == BTN_RIGHT) turnRight(); else if (cmd == BTN_OK) stopCar(); lastCmd = millis(); IrReceiver.resume(); // ready for the next button } // if no button for a moment, stop (so it doesn't run away) if (millis() - lastCmd > HOLD_MS) stopCar();}// ---------- the four moves (identical to the self-driving car) ----------void forward() { digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW); digitalWrite(IN3,HIGH);digitalWrite(IN4,LOW); analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void backward() { digitalWrite(IN1,LOW); digitalWrite(IN2,HIGH);digitalWrite(IN3,LOW); digitalWrite(IN4,HIGH);analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void turnRight(){ digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW); digitalWrite(IN3,LOW); digitalWrite(IN4,HIGH);analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void turnLeft() { digitalWrite(IN1,LOW); digitalWrite(IN2,HIGH);digitalWrite(IN3,HIGH);digitalWrite(IN4,LOW); analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void stopCar() { analogWrite(ENA,0);analogWrite(ENB,0); digitalWrite(IN1,LOW);digitalWrite(IN2,LOW);digitalWrite(IN3,LOW);digitalWrite(IN4,LOW); }
ארדואינו שני עם 4 כפתורים ששולח קוד רדיו לכל כיוון.A second Arduino with 4 buttons that sends a radio code per direction.
/* Robotika – Lesson 3 · LEVEL 2a: RF433 remote (the TRANSMITTER) -------------------------------------------------------------- With IR the remote came ready-made. With RF433 we BUILD the remote too: a second Arduino with 4 buttons that sends a radio code for each direction. RF = radio waves at 433 MHz. Unlike IR it does NOT need line of sight, goes through walls, and reaches much farther. Still one-way (remote -> car). This board is the REMOTE. The car runs level2_rf_car.ino. Library: "rc-switch" (Manage Libraries -> search "rc-switch") Wiring (this remote board): RF transmitter (FS1000A): DATA -> D10 VCC -> 5V GND -> GND (a ~17 cm wire as antenna helps a lot) Buttons to GND, using the internal pull-ups: UP -> D2 DOWN -> D3 LEFT -> D4 RIGHT -> D5 (STOP = no button)*/#include <RCSwitch.h>RCSwitch mySwitch = RCSwitch();const int TX_PIN = 10;const int BTN_UP = 2, BTN_DOWN = 3, BTN_LEFT = 4, BTN_RIGHT = 5;// the codes we agree on with the car (any distinct numbers)const long CODE_STOP = 10, CODE_UP = 11, CODE_DOWN = 12, CODE_LEFT = 13, CODE_RIGHT = 14;void setup() { mySwitch.enableTransmit(TX_PIN); pinMode(BTN_UP, INPUT_PULLUP); pinMode(BTN_DOWN, INPUT_PULLUP); pinMode(BTN_LEFT, INPUT_PULLUP); pinMode(BTN_RIGHT, INPUT_PULLUP);}void loop() { long code = CODE_STOP; // nothing pressed -> tell car to stop if (digitalRead(BTN_UP) == LOW) code = CODE_UP; else if (digitalRead(BTN_DOWN) == LOW) code = CODE_DOWN; else if (digitalRead(BTN_LEFT) == LOW) code = CODE_LEFT; else if (digitalRead(BTN_RIGHT) == LOW) code = CODE_RIGHT; mySwitch.send(code, 24); // send the 24-bit code over the air delay(100); // ~10 times a second}
שינוי חיווט אחד: IN1 עובר מ-D2 ל-D8, ו-DATA של המקלט נכנס ל-D2.One wiring change: IN1 moves from D2 to D8, and the receiver's DATA goes on D2.
/* Robotika – Lesson 3 · LEVEL 2b: RF433 remote (the CAR / RECEIVER) ---------------------------------------------------------------- The car listens for radio codes from level2_rf_transmitter.ino and drives accordingly. Same motor functions as always — only the input changed again (now it arrives by radio). !! ONE WIRING CHANGE !! rc-switch must read the radio on an INTERRUPT pin. On the Uno those are D2 and D3 — but our motor wire IN1 was on D2. So we MOVE IN1 from D2 to D8, and put the RF receiver's DATA on D2. Everything else stays the same. Library: "rc-switch" Motors: 4 motors, ONE L298N. Both LEFT motors share channel A, both RIGHT motors share channel B - so the code controls just two sides (as always). Wiring (the car): RF receiver (XY-MK-5V): DATA -> D2 VCC -> 5V GND -> GND L298N ch. A (both LEFT motors): ENA D5, IN1 D8 (moved!), IN2 D3 L298N ch. B (both RIGHT motors): ENB D6, IN3 D4, IN4 D7*/#include <RCSwitch.h>RCSwitch mySwitch = RCSwitch();// --- L298N motor driver (IN1 moved to D8 to free the interrupt pin D2) ---const int ENA = 5, IN1 = 8, IN2 = 3, IN3 = 4, IN4 = 7, ENB = 6;const int SPEED = 160;// same codes the transmitter agreed onconst long CODE_STOP = 10, CODE_UP = 11, CODE_DOWN = 12, CODE_LEFT = 13, CODE_RIGHT = 14;unsigned long lastCmd = 0;const int HOLD_MS = 300;void setup() { Serial.begin(9600); mySwitch.enableReceive(0); // interrupt 0 = pin D2 pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); stopCar();}void loop() { if (mySwitch.available()) { long code = mySwitch.getReceivedValue(); if (code == CODE_UP) forward(); else if (code == CODE_DOWN) backward(); else if (code == CODE_LEFT) turnLeft(); else if (code == CODE_RIGHT) turnRight(); else if (code == CODE_STOP) stopCar(); lastCmd = millis(); mySwitch.resetAvailable(); } // radio dropped out? stop, so the car never runs away if (millis() - lastCmd > HOLD_MS) stopCar();}// ---------- the four moves (identical, just IN1 is now D8) ----------void forward() { digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW); digitalWrite(IN3,HIGH);digitalWrite(IN4,LOW); analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void backward() { digitalWrite(IN1,LOW); digitalWrite(IN2,HIGH);digitalWrite(IN3,LOW); digitalWrite(IN4,HIGH);analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void turnRight(){ digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW); digitalWrite(IN3,LOW); digitalWrite(IN4,HIGH);analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void turnLeft() { digitalWrite(IN1,LOW); digitalWrite(IN2,HIGH);digitalWrite(IN3,HIGH);digitalWrite(IN4,LOW); analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void stopCar() { analogWrite(ENA,0);analogWrite(ENB,0); digitalWrite(IN1,LOW);digitalWrite(IN2,LOW);digitalWrite(IN3,LOW);digitalWrite(IN4,LOW); }
מודול HC-05 + אפליקציית Dabble. נשלים את החיבור בשיעור הבא.HC-05 module + the Dabble app. We finish wiring it next lesson.
/* Robotika – Lesson 3 · FINALE (demo, we finish it next lesson): Drive the car straight from your PHONE over Bluetooth -------------------------------------------------------------- No separate remote at all — your phone IS the remote. A Bluetooth module (HC-05 / HC-06) on the car talks to the free "Dabble" app, whose on-screen GamePad sends the direction. Same motor functions again; only the input changed one last time. Setup: 1) Install "Dabble" from the app store on your phone. 2) Library: "Dabble" (Manage Libraries -> search "Dabble"). 3) In the app: connect to the HC-05, open the GamePad module. Motors: 4 motors, ONE L298N. Both LEFT motors share channel A, both RIGHT motors share channel B - so the code controls just two sides (as always). Wiring (the car): HC-05: VCC -> 5V GND -> GND HC-05 TXD -> D11 HC-05 RXD <- D12 through a 1k/2k divider (the module's RX wants ~3.3V) L298N ch. A (both LEFT motors): ENA D5, IN1 D2, IN2 D3 L298N ch. B (both RIGHT motors): ENB D6, IN3 D4, IN4 D7 !! IMPORTANT: on the Uno, Dabble talks to the module through SoftwareSerial, NOT D0/D1. Its default pins are D2/D3 - our motor pins - so we move it to D11/D12 with Dabble.begin(9600, 11, 12). Nothing to unplug for upload. Android only: iPhone Dabble works with BLE modules (HM-10), not HC-05.*/#define CUSTOM_SETTINGS#define INCLUDE_GAMEPAD_MODULE#include <Dabble.h>// --- L298N motor driver (same pins as Lesson 2) ---const int ENA = 5, IN1 = 2, IN2 = 3, IN3 = 4, IN4 = 7, ENB = 6;const int SPEED = 160;void setup() { Dabble.begin(9600, 11, 12); // HC-05 on RX = D11, TX = D12 pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(ENB, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); stopCar();}void loop() { Dabble.processInput(); // read what the phone sent if (GamePad.isUpPressed()) forward(); else if (GamePad.isDownPressed()) backward(); else if (GamePad.isLeftPressed()) turnLeft(); else if (GamePad.isRightPressed()) turnRight(); else stopCar(); // finger off -> stop}// ---------- the four moves (identical to every other version) ----------void forward() { digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW); digitalWrite(IN3,HIGH);digitalWrite(IN4,LOW); analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void backward() { digitalWrite(IN1,LOW); digitalWrite(IN2,HIGH);digitalWrite(IN3,LOW); digitalWrite(IN4,HIGH);analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void turnRight(){ digitalWrite(IN1,HIGH);digitalWrite(IN2,LOW); digitalWrite(IN3,LOW); digitalWrite(IN4,HIGH);analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void turnLeft() { digitalWrite(IN1,LOW); digitalWrite(IN2,HIGH);digitalWrite(IN3,HIGH);digitalWrite(IN4,LOW); analogWrite(ENA,SPEED);analogWrite(ENB,SPEED); }void stopCar() { analogWrite(ENA,0);analogWrite(ENB,0); digitalWrite(IN1,LOW);digitalWrite(IN2,LOW);digitalWrite(IN3,LOW);digitalWrite(IN4,LOW); }