برمجة المتحكّمات بلغة مايكروبايثون · الفصل 13 — حسّاسات ومشغّلات شائعةחיישנים ומפעילים נפוצים · תכנות מיקרו-בקרים בשפת MicroPython⌂📚🏠
الفصل 13

حسّاسات ومشغّلات شائعة

חיישנים ומפעילים נפוצים – Common Sensors and Actuators
3 ساعات تعليمية

نعرف الآن الأطراف والنواقل والمكتبات. حان وقت القطع التي نجدها في كل مشروع. لكل قطعة نتبع القالب نفسه: كيف تعمل، كيف نوصلها، الشيفرة، ثم المصيدة التي يقع فيها أغلب من يبدأ بها. وفي الآخر نجمعها في نظام صغير.

في هذا الفصل:
  • نقرأ الحرارة والرطوبة من DHT11/22 دون تجاوز قيد سرعة القراءة.
  • نضيء شريط NeoPixel، ونحسب تياره قبل توصيله.
  • نشغّل مرحّلا عبر ترانزستور بأمان، ونفهم دور ثنائي الدوران الحرّ.
  • نقرأ المسّ على ESP32 وعصا تحكّم عبر محوّلين.
  • نستعمل حسّاسات I2C بمكتبة، ونبني نظاما من حسّاس وعتبة وعرض.
القطعةنوعهاكيف تتصلالقسم
DHT11 / DHT22حرارة ورطوبةطرف رقمي واحد13.1
HC-SR04مسافةطرفان رقميان، نبضة13.2 و4.5
NeoPixelمشغّل: ضوء ملوّنطرف رقمي واحد13.3
مرحّلمشغّل: مفتاح لحمل منفصلطرف رقمي وترانزستور13.4
TouchPadمسّطرف واحد، ESP32 فقط13.5
KY-023موضع واتجاهمحوّلان وطرف رقمي13.6
BMP280 / AHT20ضغط وحرارة ورطوبةI2C13.7

13.1 الحرارة والرطوبة: DHT11 وDHT22 – חיישן טמפרטורה ולחות

المبدأ: داخل الوحدة حسّاس ومتحكّم صغير يقيسان ويرسلان النتيجة أعدادا عبر سلك بيانات واحد. فهو طرف رقمي عادي، لا محوّل فيه من جهتنا. ووحدة dht جزء من البرنامج الثابت على اللوحتين.

DHT11DHT22
مجال الحرارة (نموذجي)0 – 50 °C−40 – 80 °C
مجال الرطوبة (نموذجي)20 – 90 %0 – 100 %
أسرع قراءة حسب التوثيقمرة كل ثانيةمرة كل ثانيتين
VCCDATAGNDDHT223V3DHTGNDR
المقاومة R ترفع خط البيانات. قيمتها الشائعة 4.7 kΩ، وكثير من الوحدات الجاهزة تحويها.
قياس كل ثانيتين. لقياس DHT11 نغيّر الصنف فقط.
import board
import dht
import time
from machine import Pin

sensor = dht.DHT22(Pin(board.DHT))

while True:
    try:
        sensor.measure()
        t = sensor.temperature()
        h = sensor.humidity()
        print("%.1f C  %.1f %%" % (t, h))
    except OSError:
        print("no answer from the sensor")
    time.sleep(2)
ESP32 + Pico W · MicroPython 1.29 · simulated board
24.0 C  55.0 %
24.5 C  56.0 %
25.0 C  57.0 %
...
البرنامج نفسه دون حسّاس: لا ينهار، بل يخبرنا.
import board
import dht
import time
from machine import Pin

sensor = dht.DHT22(Pin(board.DHT))

while True:
    try:
        sensor.measure()
        t = sensor.temperature()
        h = sensor.humidity()
        print("%.1f C  %.1f %%" % (t, h))
    except OSError:
        print("no answer from the sensor")
    time.sleep(2)
ESP32 + Pico W · MicroPython 1.29 · simulated board
no answer from the sensor
...
خطأ شائع: الأمر measure() هو الذي يقرأ من الحسّاس، أما temperature() فتعيد آخر قيمة. ومن ينسى measure يرى العدد نفسه إلى الأبد. وإذا قرأنا أسرع من القيد، فالنتيجة قد لا تكون دقيقة أو يفشل القياس.

إذا طلب أكثر من جزء في البرنامج الحرارة بسرعة، نضع القيد في صنف يحفظ آخر قراءة:

