🌏 期末成果統合 · Interactive Exhibition Website

地震學理論
連結 Raspberry Pi 實作

這份統合版將你原本的「地震學學習回顧互動網頁」與「Raspberry Pi 微型地震儀成果展示網頁」整合成雙版面網站: 版面一負責說明地震學概念、野外觀測與案例分析;版面二負責展示 Raspberry Pi、MPU6050、LED、蜂鳴器、Discord Webhook 與成果影片。

走時曲線震源機制SmartSoloMPU6050PGADiscord 警報

版面一:地震學回顧

用震波走時、折射、反射、震源機制與嘉義大埔案例,說明「地震訊號如何被觀測與解釋」。

版面二:微型地震儀

用 Raspberry Pi 加上 MPU6050 感測加速度,透過 LED、蜂鳴器與 Discord 呈現預警系統成果。

2互動版面相互連結
1成果展示入口整合
3級震動門檻與聲光反應
PGA最大合成加速度紀錄

統合主線:從「理解地震」到「製作地震儀」

地震學版面回答的是:震波、斷層與觀測資料如何幫助我們理解地震;Raspberry Pi 版面回答的是:如何把這些概念轉成可展示的感測、判斷與警報系統。 因此兩個版面不是分開的作業,而是一條完整的學習路徑。

1. 地震訊號由震波與地動紀錄出發,理解資料背後的物理意義。
2. 感測資料用 MPU6050 讀取三軸加速度,轉成可判讀的數值。
3. 門檻判斷以 PGA 與三級門檻控制 LED、蜂鳴器與雲端推播。
4. 成果展示以互動式網頁整合理論、程式、影片、困難與解決方案。
PAGE 01

地震學學習回顧版面

此版面嵌入你上傳的地震學互動網頁,保留原本的學習地圖、章節核心、SmartSolo、嘉義大埔案例、反思與測驗。

連到 Raspberry Pi 版面
地震學學習回顧|互動式網頁
下一版面 →
PAGE 02

Raspberry Pi 微型地震儀版面

此版面嵌入你前面製作的 Raspberry Pi 成果展示網頁,保留主程式、接線教學、門檻模擬、成果影片、預期成果、製作困難與解決辦法。

回到地震學版面
Raspberry Pi 簡易地震儀互動教學網頁
← 上一版面
主程式快速檢視:main_seismic_station.py
import smbus
import time
import math
import requests
from datetime import datetime
import RPi.GPIO as GPIO

# ==============================================================================
#  核心參數設定區
# ==============================================================================
# ⚠️ 請將下方字串替換為你測試成功的 Discord Webhook 網址(若無請保持原樣)
DISCORD_WEBHOOK_URL = "在這裡貼上你的_Discord_Webhook_網址"

# 三級震動門檻設定 (單位: g)
THRESHOLD_L1 = 1.0  
THRESHOLD_L2 = 1.5  
THRESHOLD_L3 = 2.0  

COOLDOWN_TIME = 7      # 警報冷卻時間 (單位: 秒)
LED_PIN = 18             # 使用 GPIO 18 (支援硬體 PWM)
BUZZER_PIN = 24          # 蜂鳴器使用 GPIO 24

# ==============================================================================
#  硬體初始化
# ==============================================================================
GPIO.setmode(GPIO.BCM)

# 1. LED 初始化
GPIO.setup(LED_PIN, GPIO.OUT)
led_pwm = GPIO.PWM(LED_PIN, 1000)
led_pwm.start(0)

# 2. 蜂鳴器初始化
GPIO.setup(BUZZER_PIN, GPIO.OUT)
buzzer_pwm = GPIO.PWM(BUZZER_PIN, 2000)
buzzer_pwm.start(0)

# 3. MPU6050 I2C 初始化
Device_Address = 0x68
PWR_MGMT_1   = 0x6B
ACCEL_XOUT_H = 0x3B

bus = smbus.SMBus(1)
try:
    bus.write_byte_data(Device_Address, PWR_MGMT_1, 1) # 喚醒感測器
    print("\033[92m[系統] ✅ MPU6050 硬體初始化成功。\033[0m")
except OSError:
    print("\033[91m[錯誤] ❌ 無法連線至 MPU6050,請檢查線路是否插緊。\033[0m")
    GPIO.cleanup()
    exit()

# ==============================================================================
#  功能函式定義
# ==============================================================================
def read_raw_data(addr):
    high = bus.read_byte_data(Device_Address, addr)
    low = bus.read_byte_data(Device_Address, addr+1)
    value = ((high << 8) | low)
    if value > 32768:
        value = value - 65536
    return value

def send_discord_alert(accel_val, level_title):
    if "在這裡貼上你的" in DISCORD_WEBHOOK_URL or not DISCORD_WEBHOOK_URL.startswith("http"):
        return

    current_time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
    payload = {
        "content": f"🚨 **【地震觀測站警報發布】** 🚨\n"
                   f"📢 **警報等級:** {level_title}\n"
                   f"📅 **觸發時間:** `{current_time_str}`\n"
                   f"📈 **最大合成加速度:** **{accel_val:.3f} g**\n"
                   f"💡 *現場警報器與 LED 燈組已同步全力運作中!*"
    }
    try:
        requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=5)
    except Exception:
        pass # 忽略網路報錯,確保現場運作順暢

# ==============================================================================
#  主迴圈監測邏輯
# ==============================================================================
last_alert_time = 0
max_pga_record = 0.0  # ✨ 優化四:紀錄本次實驗啟動以來的「地表最大加速度」

