Robotika ● שיעור 2Lesson 2
→ חזרה← Back
קורס ארדואינו · מפגש 2Arduino course · Session 2

חיישנים, החלטות ותצוגה
נותנים לארדואינו חושים
Sensors, decisions & a display
giving the Arduino senses

בשיעור הקודם גרמנו לנורה להבהב — אבל היא "התעלמה" מהעולם. היום הארדואינו יתחיל לחוש אור ומרחק, להחליט בעצמו מה לעשות, ולהציג מספרים על מסך. הלולאה סוף־סוף נסגרת. Last lesson we made a light blink — but it "ignored" the world. Today the Arduino starts to sense light and distance, decide on its own what to do, and show numbers on a display. The loop finally closes.

👁️ חיישן אור + מרחקLight + distance sensors
🔀 החלטות: if / elseDecisions: if / else
🔢 מסך 4 ספרות + קוד נקי4-digit display + clean code

ניווט: חצים ← → במקלדת, או הכפתורים למטה · לחצו EN למונחים באנגלית Navigate: ← → arrow keys, or the buttons below · press עב for Hebrew

2מה נעשה היוםWhat we'll do today

שלושה רעיונות גדוליםThree big ideas

  • חישה (Sensing) — נחבר חיישן אור וחיישן מרחק, ונקרא מהם מספרים אמיתייםSensing — we wire a light sensor and a distance sensor, and read real numbers from them
  • החלטות (if / else) — הקוד יבחר מה לעשות לפי מה שהחיישן אומרDecisions (if / else) — the code picks what to do based on what the sensor says
  • קוד נקי — שמות ברורים, קבועים, ופונקציות. קוד שגם מחר תבינוClean code — clear names, constants, and functions. Code you'll still understand tomorrow

התרגיל — בשלביםThe build — in levels

  • שלב 1: קוראים חיישן אור ל-Serial MonitorLevel 1: read a light sensor into the Serial Monitor
  • שלב 2: מנורת לילה — ההחלטה הראשונה שלנו (if/else)Level 2: a nightlight — our first decision (if/else)
  • שלב 3: חיישן מרחק → מספר על מסך 4 ספרותLevel 3: a distance sensor → a number on the 4-digit display
  • שלב 4: חיישן חניה — הכול יחדLevel 4: a parking sensor — everything together
לא נספיק הכול? מצוין. הכול כאן בשקופיות ובקבצי הקוד, להמשך בבית.We won't finish it all? Great. It's all here in the slides and code files, to continue at home.

3תזכורת: הלולאה — והחלק שחסרRecap: the loop — and the missing piece

בשיעור 1 אמרנו: כל רובוט הוא לולאה — חש ← חושב ← פועל. אבל ה-Blink שלנו רק חשב (טיימר) ופעל (נורה). הוא לא חש שום דבר — הוא היה מהבהב גם בחושך וגם באור, גם מול קיר וגם מול חלל ריק. In Lesson 1 we said: every robot is a loop — sense → think → act. But our Blink only thought (a timer) and acted (an LED). It never sensed anything — it would blink the same in the dark or the light, facing a wall or empty space.

היום נוסיף את החלק החסר: חישה. ברגע שלרובוט יש חוש, הוא יכול להגיב לעולם — וזה בדיוק מה שהופך מכונה ל"חכמה". Today we add the missing part: sensing. The moment a robot has a sense, it can react to the world — and that's exactly what makes a machine feel "smart".

לחצו "הפעל לולאה" וראו את שלב החישה נדלק — החלק שהיה חסר בשיעור הקודם.Press "run the loop" and watch the sense step light up — the part that was missing last time.

4החוש הראשון: חיישן אורThe first sense: a light sensor

חיישן האור הוא רכיב קטן על מודול עם 4 רגליים. ככל שמגיע אליו יותר אור, כך הוא "מעביר" מתח גבוה יותר. הארדואינו קורא את המתח הזה והופך אותו למספר. The light sensor is a small part on a 4-leg module. The more light hits it, the higher the voltage it "passes". The Arduino reads that voltage and turns it into a number.

החיווט — 3 רגליים, ישר לארדואינוWiring — 3 legs, straight into the Arduino