نسأل كل ثانية، والحسّاس يُقرأ كل ثانيتين فقط.
import board
import dht
import time
from machine import Pin


class Climate:
    def __init__(self, pin, min_ms=2000):
        self.sensor = dht.DHT22(Pin(pin))
        self.min_ms = min_ms
        self.last = None

    def read(self):
        now = time.ticks_ms()
        if (self.last is None
                or time.ticks_diff(now, self.last) >= self.min_ms):
            self.sensor.measure()
            self.last = now
        return self.sensor.temperature()


room = Climate(board.DHT)
for _ in range(5):
    print("%.1f C" % room.read())
    time.sleep(1)
ESP32 + Pico W · MicroPython 1.29 · simulated board
24.0 C
24.0 C
26.0 C
26.0 C
28.0 C

13.2 المسافة: HC-SR04 – מרחק

شرحنا هذا الحسّاس في القسم 4.5: المبدأ، ومجزّئ الجهد على ECHO، والمكتبة hcsr04.py. نرجع إلى هناك للتوصيل، وهنا نستعمل المكتبة مع عتبة:

المكتبة تعيد None إذا لم يعد صدى.
import board
import time
from hcsr04 import HCSR04

NEAR_CM = 30
sensor = HCSR04(board.TRIG, board.ECHO)

for _ in range(3):
    d = sensor.distance_cm()
    if d is None:
        print("no echo")
    else:
        print("%.1f cm" % d, "NEAR" if d < NEAR_CM else "far")
    time.sleep(1)
ESP32 + Pico W · MicroPython 1.29 · simulated board
20.0 cm NEAR
no echo
100.0 cm far
...
خطأ شائع: لا ننسى فحص None قبل المقارنة: None < 30 خطأ يوقف البرنامج. وقطعة قماش أو سطح مائل قد لا يعيدان صدى، فلا نستنتج من None أن الطريق خالية.

13.3 الشريط الملوّن: NeoPixel – רצועת לדים (NeoPixel, WS2812)

المبدأ: كل ثنائي باعث للضوء في الشريط فيه شريحة صغيرة. البيانات تدخل إلى الأول، فيأخذ ثلاثة بايتات لنفسه: أحمر وأخضر وأزرق، ويمرّر الباقي إلى التالي. لذلك يكفي طرف واحد لكل الشريط. والألوان تتغيّر فقط عند write().

DIN5VGNDWS2812 x 8NEOPIXELGNDR+5 V
تغذية 5 V خارجية وأرضي مشترك. المقاومة R على خط البيانات قيمتها الشائعة بضع مئات الأوم.
مثال 13.1
كم تيارا يحتاج شريط من 8 ثنائيات؟ نأخذ قيمة نموذجية: نحو 60 mA للثنائي الواحد عند الأبيض الكامل، ونراجع ورقة بيانات الشريط.
الحل:
I = N · ILED
I = 8 · 60
I = 480 mA

هذا أكثر مما نطلبه من طرف تغذية اللوحة، فنستعمل مصدرا خارجيا.

I = 480 mA
مقياس الجهد يحدّد عدد الثنائيات المضاءة. بعد البرنامج: ما خرج على السلك بالنظام الست عشري، كل ستة أرقام ثنائي واحد بالترتيب أحمر، أخضر، أزرق، و28 هو العدد 40.
import board
import neopixel
import time
from machine import Pin

COUNT = 8
GREEN = (0, 40, 0)
OFF = (0, 0, 0)

strip = neopixel.NeoPixel(Pin(board.NEOPIXEL, Pin.OUT), COUNT)
pot = board.analog_in(board.POT)

while True:
    lit = pot.read_u16() * (COUNT + 1) // 65536
    for i in range(COUNT):
        strip[i] = GREEN if i < lit else OFF
    strip.write()
    print("lit:", lit)
    time.sleep(1)
ESP32 + Pico W · MicroPython 1.29 · simulated board
lit: 0
lit: 2
lit: 5
lit: 8
[neo]
000000 000000 000000 000000 000000 000000 000000 000000
002800 002800 000000 000000 000000 000000 000000 000000
002800 002800 002800 002800 002800 000000 000000 000000
002800 002800 002800 002800 002800 002800 002800 002800
...

اخترنا اللون (0, 40, 0) وليس 255: السطوع يكفي، والتيار ينخفض. بقيمة نموذجية نحو 20 mA للون الواحد عند أقصى سطوع، ينخفض تيار الثمانية إلى نحو 25 mA.

