שיעור 3 — קבצי הקודLesson 3 — code files
פותחים כל קובץ בתיקייה הנושאת את אותו שם ב־Arduino IDE. בוחרים Uno ופורט מתאים. אין צורך בספריות חיצוניות.Open each file inside its same-named folder in Arduino IDE. Select Uno and the appropriate port. No external libraries are required.
הורדת כל חמשת הסקצ׳ים — ZIPDownload all five sketches — ZIP
שלב 1 — מנוע אחדLevel 1 — one motor
ניסוי חד־פעמי בערוץ A: כיוון אחד, גלישה, כיוון הפוך. המתינו לעצירה לפני היפוך.One-shot channel A test: one direction, coast, reverse. Wait for the wheel to stop before reversal.
הצגת הקוד והעתקהView and copy code
// Arduino Uno + L298N. ENA/ENB jumper caps removed.
// Disconnect motor power while wiring/uploading; begin with wheels raised.
// Verify motor/module ratings and module-specific logic-supply wiring.
const byte ENA = 5, IN1 = 2, IN2 = 3;
const byte ENB = 6, IN3 = 4, IN4 = 7;
// Calibrate each side with wheels raised. These depend on physical mounting.
const bool LEFT_REVERSED = false;
const bool RIGHT_REVERSED = false;
void coastAll() {
digitalWrite(ENA, LOW);
digitalWrite(ENB, LOW);
}
void beginMotors() {
pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT);
coastAll();
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
void setMotor(byte en, byte a, byte b, int command, bool reversed) {
command = constrain(command, -255, 255);
if (reversed) command = -command;
digitalWrite(en, LOW); // disable before changing direction inputs
digitalWrite(a, command > 0 ? HIGH : LOW);
digitalWrite(b, command < 0 ? HIGH : LOW);
if (command != 0) analogWrite(en, abs(command));
// command == 0 means COAST. brakeAll() is a separate operation.
}
void drive(int left, int right) {
setMotor(ENA, IN1, IN2, left, LEFT_REVERSED);
setMotor(ENB, IN3, IN4, right, RIGHT_REVERSED);
}
void brakeAll() {
coastAll();
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
digitalWrite(ENA, HIGH); digitalWrite(ENB, HIGH);
// L298: enabled + equal direction inputs = electrical brake.
// Braking generates current; check load ratings. Not a holding brake.
}
void setup() {
beginMotors();
delay(3000); // switch on motor power; wheels must be raised
setMotor(ENA, IN1, IN2, 160, LEFT_REVERSED);
delay(1000);
coastAll(); delay(3000); // verify wheel is stopped before reverse
setMotor(ENA, IN1, IN2, -160, LEFT_REVERSED);
delay(1000);
coastAll();
}
void loop() {} // reset to repeat; do not hold the shaft stalledשלב 2 — נסיעה ופנייהLevel 2 — drive and turn
בדיקה חד־פעמית של שני הצדדים; כיילו קוטביות לפני הנחה על הרצפה.One-shot two-side test; calibrate polarity before floor testing.
הצגת הקוד והעתקהView and copy code
// Arduino Uno + L298N. ENA/ENB jumper caps removed.
// Disconnect motor power while wiring/uploading; begin with wheels raised.
// Verify motor/module ratings and module-specific logic-supply wiring.
const byte ENA = 5, IN1 = 2, IN2 = 3;
const byte ENB = 6, IN3 = 4, IN4 = 7;
// Calibrate each side with wheels raised. These depend on physical mounting.
const bool LEFT_REVERSED = false;
const bool RIGHT_REVERSED = false;
void coastAll() {
digitalWrite(ENA, LOW);
digitalWrite(ENB, LOW);
}
void beginMotors() {
pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT);
coastAll();
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
void setMotor(byte en, byte a, byte b, int command, bool reversed) {
command = constrain(command, -255, 255);
if (reversed) command = -command;
digitalWrite(en, LOW); // disable before changing direction inputs
digitalWrite(a, command > 0 ? HIGH : LOW);
digitalWrite(b, command < 0 ? HIGH : LOW);
if (command != 0) analogWrite(en, abs(command));
// command == 0 means COAST. brakeAll() is a separate operation.
}
void drive(int left, int right) {
setMotor(ENA, IN1, IN2, left, LEFT_REVERSED);
setMotor(ENB, IN3, IN4, right, RIGHT_REVERSED);
}
void brakeAll() {
coastAll();
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
digitalWrite(ENA, HIGH); digitalWrite(ENB, HIGH);
// L298: enabled + equal direction inputs = electrical brake.
// Braking generates current; check load ratings. Not a holding brake.
}
void setup() {
beginMotors(); delay(3000);
drive(160, 160); delay(800);
brakeAll(); delay(1500);
drive(0, 160); delay(400); // left coasts, right drives: turn left
brakeAll(); delay(1500);
coastAll();
}
void loop() {}שלב 3 — חיישן מרחקLevel 3 — distance sensor
בדקו תחילה בלי הפעלת מנועים. Serial Monitor: 9600 baud. TRIG=D9, ECHO=D10.Test with motor power off first. Serial Monitor: 9600 baud. TRIG=D9, ECHO=D10.
הצגת הקוד והעתקהView and copy code
// Arduino Uno, HC-SR04: VCC=5V, GND=GND, TRIG=D9, ECHO=D10.
const byte TRIG = 9, ECHO = 10;
const unsigned long ECHO_TIMEOUT_US = 25000UL;
void beginSonar() {
pinMode(TRIG, OUTPUT); digitalWrite(TRIG, LOW);
pinMode(ECHO, INPUT);
}
float readDistanceCm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
unsigned long us = pulseIn(ECHO, HIGH, ECHO_TIMEOUT_US);
if (us == 0) return -1.0; // invalid, NOT a clear path
float cm = us / 58.0;
if (cm < 2.0 || cm > 400.0) return -1.0;
return cm;
}
void printDistance(float cm) {
if (cm < 0) Serial.println(F("INVALID: no reliable echo"));
else { Serial.print(cm); Serial.println(F(" cm")); }
}
void setup() { Serial.begin(9600); beginSonar(); }
void loop() {
printDistance(readDistanceCm());
delay(70); // >60 ms between measurement starts
}שלב 4 — עצירה מול מכשולLevel 4 — obstacle stop
בלימה במדידה לא תקינה או עד 20 ס״מ; חזרה לנסיעה מ־25 ס״מ. מהירות וספים דורשים כיול.Brake on invalid data or at 20 cm; resume at 25 cm. Speed and thresholds require calibration.
הצגת הקוד והעתקהView and copy code
// Arduino Uno + L298N. ENA/ENB jumper caps removed.
// Disconnect motor power while wiring/uploading; begin with wheels raised.
// Verify motor/module ratings and module-specific logic-supply wiring.
const byte ENA = 5, IN1 = 2, IN2 = 3;
const byte ENB = 6, IN3 = 4, IN4 = 7;
// Calibrate each side with wheels raised. These depend on physical mounting.
const bool LEFT_REVERSED = false;
const bool RIGHT_REVERSED = false;
void coastAll() {
digitalWrite(ENA, LOW);
digitalWrite(ENB, LOW);
}
void beginMotors() {
pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT);
coastAll();
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
void setMotor(byte en, byte a, byte b, int command, bool reversed) {
command = constrain(command, -255, 255);
if (reversed) command = -command;
digitalWrite(en, LOW); // disable before changing direction inputs
digitalWrite(a, command > 0 ? HIGH : LOW);
digitalWrite(b, command < 0 ? HIGH : LOW);
if (command != 0) analogWrite(en, abs(command));
// command == 0 means COAST. brakeAll() is a separate operation.
}
void drive(int left, int right) {
setMotor(ENA, IN1, IN2, left, LEFT_REVERSED);
setMotor(ENB, IN3, IN4, right, RIGHT_REVERSED);
}
void brakeAll() {
coastAll();
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
digitalWrite(ENA, HIGH); digitalWrite(ENB, HIGH);
// L298: enabled + equal direction inputs = electrical brake.
// Braking generates current; check load ratings. Not a holding brake.
}
const byte TRIG = 9, ECHO = 10;
const unsigned long ECHO_TIMEOUT_US = 25000UL;
void beginSonar() {
pinMode(TRIG, OUTPUT); digitalWrite(TRIG, LOW);
pinMode(ECHO, INPUT);
}
float readDistanceCm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
unsigned long us = pulseIn(ECHO, HIGH, ECHO_TIMEOUT_US);
if (us == 0) return -1.0; // invalid, NOT a clear path
float cm = us / 58.0;
if (cm < 2.0 || cm > 400.0) return -1.0;
return cm;
}
void printDistance(float cm) {
if (cm < 0) Serial.println(F("INVALID: no reliable echo"));
else { Serial.print(cm); Serial.println(F(" cm")); }
}
const float STOP_CM = 20.0, RESUME_CM = 25.0;
const int CRUISE_PWM = 160;
bool moving = false;
void setup() {
beginMotors(); beginSonar(); Serial.begin(9600);
brakeAll(); delay(3000); // motor power on only after wiring is verified
}
void loop() {
float distanceCm = readDistanceCm();
printDistance(distanceCm);
if (distanceCm < 0 || distanceCm <= STOP_CM) moving = false;
else if (distanceCm >= RESUME_CM) moving = true;
// Between thresholds, retain previous state (hysteresis).
if (moving) drive(CRUISE_PWM, CRUISE_PWM);
else brakeAll();
delay(70);
}תוספת — פנייה מתוזמנתExtension — timed turn
מכונת מצבים עם millis; ממשיכה לבדוק מרחק בזמן פנייה. אין חיישן צד או גב ואין הבטחה לפינוי מכשול.A millis state machine keeps sampling during turns. No side/rear sensing and no guaranteed obstacle clearance.
הצגת הקוד והעתקהView and copy code
// Arduino Uno + L298N. ENA/ENB jumper caps removed.
// Disconnect motor power while wiring/uploading; begin with wheels raised.
// Verify motor/module ratings and module-specific logic-supply wiring.
const byte ENA = 5, IN1 = 2, IN2 = 3;
const byte ENB = 6, IN3 = 4, IN4 = 7;
// Calibrate each side with wheels raised. These depend on physical mounting.
const bool LEFT_REVERSED = false;
const bool RIGHT_REVERSED = false;
void coastAll() {
digitalWrite(ENA, LOW);
digitalWrite(ENB, LOW);
}
void beginMotors() {
pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT);
coastAll();
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
void setMotor(byte en, byte a, byte b, int command, bool reversed) {
command = constrain(command, -255, 255);
if (reversed) command = -command;
digitalWrite(en, LOW); // disable before changing direction inputs
digitalWrite(a, command > 0 ? HIGH : LOW);
digitalWrite(b, command < 0 ? HIGH : LOW);
if (command != 0) analogWrite(en, abs(command));
// command == 0 means COAST. brakeAll() is a separate operation.
}
void drive(int left, int right) {
setMotor(ENA, IN1, IN2, left, LEFT_REVERSED);
setMotor(ENB, IN3, IN4, right, RIGHT_REVERSED);
}
void brakeAll() {
coastAll();
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
digitalWrite(ENA, HIGH); digitalWrite(ENB, HIGH);
// L298: enabled + equal direction inputs = electrical brake.
// Braking generates current; check load ratings. Not a holding brake.
}
const byte TRIG = 9, ECHO = 10;
const unsigned long ECHO_TIMEOUT_US = 25000UL;
void beginSonar() {
pinMode(TRIG, OUTPUT); digitalWrite(TRIG, LOW);
pinMode(ECHO, INPUT);
}
float readDistanceCm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
unsigned long us = pulseIn(ECHO, HIGH, ECHO_TIMEOUT_US);
if (us == 0) return -1.0; // invalid, NOT a clear path
float cm = us / 58.0;
if (cm < 2.0 || cm > 400.0) return -1.0;
return cm;
}
void printDistance(float cm) {
if (cm < 0) Serial.println(F("INVALID: no reliable echo"));
else { Serial.print(cm); Serial.println(F(" cm")); }
}
const float STOP_CM = 20.0, RESUME_CM = 25.0, TOO_CLOSE_CM = 10.0;
const int CRUISE_PWM = 150, TURN_PWM = 150;
const unsigned long SAMPLE_MS = 70, BRAKE_MS = 300, TURN_MS = 400;
enum State { WAIT_CLEAR, FORWARD, BRAKING, TURNING, CHECKING };
void changeState(State next, unsigned long now);
State state = WAIT_CLEAR;
unsigned long stateSince = 0, lastSample = 0;
float distanceCm = -1.0;
void changeState(State next, unsigned long now) {
state = next; stateSince = now;
}
void setup() {
beginMotors(); beginSonar(); Serial.begin(9600);
brakeAll(); delay(3000);
}
void loop() {
unsigned long now = millis();
bool fresh = false;
if (now - lastSample >= SAMPLE_MS) {
lastSample = now;
distanceCm = readDistanceCm();
printDistance(distanceCm);
now = millis(); // pulseIn may have blocked for up to the timeout
fresh = true;
if (distanceCm < 0 || distanceCm <= TOO_CLOSE_CM) {
changeState(WAIT_CLEAR, now); // require clear path to resume
}
}
switch (state) {
case WAIT_CLEAR:
brakeAll();
if (fresh && distanceCm >= RESUME_CM) changeState(FORWARD, now);
break;
case FORWARD:
if (fresh && distanceCm <= STOP_CM) {
brakeAll(); changeState(BRAKING, now);
} else drive(CRUISE_PWM, CRUISE_PWM);
break;
case BRAKING:
brakeAll();
if (now - stateSince >= BRAKE_MS) changeState(TURNING, now);
break;
case TURNING:
if (now - stateSince >= TURN_MS) {
brakeAll(); changeState(CHECKING, now);
} else drive(0, TURN_PWM); // no reverse; left coasts
break;
case CHECKING:
brakeAll();
if (fresh) {
if (distanceCm >= RESUME_CM) changeState(FORWARD, now);
else changeState(WAIT_CLEAR, now); // no repeated blind turns
}
break;
}
}