רגל במודולModule legאלTo
VCC5V
GNDGND
AOA0
DOלא מחברים (בינתיים)leave unconnected (for now)
AO = Analog Out, הרגל ה"אנלוגית". אנחנו קוראים אותה עם analogRead(A0) ומקבלים מספר בין 0 (חושך) ל-1023 (אור חזק).AO = Analog Out, the "analog" leg. We read it with analogRead(A0) and get a number from 0 (dark) to 1023 (bright light).

גררו את כמות האור וראו מה הארדואינו "קורא":Drag the amount of light and see what the Arduino "reads":

☀️
512

5דיגיטלי מול אנלוגי — מתג מול חוגהDigital vs analog — a switch vs a dial

בשיעור הקודם הפינים היו דיגיטליים: רק שני מצבים — דלוק/כבוי, HIGH/LOW, 1/0. כמו מתג אור בקיר. Last lesson the pins were digital: only two states — on/off, HIGH/LOW, 1/0. Like a light switch on the wall.

חיישן אור נותן הרבה יותר מזה — טווח שלם של ערכים, 0 עד 1023. כמו חוגת עמעם במקום מתג. לכן קוראים אותו מהפינים האנלוגיים (A0–A5) עם analogRead, ולא עם digitalRead. A light sensor gives much more — a whole range of values, 0 to 1023. Like a dimmer dial instead of a switch. So we read it from the analog pins (A0–A5) with analogRead, not digitalRead.

דיגיטליDigitalאנלוגיAnalog
דוגמהLike aמתגswitchחוגה/עמעםdial/dimmer
ערכיםValues0 / 10 … 1023
פקודה לקריאהRead withdigitalReadanalogRead
פיניםPinsD0–D13A0–A5
לדוגמהExampleכפתור לחוץ?button pressed?כמה אור יש?how much light?
💡 חיישן המרחק שנכיר בהמשך הוא דווקא דיגיטלי בצורה אחרת — הוא מודד זמן. עוד מעט.💡 The distance sensor we'll meet later is digital in a different way — it measures time. Soon.

6שלב 1: קוראים את חיישן האורLevel 1: read the light sensor

הקוד הקצר הזה הוא ה"עיניים" שלנו אל תוך הארדואינו. אנחנו קוראים מספר מהחיישן ומדפיסים אותו, כדי שגם אנחנו נראה מה הארדואינו רואה. פותחים Serial Monitor במהירות 9600. This short program is our "eyes" into the Arduino. We read a number from the sensor and print it, so that we can see what the Arduino sees. Open the Serial Monitor at 9600.

const int LIGHT_PIN = A0;   // sensor's AO leg

void setup() {
  Serial.begin(9600);       // window to the PC
}

void loop() {
  int light = analogRead(LIGHT_PIN); // 0..1023
  Serial.print("Light: ");
  Serial.println(light);
  delay(200);
}

📄 code/level1_light_read.ino📄 code/level1_light_read.ino

זה מה שתראו ב-Serial Monitor — כסו את החיישן ביד:This is what you'll see in the Serial Monitor — cover the sensor with your hand:

7לחשוב: if / elseTo think: if / else

עכשiו שיש לנו מספר מהחיישן, הקוד יכול להחליט. זה ה-חושב שבלולאה. ההחלטה הכי בסיסית במחשב היא פיצול בדרך: Now that we have a number from the sensor, the code can decide. This is the think in the loop. The most basic decision a computer makes is a fork in the road:

if (light < DARK_LEVEL) {
  // it's dark -> do this
} else {
  // otherwise -> do that
}

קוראים את זה כמו משפט בעברית: "אם האור נמוך מהסף — הדלק; אחרת — כבה." המחשב בודק את התנאי בסוגריים, ובוחר רק אחד משני המסלולים. Read it like a sentence: "if the light is below the threshold — turn on; else — turn off." The computer checks the condition in the parentheses and takes exactly one of the two paths.

גררו את האור. ראו איזה מסלול נבחר, ואת הנורה:Drag the light. See which path is chosen, and the LED:

if חושך → נורה דולקת 💡dark → LED on 💡
else אור → נורה כבויהlight → LED off