تحذير: لا نغذّي شريطا طويلا من 3V3، ونوصل الأرضيين معا. وكثير من الأشرطة تُغذّى بـ5 V وتحتاج على خط البيانات إلى جهد أعلى من 3.3 V حسب ورقة البيانات. فإذا ظهرت ألوان عشوائية، فهذا أول ما نفحصه. وننصح بمكثّف كبير على التغذية قرب الشريط.

13.4 المرحّل: مفتاح لحمل منفصل – ממסר (Relay)

المبدأ: المرحّل (ממסר) فيه ملف يجذب ملامسا (מגע) ميكانيكيا. جانب الملف وجانب الملامس غير متصلين كهربائيا، فيتحكّم تيار صغير في دائرة أخرى منفصلة تماما. لكن تيار الملف أكبر مما يعطيه الطرف، فنحتاج إلى ترانزستور كما في القسم 7.8.

LED_EXTGND1 kΩ+5 V+−12 V
الترانزستور يشغّل الملف، والملامس يشغّل حملا في دائرة منفصلة بجهد منخفض. الخط المتقطّع هو الرباط الميكانيكي.

والثنائي الموصول على الملف هو ثنائي الدوران الحرّ: الملف يختزن طاقة، وعند الفصل يقفز جهده قفزة قد تتلف الترانزستور، فيمرّر الثنائي هذا التيار حتى يتلاشى. ولا نستغني عنه.

مثال 13.2
ملف نموذجي من 5 V يسحب 70 mA. والترانزستور قيمة hFE الدنيا له نحو 100 حسب ورقة بياناته. نختار RB = 1 kΩ، فهل يكفي تيار القاعدة؟
الحل:
IB,min = IChFE = 70100 = 0.7 mA
IB = Vpin − VBERB = 3.3 − 0.71 = 2.6 mA

التيار أكبر بكثير من الحد الأدنى، فالترانزستور يعمل مفتاحا مغلقا. ونبقى ضمن ما يعطيه الطرف عادة.

IB = 2.6 mA

والبرنامج طرف مخرج عادي. نستعمل هنا board.LED_EXT لأنه طرف حرّ. ونضع بين التشغيل والإيقاف عتبتين وليس واحدة، حتى لا يطقطق الملامس كلما تذبذبت الحرارة حول العتبة:

عند 27 يبقى المرحّل على حالته السابقة: مرة مفصول ومرة موصول.
import board
import dht
import time
from machine import Pin

ON_ABOVE = 28
OFF_BELOW = 26

relay = Pin(board.LED_EXT, Pin.OUT, value=0)
sensor = dht.DHT22(Pin(board.DHT))

while True:
    sensor.measure()
    t = sensor.temperature()
    if t >= ON_ABOVE:
        relay.value(1)
    elif t <= OFF_BELOW:
        relay.value(0)
    print("%.1f C  relay=%d" % (t, relay.value()))
    time.sleep(2)
ESP32 + Pico W · MicroPython 1.29 · simulated board
25.0 C  relay=0
27.0 C  relay=0
28.5 C  relay=1
27.0 C  relay=1
26.0 C  relay=0
27.0 C  relay=0
...
تحذير: سلامة: لا نوصل جهد الشبكة بمرحّل في هذا الكتاب، ولا على لوحة تجارب. جهد الشبكة قاتل، والعمل عليه لصاحب الاختصاص. نجرّب بجهد منخفض ومصدر مناسب، كمصباح 12 V. ونقرأ جهد الملامس وتياره الأقصيين في ورقة البيانات، وليس ما هو مكتوب على موقع البيع.
ملاحظة: وحدات المرحّل الجاهزة تضم الترانزستور والثنائي. بعضها يعمل عند 0 وبعضها عند 1، وبعضها يحتاج إلى جهد إدخال أعلى من 3.3 V. لذلك نفحص الوحدة أولا دون حمل.
سؤال 13.1: ملف يسحب 40 mA، وhFE الدنيا 100. ما أقل تيار قاعدة؟

13.5 المسّ: TouchPad – חיישן מגע (Capacitive Touch)

المبدأ: كل جسم موصل يغيّر السعة الكهربائية على الطرف، والشريحة تقيس ذلك. فيكفي سلك وقطعة نحاس، بلا زر. الصنف TouchPad موجود على ESP32 فقط، وبعض أطرافه: 0, 2, 4, 12–15, 27, 32, 33. وعلى Pico W لا يوجد.

