'''
Voltaat Learn (http://learn.voltaat.com)
Link to the full tutorial:
Tutorial: Building a project to detect earthquakes using a Raspberry Pi Pico board
The function of the following script is to read the acceleration values from the
acceleration sensor, display the value on the screen, and sound an alarm when
the vibration intensity exceeds a certain limit.
Note: You can use this sketch with any Raspberry Pi Pico.
'''
import machine
from machine import Pin, I2C
from imu import MPU6050
from time import sleep, ticks_ms, ticks_diff
from lcd_api import LcdApi
from pico_i2c_lcd import I2cLcd
# تعريف الثوابت
I2C_ADDR = 0x27 # عنوان شاشة LCD على I2C
LCD_ROWS = 2 # عدد أسطر الشاشة
LCD_COLS = 16 # عدد أعمدة الشاشة
MPU6050_ADDR = 0x68 # عنوان حساس MPU6050
# إعدادات كشف الزلزال
EARTHQUAKE_THRESHOLD = 1.3 # عتبة التسارع لكشف الزلازل (g)
ALARM_DURATION = 5000 # مدة التنبيه بالمللي ثانية
CALIBRATION_SAMPLES = 100 # عدد العينات لمعايرة الحساس
# إعداد منفذ LED المدمج
led = machine.Pin("LED", machine.Pin.OUT)
led.off()
# إعداد زر للتهدئة/إعادة الضبط
button = Pin(15, Pin.IN, Pin.PULL_UP)
# إعداد بيزر للتنبيه
buzzer = Pin(14, Pin.OUT)
buzzer.off()
# تهيئة I2C0 لحساس MPU6050 على المنافذ 0 و 1
i2c0 = I2C(1, sda=Pin(18), scl=Pin(19), freq=400000)
# تهيئة I2C1 لشاشة LCD على المنافذ 16 و 17
i2c1 = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
# تهيئة شاشة LCD على I2C1
lcd = I2cLcd(i2c1, I2C_ADDR, LCD_ROWS, LCD_COLS)
# تهيئة حساس MPU6050 على I2C0
imu = MPU6050(i2c0)
# متغيرات النظام
alarm_active = False
alarm_start_time = 0
calibration_values = {"ax": 0, "ay": 0, "az": 0}
last_update_time = 0
update_interval = 200 # تحديث الشاشة كل 200 مللي ثانية
class EarthquakeDetector:
def __init__(self):
self.earthquake_detected = False
self.earthquake_magnitude = 0
self.max_acceleration = 0
self.base_acceleration = 1.0 # تسارع الجاذبية الأرضية
def calibrate_sensor(self):
"""معايرة الحساس بأخذ متوسط القراءات"""
lcd.clear()
lcd.putstr("Calibrating...")
sum_ax, sum_ay, sum_az = 0, 0, 0
for i in range(CALIBRATION_SAMPLES):
ax = imu.accel.x
ay = imu.accel.y
az = imu.accel.z
sum_ax += ax
sum_ay += ay
sum_az += az
# عرض شريط التقدم
progress = int((i+1) / CALIBRATION_SAMPLES * 16)
lcd.move_to(0, 1)
lcd.putstr("[" + "=" * progress + " " * (16-progress-2) + "]")
sleep(0.01)
calibration_values["ax"] = sum_ax / CALIBRATION_SAMPLES
calibration_values["ay"] = sum_ay / CALIBRATION_SAMPLES
calibration_values["az"] = sum_az / CALIBRATION_SAMPLES
# حساب تسارع الجاذبية الأساسي
self.base_acceleration = abs(calibration_values["az"])
lcd.clear()
lcd.putstr("Calibration Done!")
sleep(1)
def check_earthquake(self):
"""فحص وجود زلزال"""
global alarm_active, alarm_start_time
# قراءة القيم من الحساس مع تطبيق المعايرة
ax = imu.accel.x - calibration_values["ax"]
ay = imu.accel.y - calibration_values["ay"]
az = imu.accel.z - calibration_values["az"]
# حساب التسارع الكلي (باستثناء الجاذبية)
total_acceleration = (ax**2 + ay**2 + (az - self.base_acceleration)**2) ** 0.5
# حساب شدة الزلزال
earthquake_intensity = total_acceleration / EARTHQUAKE_THRESHOLD
# تتبع أقصى تسارع
if total_acceleration > self.max_acceleration:
self.max_acceleration = total_acceleration
# كشف الزلزال
if total_acceleration > EARTHQUAKE_THRESHOLD and not alarm_active:
self.earthquake_detected = True
self.earthquake_magnitude = earthquake_intensity
alarm_active = True
alarm_start_time = ticks_ms()
# تفعيل التنبيهات
led.on()
buzzer.on()
return True, total_acceleration, earthquake_intensity
# إيقاف التنبيه بعد المدة المحددة
if alarm_active and ticks_diff(ticks_ms(), alarm_start_time) > ALARM_DURATION:
alarm_active = False
led.off()
buzzer.off()
self.earthquake_detected = False
return False, total_acceleration, earthquake_intensity
# إنشاء كائن كاشف الزلازل
detector = EarthquakeDetector()
def display_system_info():
"""عرض معلومات النظام على الشاشة"""
lcd.clear()
lcd.putstr("Earthquake Detector")
lcd.move_to(0, 1)
lcd.putstr("Calibrating...")
def display_sensor_data(accel_total, intensity, earthquake_detected):
"""عرض بيانات الحساس على الشاشة"""
global last_update_time
current_time = ticks_ms()
# تحديث الشاشة فقط كل فترة زمنية محددة
if ticks_diff(current_time, last_update_time) > update_interval:
lcd.clear()
if earthquake_detected:
# عرض تحذير الزلزال
lcd.putstr("EARTHQUAKE!")
lcd.move_to(0, 1)
intensity_str = "Intensity: {:.1f}".format(intensity)
lcd.putstr(intensity_str[:16])
else:
# عرض البيانات العادية
accel_str = "Accel: {:.2f}g".format(accel_total)
lcd.putstr(accel_str)
lcd.move_to(0, 1)
status_str = "Status: Normal"
if alarm_active:
status_str = "Status: ALARM!"
lcd.putstr(status_str[:16])
last_update_time = current_time
def handle_button_press():
"""معالجة ضغط الزر"""
global alarm_active
if button.value() == 0: # الزر مضغوط
# إيقاف التنبيه
alarm_active = False
led.off()
buzzer.off()
# عرض رسالة تأكيد
lcd.clear()
lcd.putstr("Alarm Silenced")
sleep(1)
return True
return False
def check_i2c_devices():
"""فحص وجود الأجهزة على منافذ I2C"""
print("Checking I2C devices...")
# فحص I2C0 (MPU6050)
devices0 = i2c0.scan()
if devices0:
print("I2C0 devices found:", [hex(device) for device in devices0])
else:
print("No devices found on I2C0")
# فحص I2C1 (LCD)
devices1 = i2c1.scan()
if devices1:
print("I2C1 devices found:", [hex(device) for device in devices1])
else:
print("No devices found on I2C1")
return len(devices0) > 0 and len(devices1) > 0
# الدالة الرئيسية
def main():
# فحص وجود الأجهزة
lcd.clear()
lcd.putstr("Starting...")
print("Starting Earthquake Detection System")
if not check_i2c_devices():
lcd.clear()
lcd.putstr("I2C Error!")
lcd.move_to(0, 1)
lcd.putstr("Check connections")
print("I2C connection error. Please check your connections.")
while True:
sleep(1)
# عرض معلومات النظام
display_system_info()
sleep(1)
# معايرة الحساس
detector.calibrate_sensor()
# عرض رسالة جاهزية
lcd.clear()
lcd.putstr("System Ready")
lcd.move_to(0, 1)
lcd.putstr("Monitoring...")
sleep(1)
# الحلقة الرئيسية
while True:
# فحص ضغط الزر
handle_button_press()
# فحص وجود زلزال
earthquake_detected, accel_total, intensity = detector.check_earthquake()
# عرض البيانات على الشاشة
display_sensor_data(accel_total, intensity, earthquake_detected)
# طباعة البيانات على المنفذ التسلسلي للتحليل
ax = imu.accel.x - calibration_values["ax"]
ay = imu.accel.y - calibration_values["ay"]
az = imu.accel.z - calibration_values["az"]
print("AX:{:.2f} AY:{:.2f} AZ:{:.2f} Total:{:.2f}g EQ:{} Int:{:.1f}".format(
ax, ay, az, accel_total, earthquake_detected, intensity
))
# وميض LED إذا كان النظام في حالة تأهب
if alarm_active:
led.value(not led.value()) # تبديل حالة LED
buzzer.value(not buzzer.value()) # صوت متقطع
sleep(0.05) # تأخير قصير للحلقة
# تشغيل النظام
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
# تنظيف الموارد عند الإيقاف
lcd.clear()
lcd.putstr("System Stopped")
led.off()
buzzer.off()
print("System stopped by user")
except Exception as e:
# معالجة الأخطاء
lcd.clear()
lcd.putstr("Error!")
lcd.move_to(0, 1)
error_msg = str(e)[:16]
lcd.putstr(error_msg)
print("Error:", e)