8שלב 2: מנורת לילהLevel 2: a nightlight

אותו חיווט כמו שלב 1 (רק חיישן האור), ובלי רכיב חדש: נשתמש בנורה שכבר על הלוח — פין 13. עכשיו הלולאה שלמה: חש אור ← החלט ← הדלק/כבה. Same wiring as Level 1 (just the light sensor), and no new part: we use the LED that is already on the board — pin 13. Now the loop is complete: sense light → decide → on/off.

const int LIGHT_PIN = A0;
const int LED_PIN   = 13;
const int DARK_LEVEL = 400; // tune to your room

void loop() {
  int light = analogRead(LIGHT_PIN);
  if (light < DARK_LEVEL) {
    digitalWrite(LED_PIN, HIGH); // dark -> on
  } else {
    digitalWrite(LED_PIN, LOW);  // bright -> off
  }
  delay(100);
}

📄 code/level2_nightlight.ino📄 code/level2_nightlight.ino

למה DARK_LEVEL בשם?Why name DARK_LEVEL?

הסף 400 מופיע כקבוע עם שם בראש הקובץ — לא מספר "קסם" תקוע באמצע הקוד. כשהחדר אצלכם בהיר או חשוך יותר, משנים מקום אחד וסיימתם. זה הכלל הראשון של קוד נקי. The threshold 400 lives as a named constant at the top of the file — not a "magic number" stuck in the middle of the code. When your room is brighter or darker, you change one place and you're done. That's rule one of clean code.

טיפ כיתה: קודם מריצים את שלב 1, רואים איזה מספר יש בחדר כשמכסים את החיישן, ולפי זה בוחרים DARK_LEVEL.Class tip: run Level 1 first, see what number you get when you cover the sensor, and pick DARK_LEVEL from that.

9קוד נקי — מתנה לעצמכם ממחרClean code — a gift to tomorrow's you

✗ עובד, אבל מבולגן✗ works, but messy

void loop() {
  if (analogRead(0) < 400) {
    digitalWrite(13, 1);
  } else {
    digitalWrite(13, 0);
  }
  delay(100);
}

מה זה 0? מה זה 13? מה זה 400? בעוד שבוע — גם אתם לא תזכרו.What's 0? What's 13? What's 400? In a week — you won't remember either.

✓ אותה התנהגות, נקי✓ same behaviour, clean

const int LIGHT_PIN  = A0;
const int LED_PIN    = 13;
const int DARK_LEVEL = 400;

void loop() {
  int light = analogRead(LIGHT_PIN);
  if (light < DARK_LEVEL)
    digitalWrite(LED_PIN, HIGH);
  else
    digitalWrite(LED_PIN, LOW);
  delay(100);
}
  • תנו שם לכל פין — const int בראש הקובץName every pin — const int at the top
  • אין מספרי קסם — כל סף הוא קבוע עם שםNo magic numbers — every threshold is a named constant
  • הערה אומרת "למה", לא "מה"A comment says "why", not "what"
  • מה שחוזר על עצמו → פונקציה (עוד מעט)Repeated work → a function (coming up)

10חוש שני: מרחק (אולטרסוני)A second sense: distance (ultrasonic)

חיישן ה-HC-SR04 מודד מרחק בדיוק כמו עטלף: הוא שולח "ציוץ" קולי שאוזן לא שומעת, ומודד כמה זמן לקח להד לחזור. יותר זמן = העצם רחוק יותר. The HC-SR04 sensor measures distance just like a bat: it sends a sound "chirp" your ear can't hear, and times how long the echo takes to return. More time = the object is farther.

שימו לב להבדל היפה: חיישן האור מדד מתח; החיישן הזה מודד זמן. אותה פקודה לא תתאים לשניהם — לכן יש לו שתי רגליים מיוחדות: Note the lovely difference: the light sensor measured voltage; this one measures time. The same command won't fit both — so it has two special legs:

  • Trig (D9) — מכאן שולחים את הציוץTrig (D9) — we send the chirp from here
  • Echo (D10) — כאן מקשיבים לחזרהEcho (D10) — we listen for the return here
  • VCC → 5V · GND → GNDVCC → 5V · GND → GND