14 (ESP32)
قطعة موصلة وسلك إلى الطرف 14، بعد فصل الزر عنه.
على ESP32 فقط: نقيس لحظة التشغيل ونأخذ نصفها عتبة.
import time
from machine import Pin, TouchPad

pad = TouchPad(Pin(14))
limit = pad.read() // 2
print("limit:", limit)

while True:
    value = pad.read()
    print(value, "touched" if value < limit else "free")
    time.sleep(1)
ESP32 · MicroPython 1.29 · simulated board
limit: 600
1200 free
1180 free
60 touched
55 touched
1190 free
...
تحذير: الأعداد نسبية. التوثيق يقول إنها عادة عشرات عند اللمس وأكثر من ألف بدونه، لكنها تتغيّر مع اللوحة والمحيط. لذلك لا نكتب عتبة ثابتة، بل نعايرها عند التشغيل ولا نلمس القطعة في تلك اللحظة.

13.6 عصا التحكّم: KY-023 – ג׳ויסטיק (Joystick)

المبدأ: وحدة KY-023 هي مقياسا جهد متعامدان وزر. كل محور جهد نقرؤه بمحوّل، كما في الفصل 6. وفي الوسط الجهد نحو نصف التغذية، أي عدد قريب من 32768.

GND+5VVRxVRySWKY-023GND3V3POTLDRBTN
التوصيل بأسماء board.py. السلك الأحمر: الطرف المكتوب عليه +5V يذهب إلى 3V3.
ذهاب وعودة على المحورين، ثم ضغطة على الزر.
import board
import time
from machine import Pin

CENTER = 32768
DEAD = 6000

x_axis = board.analog_in(board.POT)
y_axis = board.analog_in(board.LDR)
button = Pin(board.BTN, Pin.IN, Pin.PULL_UP)


def axis(adc):
    d = adc.read_u16() - CENTER
    return 0 if abs(d) < DEAD else d


def direction(dx, dy):
    if dx == 0 and dy == 0:
        return "center"
    if abs(dx) >= abs(dy):
        return "right" if dx > 0 else "left"
    return "up" if dy > 0 else "down"


while True:
    name = direction(axis(x_axis), axis(y_axis))
    print(name, "pressed" if button.value() == 0 else "")
    time.sleep(1)
ESP32 + Pico W · MicroPython 1.29 · simulated board
center 
right 
up 
left 
center pressed
...
▶تجربة حية — عصا التحكّممقياس الجهد هو المحور الأفقي، والمقاومة الضوئية هي المحور العمودي. نحرّكهما ونرى الاتجاه، ونغيّر DEAD.
⚠
المختبر غير متاح الآن. المادة في هذا الفصل كاملة من دونه — نواصل القراءة، ونعود إلى التجربة لاحقا أو نفتحها مباشرة من الرابط الذي تحت الإطار.
https://fahed-lab.com/books/micropython/lab/mpy_lab?prog=ch13_joystick
نفتح المختبر في صفحة مستقلة ↗ fahed-lab.com/books/micropython/lab/mpy_lab?prog=ch13_joystick
خطأ شائع: لا نوصل الوحدة بـ5 V رغم الكتابة عليها: عندها يصل خرج المحورين إلى 5 V، وهذا فوق ما يتحمّله الطرف. والوسط ليس 32768 تماما، لذلك نحتاج إلى منطقة ميتة (אזור מת): DEAD = 6000 يقابل نحو 0.3 V. وقد يكون اتجاه المحور معكوسا حسب تركيب الوحدة، فنفحصه ونبدّل الإشارة.

13.7 حسّاسات I2C: BMP280 وAHT20 – חיישני I2C

المبدأ: هذان الحسّاسان يعملان على الناقل الذي عرفناه في الفصل 9. BMP280 يقيس الضغط والحرارة، وAHT20 الحرارة والرطوبة، بعنوانين مختلفين: 0x76 أو 0x77 للأول، و0x38 للثاني، فيعملان معا على السلكين نفسيهما.

VCCSCLSDAGNDBMP2803V3SCLSDAGND
أربعة أسلاك، وهي نفسها للحسّاسين.

كتبنا لكل منهما مكتبة قصيرة: common/bmp280.py وcommon/aht20.py، وهما مع مكتبات الكتاب. مكتبة BMP280 تطبّق قوانين التصحيح من ورقة بيانات الشركة المصنّعة، لأن كل شريحة تأتي بمعاملات معايرة خاصة بها، فهي تقرؤها أولا ثم تحسب.