print("\n=======================================================")
print("  🌋 微型地震預警與環境監測系統 (成果發表終極版) 🌋 ")
print("=======================================================")
print("正在即時採樣中... (欲停止監測或重設請按 Ctrl+C)\n")

try:
    while True:
        try:
            # 1. 讀取三個軸向的原始資料
            acc_x = read_raw_data(ACCEL_XOUT_H) / 16384.0
            acc_y = read_raw_data(ACCEL_XOUT_H + 2) / 16384.0
            acc_z = read_raw_data(ACCEL_XOUT_H + 4) / 16384.0
        except OSError:
            print("⚠️ [警告] 訊號瞬間中斷,正在自動防護重試...", end='\r')
            time.sleep(0.05)
            continue
        
        # 2. 計算三軸合成空間向量大小
        total_accel = math.sqrt(acc_x**2 + acc_y**2 + acc_z**2)
        
        # ✨ 優化四:如果突破歷史最高紀錄,就地更新!
        if total_accel > max_pga_record:
            max_pga_record = total_accel
        
        # 3. 判斷當前震動等級與對應的「特效參數」
        current_level = 0
        level_text = ""
        flash_period = 1.0  
        buzzer_freq = 1000
        led_brightness = 0

        # ✨ 優化三:利用時間正弦波,為低階地震打造優雅的呼吸燈特效
        # time.time() * 6 代表速度,透過 sin 讓數值在 0 ~ 1 之間來回起伏
        breathing_brightness = int((math.sin(time.time() * 6) + 1) / 2 * 20) # 最高 20% 安全亮度

        if total_accel >= THRESHOLD_L3:
            current_level = 3
            level_text = "🔴【三級:強烈有感地震】"
            flash_period = 0.15 # 爆閃
            # ✨ 優化二:三級地震採用「空襲警報式」高頻連續高音
            buzzer_freq = 2500 if (int(time.time() * 10) % 2 == 0) else 2000
            led_brightness = 40  # 提高亮度以彰顯災情
            
        elif total_accel >= THRESHOLD_L2:
            current_level = 2
            level_text = "🟠【二級:中度有感地震】"
            flash_period = 0.4 
            # ✨ 優化二:二級地震採用「救護車式」雙音頻交替切換 (逼~啵~)
            buzzer_freq = 800 if (int(time.time() * 4) % 2 == 0) else 1300
            led_brightness = 20
            
        elif total_accel >= THRESHOLD_L1:
            current_level = 1
            level_text = "🟡【一級:輕微有感地震】"
            flash_period = 1.0 
            buzzer_freq = 440   # 溫和低沉單音
            led_brightness = breathing_brightness # 啟用呼吸燈特效

        # ✨ 優化一:終端機動態進度條美化與色彩系統
        # 以 3.5g 為滿格 (35 格) 進行比例計算
        bar_length = min(int(total_accel * 10), 35)
        bar = "█" * bar_length + "░" * (35 - bar_length)
        
        if current_level == 3:
            color_code = "\033[91m"  # 搶眼紅
        elif current_level == 2:
            color_code = "\033[93m"  # 警告橘黃
        elif current_level == 1:
            color_code = "\033[96m"  # 水藍綠
        else:
            color_code = "\033[92m"  # 安全綠

        # 終端機同一行不斷刷新,同時顯示動態能量條與右側的「歷史最大紀錄保持」
        print(f"{color_code}[{bar}] 即時震度: {total_accel:.2f}g (L{current_level}) \033[0m | 🏆 \033[1;35m最高 PGA 紀錄: {max_pga_record:.2f} g\033[0m", end='\r')

        # 4. 執行硬體反應與報警
        if current_level > 0:
            # 針對二級與三級,實施週期性的閃爍與鳴叫
            if current_level in [2, 3]:
                if (time.time() % flash_period) < (flash_period / 2):
                    led_pwm.ChangeDutyCycle(led_brightness)          
                    buzzer_pwm.ChangeFrequency(buzzer_freq)
                    buzzer_pwm.ChangeDutyCycle(30) # 固定 30% 電流輸出避免主動式蜂鳴器破音
                else:
                    led_pwm.ChangeDutyCycle(0)           
                    buzzer_pwm.ChangeDutyCycle(0)        
            else:
                # 一級地震直接輸出平滑的呼吸燈,並維持單音鳴叫
                led_pwm.ChangeDutyCycle(led_brightness)
                buzzer_pwm.ChangeFrequency(buzzer_freq)
                buzzer_pwm.ChangeDutyCycle(10) # 輕微提示音量

            # Discord 雲端推播 (含冷卻機制)
            current_timestamp = time.time()
            if current_timestamp - last_alert_time > COOLDOWN_TIME:
                # 在畫面上印出乾淨漂亮的警報發布觸發通知
                print(f"\n\033[1;33m🔥 [觀測站事件發布] {level_text}!數值: {total_accel:.2f} g\033[0m")
                send_discord_alert(total_accel, level_text)
                last_alert_time = current_timestamp
        else:
            # 安全無事狀態,全部歸零
            led_pwm.ChangeDutyCycle(0)
            buzzer_pwm.ChangeDutyCycle(0)
            
        time.sleep(0.04) # 稍微提高採樣率至每秒約 25 次,抓取晃動更靈敏

except KeyboardInterrupt:
    print("\n\n\033[95m[系統] 收到終止指令,正在安全下線觀測站...")
    led_pwm.stop()
    buzzer_pwm.stop()
    GPIO.cleanup()
    print("[系統] 所有硬體資源已安全釋放。最大 PGA 歷史紀錄為: {:.2f} g。再見!\033[0m".format(max_pga_record))