לחצו "ציוץ!" וגררו את העצם קרוב/רחוק:Press "chirp!" and drag the object near/far:

25 cm

11פונקציה: לשמור את loop() קריאA function: keep loop() readable

מדידת מרחק דורשת כמה שורות טכניות (ציוץ, המתנה, חישוב). אם נדחוף אותן לתוך loop(), הוא יהפוך לג'ונגל. הפתרון: נארוז אותן בפונקציה עם שם, getDistanceCm(), שמחזירה מספר. Measuring distance takes a few technical lines (chirp, wait, compute). If we cram them into loop(), it becomes a jungle. The fix: wrap them in a named function, getDistanceCm(), that returns a number.

עכשיו loop() נקרא כמו משפט: "קבל מרחק, הצג אותו". מי שרוצה לדעת איך מודדים — יורד לפונקציה. מי שלא — ממשיך לקרוא בשקט. Now loop() reads like a sentence: "get the distance, show it". Whoever wants to know how we measure — dives into the function. Whoever doesn't — keeps reading in peace.

זה בדיוק הכלל הרביעי של קוד נקי: מה שחוזר, או מה שמסובך — תנו לו שם ותוציאו החוצה. פונקציה טובה היא כמו כפתור: אתה לוחץ, זה עובד, ולא אכפת לך מה בפנים.This is rule four of clean code: what repeats, or what's complex — give it a name and pull it out. A good function is like a button: you press it, it works, and you don't care what's inside.
void loop() {
  int distance = getDistanceCm();
  display.showNumberDec(distance);
  delay(200);
}

// all the fiddly steps live here, once
int getDistanceCm() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  long t = pulseIn(ECHO_PIN, HIGH);
  return t * 0.0343 / 2;
}

🗣️ "קח את הזמן ששמעת, הכפל במהירות הקול, חלק ב-2 (הלוך ושוב) — וקיבלת ס"מ."🗣️ "take the time you heard, times the speed of sound, divide by 2 (there and back) — and you have cm."

12מסך 4 ספרות (TM1637)The 4-digit display (TM1637)

עד עכשיו "דיברנו" עם המחשב דרך ה-Serial Monitor. אבל רובוט אמיתי צריך להראות דברים בלי מחשב מחובר. המסך הזה מציג מספר בן 4 ספרות שרואים מהצד השני של החדר. So far we "talked" to the computer through the Serial Monitor. But a real robot needs to show things with no computer attached. This display shows a 4-digit number you can read from across the room.

רק 2 חוטי מידע + מתחJust 2 data wires + power

רגלPinאלToמה זהWhat
CLKD4הקצב שמסנכרןthe sync beat
DIOD5הנתונים עצמםthe data itself
VCC5V—
GNDGND—
צריך ספרייה אחת: בתפריט Library Manager מחפשים "TM1637Display" (של Avishay Orpaz) ולוחצים Install. מוסיפים בראש הקוד #include <TM1637Display.h>.You need one library: in the Library Manager search "TM1637Display" (by Avishay Orpaz) and click Install. Add #include <TM1637Display.h> at the top.

זהו המסך. גררו את המרחק וראו את הספרות:This is the display. Drag the distance and watch the digits:

הפקודה: display.showNumberDec(distance);The command: display.showNumberDec(distance);

13למה המסך צריך חוט "שעון" (CLK)?Why does the display need a "clock" wire (CLK)?

שמתם לב שלמסך יש שני חוטי מידע (CLK ו-DIO), ולא אחד? הנה למה. המסך מקבל את המספר ביט אחרי ביט (0 או 1) על חוט אחד — אבל איך הוא יודע מתי כל ביט מוכן לקריאה? Notice the display has two data wires (CLK and DIO), not one? Here's why. The display receives the number bit by bit (0 or 1) on one wire — but how does it know when each bit is ready to be read?

  • DIO — נתונים: הביטים עצמם (0 או 1)data: the bits themselves (0 or 1)
  • CLK — שעון: פעימה שאומרת "עכשיו! קרא ביט"clock: a beat that says "now! read a bit"