وضعنا في المُحاكي معاملات وقراءات المثال المحلول في ورقة البيانات. والنتيجة هي نتيجته.
import board
from bmp280 import BMP280

i2c = board.i2c()
print("found:", [hex(a) for a in i2c.scan()])

sensor = BMP280(i2c)
t, p = sensor.read()
print("%.2f C" % t)
print("%.1f hPa" % (p / 100))
ESP32 + Pico W · MicroPython 1.29 · simulated board
found: ['0x76']
25.08 C
1006.5 hPa
استعمال AHT20.
import board
from aht20 import AHT20

sensor = AHT20(board.i2c())
t, h = sensor.read()
print("%.1f C  %.1f %%" % (t, h))

برنامج AHT20 وحده لم يُشغَّل في بناء الكتاب، لأن المُحاكي لا يملك هذه الشريحة، وقد مرّ بالترجمة فقط. فلنجرّبه أولا على اللوحة.

تحذير: وحدات تشبه بعضها: BME280 غير BMP280، ولها رقم تعريف آخر، فتتوقف المكتبة برسالة خطأ بدل أن تعطي أعدادا خاطئة. وقد نجد عنوانا غير المتوقّع، فنبدأ دائما بالأمر i2c.scan(). والأعداد العشرية على اللوحة أقل دقة منها في المُحاكي، فلا نقرأ المنازل الأخيرة من الضغط.

13.8 مشروع: نافذة دفيئة – מערכת קטנה: חממה

نجمع الآن حسّاسا وعتبتين وعرضا ومشغّلا. الدفيئة (חממה) تفتح نافذتها إذا ارتفعت الحرارة، واللون يبيّن الحالة. المحرّك المؤازر من القسم 7.4 مع مكتبته servo.py.

DHT22الحرارةالقرارعتبتانNeoPixelاللونServoفتحة النافذة
من الحسّاس إلى القرار، ومنه إلى المشغّلين.
القرار في دالة واحدة لا تعرف شيئا عن العتاد، فيسهل فحصها وتغييرها.
import board
import dht
import neopixel
import time
from machine import Pin
from servo import Servo

WARM = 26
HOT = 30
GREEN, AMBER, RED = (0, 40, 0), (40, 20, 0), (40, 0, 0)

sensor = dht.DHT22(Pin(board.DHT))
strip = neopixel.NeoPixel(Pin(board.NEOPIXEL, Pin.OUT), 8)
window = Servo(board.pwm(board.SERVO, 50))


def decide(t):
    if t >= HOT:
        return RED, 90
    if t >= WARM:
        return AMBER, 45
    return GREEN, 0


while True:
    try:
        sensor.measure()
    except OSError:
        print("sensor error")
        time.sleep(2)
        continue
    t = sensor.temperature()
    color, angle = decide(t)
    strip.fill(color)
    strip.write()
    window.angle(angle)
    print("%.1f C  window %d" % (t, angle))
    time.sleep(2)
ESP32 + Pico W · MicroPython 1.29 · simulated board
24.0 C  window 0
27.0 C  window 45
31.0 C  window 90
28.0 C  window 45
24.0 C  window 0
[neo]
002800 002800 002800 002800 002800 002800 002800 002800
281400 281400 281400 281400 281400 281400 281400 281400
280000 280000 280000 280000 280000 280000 280000 280000
281400 281400 281400 281400 281400 281400 281400 281400
002800 002800 002800 002800 002800 002800 002800 002800
...
تحذير: الشريط والمحرّك المؤازر يأخذان تيارا كبيرا: مصدر 5 V خارجي، وأرضي مشترك مع اللوحة. وإذا أعادت اللوحة التشغيل حين يتحرّك المحرّك، فهذا عادة هبوط في التغذية وليس خطأ في البرنامج.
نشاط: أضيفوا سجلّ CSV من الفصل 12، يكتب الحرارة والزاوية كل عشر قراءات، واجعلوا WARM وHOT تأتيان من ملف إعدادات.

13.9 كيف نختار الحسّاس؟ – בחירת חיישן

نريد أن نقيسنختارنسأل قبل الشراء
الحرارة والرطوبة في غرفةDHT22 أو AHT20هل يكفي بطء القراءة؟ هل عندي ناقل I2C؟
الضغط والارتفاع النسبيBMP280هل هي BMP أم BME؟ ما جهدها؟
الضوء بلا دقة كبيرةمقاومة ضوئية، الفصل 6هل يكفي مجزّئ جهد؟
مسافة بضعة أمتارHC-SR04هل الجهد 5 V؟ هل السطح يعكس الصوت؟
تدفق الماءحسّاس بمروحة يعطي نبضاتكم نبضة للتر حسب ورقة البيانات؟ نعدّها بالمقاطعة، الفصل 5
لمس بلا زرTouchPadهل اللوحة ESP32؟
موضع يدويمقياس جهد أو KY-023كم محوّلا متاحا؟

القاعدة: نبدأ بما نحتاج إليه فعلا: المجال، وسرعة القراءة، وجهد العمل، وطريقة الاتصال. وكل رقم نأخذه من ورقة البيانات وليس من موقع البيع.

أهمّ أفكار الفصل:

ملخّص قوانين الفصل:

القانونالصيغة
تيار الشريطI = N · ILED
أدنى تيار قاعدةIB,min = IChFE
تيار القاعدةIB = Vpin − VBERB

أوامر الفصل:

الأمرعمله
dht.DHT22(Pin(n)), dht.DHT11(Pin(n))حسّاس حرارة ورطوبة.
sensor.measure()قياس جديد. وبعده temperature() وhumidity().
neopixel.NeoPixel(Pin(n, Pin.OUT), count)شريط من count ثنائيات.
strip[i] = (r, g, b), strip.fill(c)لون ثنائي واحد أو الجميع، في الذاكرة.
strip.write()إرسال الألوان إلى الشريط.
TouchPad(Pin(n)).read()قياس المسّ، على ESP32 فقط.
BMP280(i2c).read()الحرارة والضغط، من bmp280.py.
AHT20(i2c).read()الحرارة والرطوبة، من aht20.py.

قاموس المصطلحات – מילון מונחים:

بالعربيةبالعبريةEnglish
المرحّلממסרRelay
الملامسמגעContact
الدفيئةחממהGreenhouse
المنطقة الميتةאזור מתDead Zone
الرطوبةלחותHumidity
الضغط الجويלחץ אטמוספריAtmospheric Pressure
عصا التحكّمג׳ויסטיקJoystick
الإجابات النهائية لأسئلة الفصل
13.1 IB,min = 0.4 mA.

أسئلة للتمرين:

المستوى الأول — أساسي
1.
ما الفرق بين measure() وtemperature()؟
الإجابات: الأول يقرأ من الحسّاس، والثاني يعيد آخر قيمة قُرئت.
2.
ثبّتنا ألوان الشريط ولم يتغيّر شيء. ما الأمر الناقص؟
الإجابات: strip.write().
3.
لماذا لا يعمل برنامج TouchPad على Pico W؟
الإجابات: لأن هذا الصنف موجود على ESP32 فقط.
4.
ما دور ثنائي الدوران الحرّ في دائرة المرحّل؟
الإجابات: يمرّر تيار الملف عند الفصل، فيحمي الترانزستور من قفزة الجهد.
المستوى الثاني — تطبيق
5.
شريط من 30 ثنائيا، بقيمة نموذجية 60 mA للثنائي. كم تيارا نحتاج عند الأبيض الكامل؟
الإجابات: I = 1.8 A.
6.
عدّلوا joystick.py ليضيء LED_EXT ما دام الزر مضغوطا.
الإجابات: نضيف Pin(board.LED_EXT, Pin.OUT)، وفي الحلقة: led.value(1 - button.value()).
7.
لماذا نستعمل عتبتين في برنامج المرحّل؟ ماذا يحدث بعتبة واحدة عند حرارة تتذبذب حولها؟
الإجابات: بعتبة واحدة يفتح الملامس ويغلق مرارا، فيطقطق ويهترئ. العتبتان تمنعان ذلك.
المستوى الثالث — تحدٍّ
8.
اجعلوا decide في greenhouse.py بعتبتين لكل حالة حتى لا تتذبذب النافذة.
الإجابات: نحفظ الحالة الحالية، ولا ننتقل منها إلا إذا تجاوزت الحرارة عتبة أعلى للصعود أو أخفض للنزول.
9.
صمّموا مشروعا يضيء شريطا كلما اقترب جسم: كم ثنائيا لكل مسافة؟
الإجابات: مثلا: lit = COUNT - d * COUNT // 100 بين 0 و100 سم، مع فحص None وحصر النتيجة بين 0 وCOUNT.
لوحة القوانين: كل قوانين هذا الفصل مجموعة مع رسومها وجداول رموزها في الفصل 25 — لوحة القوانين الشاملة. (נוסחאון הספר)