בלי שעון משותף, הצד המקבל לא יודע מתי הקו מחליף ערך ומתי הוא יציב. השעון הוא המטרונום ששני הצדדים סופרים לפיו. זו "תקשורת טורית" (serial): ביט-אחרי-ביט על חוט אחד, בקצב של השעון. Without a shared clock, the receiver can't tell when the line is switching versus steady. The clock is the metronome both sides count to. This is "serial communication": bit after bit on one wire, paced by the clock.

בכל עלייה של השעון (מ-0 ל-1), המסך "צובט" את הערך שיושב כרגע על חוט הנתונים. זה בדיוק מה ש-TM1637Display עושה מאחורי הקלעים — ולכן צריך את שני הפינים, CLK ו-DIO. On every rising edge of the clock (0 → 1), the display "latches" whatever value is on the data wire. That's exactly what TM1637Display does behind the scenes — which is why it needs both pins, CLK and DIO.

לחצו "הפעל שעון" — בכל פעימה נקלט ביט מחוט הנתונים:Press "run the clock" — on each beat one bit is captured from the data wire:

נקלטcaptured: ________ = —

14שלב 3: מרחק על המסךLevel 3: distance on the display

מחברים הכול: החיישן מודד, הפונקציה מחזירה מספר, והמסך מציג אותו. שימו לב כמה loop() קצר וברור — כל הטכניקה חבויה ב-getDistanceCm(). Put it together: the sensor measures, the function returns a number, the display shows it. Notice how short and clear loop() is — all the technique hides inside getDistanceCm().

#include <TM1637Display.h>
const int TRIG_PIN=9, ECHO_PIN=10;
const int CLK_PIN=4, DIO_PIN=5;
TM1637Display display(CLK_PIN, DIO_PIN);

void setup() {
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  display.setBrightness(5);
}

void loop() {
  int distance = getDistanceCm();
  display.showNumberDec(distance);
  delay(200);
}

📄 code/level3_sonar_display.ino · כל הקוד📄 code/level3_sonar_display.ino · all the code

סדר החיווט המומלץSuggested wiring order

  • קודם רק את ה-HC-SR04 (Trig→D9, Echo→D10), ולבדוק ב-Serial שהמספרים הגיונייםFirst just the HC-SR04 (Trig→D9, Echo→D10), and check in Serial that the numbers make sense
  • רק אז מוסיפים את המסך (CLK→D4, DIO→D5)Only then add the display (CLK→D4, DIO→D5)
  • כל רכיב חדש — לבד קודם. ככה קל למצוא מה לא עובד.Each new part — alone first. That's how it's easy to find what's broken.
לא מופיע מספר? בדקו 5V ו-GND של כל רכיב, ושה-Trig/Echo לא התחלפו.No number? Check each part's 5V and GND, and that Trig/Echo aren't swapped.

15שלב 4: חיישן חניה — הכול יחדLevel 4: a parking sensor — all together

הפרויקט המסכם: בדיוק כמו חיישן חניה ברכב. המסך מראה את המרחק, ונורת אזהרה מהבהבת מהר יותר ככל שמתקרבים. זו החלטה (if/else) ועוד כלי חדש — map(). The capstone: exactly like a car's parking sensor. The display shows the distance, and a warning LED blinks faster the closer you get. That's a decision (if/else) plus one new tool — map().

מה עושה map()?What does map() do?

map() "מותח" טווח אחד על טווח אחר. כאן: מרחק 0→30 ס"מ הופך להשהיית הבהוב 40→500 מילישניות. קרוב = השהיה קטנה = הבהוב מהיר. map() "stretches" one range onto another. Here: distance 0→30 cm becomes a blink delay of 40→500 ms. Close = small delay = fast blink.

➕ חיווט נוסף: נורה + נגד 220Ω מ-D6 ל-GND (כמו בשיעור 1).➕ Added wiring: an LED + 220Ω resistor from D6 to GND (like Lesson 1).

גררו את המכשול לכיוון החיישן:Drag the obstacle toward the sensor:

25 cm

16שלב 4: הקודLevel 4: the code

const int WARN_CM = 30; // warning zone starts here

void loop() {
  int distance = getDistanceCm();
  display.showNumberDec(distance);

  if (distance > WARN_CM) {
    digitalWrite(LED_PIN, LOW); // clear
    delay(100);
  } else {
    // closer -> smaller delay -> faster
    int d = map(distance, 0, WARN_CM, 40, 500);
    digitalWrite(LED_PIN, HIGH); delay(d);
    digitalWrite(LED_PIN, LOW);  delay(d);
  }
}

📄 code/level4_parking_sensor.ino📄 code/level4_parking_sensor.ino

למה זה יפהWhy this is nice

  • כל מה שלמדנו היום בקובץ אחד: חישה (מרחק), החלטה (if/else), פעולה (מסך + נורה)Everything from today in one file: sensing (distance), a decision (if/else), acting (display + LED)
  • getDistanceCm() מוסתר — loop() נשאר קצר וקריאgetDistanceCm() is hidden — loop() stays short and readable
  • WARN_CM בשם — משנים את גודל "אזור האזהרה" במקום אחדWARN_CM is named — change the "warning zone" size in one place
רוצים גם צליל? מי שיש לו זמזם (buzzer) יכול להחליף/להוסיף אותו במקום הנורה — ממש כמו ברכב.Want sound too? Whoever has a buzzer can swap/add it in place of the LED — just like in a car.

17ריצת מסלול — למי שרץ קדימהRunway — for whoever races ahead

אתגרי בונוסBonus challenges

  • בהירות אוטומטית: חיישן האור קובע את בהירות המסך — שני חיישנים עובדים יחד, ושוב map(). bonus_auto_brightness.inoAuto-brightness: the light sensor sets the display's brightness — two sensors working together, and map() again. bonus_auto_brightness.ino
  • שלושה אזורי אור: בהיר / עמום / חשוך עם if … else if … else — שרשרת החלטות. bonus_light_zones.inoThree light zones: bright / dim / dark with if … else if … else — a chain of decisions. bonus_light_zones.ino

לשחק איתו בביתPlay at home

  • הפכו את מנורת הלילה: שתידלק דווקא באור (שנו < ל->)Flip the nightlight: make it turn on in the light instead (change < to >)
  • הציגו על המסך את ערך האור (0–1023) במקום המרחקShow the light value (0–1023) on the display instead of distance
  • סמנו "קרוב מדי" על המסך עם display.showNumberDec של מספר מיוחד, למשל 0Flag "too close" on the display using a special number, e.g. 0
הכלל של היום: רכיב אחד בכל פעם, ו-Serial תמיד פתוח. ה-Serial Monitor הוא העיניים שלכם — כשמשהו לא עובד, הדפיסו ותראו.Today's rule: one part at a time, and Serial always open. The Serial Monitor is your eyes — when something breaks, print and look.

18סיכום — מה לקחנו הביתהSummary — what we take home

הרעיון האחד להיוםThe one idea for today

הלולאה נסגרה: עכשיו הארדואינו חש (אור, מרחק), מחליט לבד (if/else), ופועל (מסך, נורה). זה כבר לא טיימר עיוור — זו מכונה שמגיבה לעולם. וכתבתם את זה בקוד נקי: שמות, קבועים, ופונקציה. The loop closed: now the Arduino senses (light, distance), decides on its own (if/else), and acts (display, LED). It's no longer a blind timer — it's a machine that reacts to the world. And you wrote it in clean code: names, constants, and a function.

המילים החדשותThe new words

analogRead · if / else · if/else if · const · פונקציהfunction · return · pulseIn · map() · showNumberDec

בשיעור הבאNext lesson

נתנו לארדואינו חושים — עכשיו ניתן לו שרירים. נוסיף מנוע, ונגרום לדברים לזוז לפי מה שהחיישנים אומרים. הלולאה חש→חושב→פועל סוף־סוף תזיז משהו בעולם. We gave the Arduino senses — now we give it muscles. We add a motor, and make things move based on what the sensors say. The sense→think→act loop will finally move something in the world.

💻 כל קבצי הקוד של השיעור — הורדהAll of this lesson's code — download

עבודה יפה — נתראה בשיעור הבא! 👋Nice work — see you next lesson! 👋