convert the Data from Table into Insert Sentence.

本文介绍了一个SQL Server存储过程的示例,该存储过程用于从指定表中读取并构造插入语句,同时处理了表不存在、非表对象及特殊数据类型的字段等情况。

CREATE       PROCEDURE   dbo.UspOutputData  
  @tablename   sysname  
  AS  
  declare   @column   varchar(1000)  
  declare   @columndata   varchar(1000)  
  declare   @sql   varchar(4000)  
  declare   @xtype   tinyint  
  declare   @name   sysname  
  declare   @objectId   int  
  declare   @objectname   sysname  
  declare   @ident   int  
   
  set   nocount   on  
  set   @objectId=object_id(@tablename)  
   
  if   @objectId   is   null   --   判斷對象是否存在    
  begin    
  print   'The   object   not   exists'    
  return    
  end    
  set     @objectname=object_name(@objectId)  
   
  if     @objectname   is   null   or   charindex(@objectname,@tablename)=0   --此判断不严密  
  begin  
  print   'object   not   in   current   database'  
  return  
  end  
   
  if   OBJECTPROPERTY(@objectId,'IsTable')   <>   1   --   判斷對象是否是table    
  begin    
  print   'The   object   is   not   table'    
  return    
  end    
   
  select   @ident=status&0x80     from   syscolumns   where   id=@objectid   and   status&0x80=0x80  
   
  if   @ident   is   not   null  
  print   'SET   IDENTITY_INSERT   '+@TableName+'   ON'  
   
  declare   syscolumns_cursor   cursor    
  for   select   c.name,c.xtype   from   syscolumns   c  
  where   c.id=@objectid  
  order   by   c.colid  
  open   syscolumns_cursor  
  set   @column=''  
  set   @columndata=''  
  fetch   next   from   syscolumns_cursor   into   @name,@xtype  
  while   @@fetch_status   <>-1  
  begin  
  if   @@fetch_status<>-2  
  begin  
  if   @xtype   not   in(189,34,35,99,98)   --timestamp不需处理,image,text,ntext,sql_variant   暂时不处理  
  begin  
  set   @column=@column+case   when   len(@column)=0   then''   else   ','end+@name  
  set   @columndata=@columndata+case   when   len(@columndata)=0   then   ''   else   ','','','end  
  +case   when   @xtype   in(167,175)   then   '''''''''+'+@name+'+'''''''''   --varchar,char  
  when   @xtype   in(231,239)   then   '''N''''''+'+@name+'+'''''''''   --nvarchar,nchar  
  when   @xtype=61   then   '''''''''+convert(char(23),'+@name+',121)+'''''''''   --datetime  
  when   @xtype=58   then   '''''''''+convert(char(16),'+@name+',120)+'''''''''   --smalldatetime  
  when   @xtype=36   then   '''''''''+convert(char(36),'+@name+')+'''''''''   --uniqueidentifier  
  else   @name   end  
  end  
  end      
  fetch   next   from   syscolumns_cursor   into   @name,@xtype  
  end  
  close   syscolumns_cursor  
  deallocate   syscolumns_cursor  
   
  set   @sql='set   nocount   on   select   ''insert   '+@tablename+'('+@column+')   values(''as   ''--'','+@columndata+','')''   from   '+@tablename  
   
  print   '--'+@sql  
  exec(@sql)  
   
  if   @ident   is   not   null  
  print   'SET   IDENTITY_INSERT   '+@TableName+'   OFF'  
   
  GO 

import os import time import threading import RPi.GPIO as GPIO import cv2 import numpy as np import pyaudio import vosk import json import serial import pynmea2 import datetime import sqlite3 from pathlib import Path import logging import sys # ------------------- 硬件与模型配置 ------------------- BUZZER_PIN = 18 # BCM模式 FREQ_LOW = 1000 FREQ_HIGH = 2000 BUZZER_DURATION = 60 # 蜂鸣器持续秒数 PIR_PIN = 17 # BCM模式 FACE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_alt2.xml' PROFILE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_profileface.xml' VOSK_MODEL_PATH = "/home/pi/vosk-model-small-cn-0.22" # ------------------- 全局变量 ------------------- pwm = None detection_triggered = False # 检测到人/救命标记 buzzer_active = False # 蜂鸣器运行标记 cap = None # 全局摄像头对象 face_cascade = None # 全局人脸分类器 profile_cascade = None # 全局侧脸分类器 # ------------------- 蜂鸣器控制 ------------------- def setup_buzzer(): global pwm GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(BUZZER_PIN, GPIO.OUT) pwm = GPIO.PWM(BUZZER_PIN, FREQ_LOW) def run_buzzer(): global buzzer_active, detection_triggered buzzer_active = True pwm.start(50) start_time = time.time() while (time.time() - start_time < BUZZER_DURATION) and buzzer_active and not detection_triggered: pwm.ChangeFrequency(FREQ_LOW) time.sleep(0.5) pwm.ChangeFrequency(FREQ_HIGH) time.sleep(0.5) pwm.stop() buzzer_active = False # ------------------- PIR + 人脸检测 ------------------- def setup_pir(): GPIO.setup(PIR_PIN, GPIO.IN) def setup_camera_and_cascades(): global cap, face_cascade, profile_cascade cap = cv2.VideoCapture(0) if not cap.isOpened(): print("错误:摄像头无法打开!") return False cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH) profile_cascade = cv2.CascadeClassifier(PROFILE_CASCADE_PATH) if face_cascade.empty() or profile_cascade.empty(): print("错误:人脸分类器加载失败!") return False print("摄像头+分类器初始化完成") return True def detect_human(): global cap, face_cascade, profile_cascade if not cap or not cap.isOpened(): return False ret, img = cap.read() if not ret: return False img = cv2.flip(img, 1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30)) profiles = profile_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30)) if len(faces) > 0 or len(profiles) > 0: print(f"检测到:正脸{len(faces)}个,侧脸{len(profiles)}个") return len(faces) > 0 or len(profiles) > 0 def monitor_pir(): global detection_triggered, buzzer_active print("PIR监控线程启动") while buzzer_active and not detection_triggered: current_val = GPIO.input(PIR_PIN) if current_val == 1: print("PIR检测到活动,持续人脸检测...") if detect_human(): detection_triggered = True print("1(检测到人体)") break time.sleep(0.5) print("PIR监控线程退出") # ------------------- Vosk 人声识别 ------------------- def setup_voice_recognition(): if not os.path.exists(VOSK_MODEL_PATH): print("错误:Vosk模型目录不存在!") return None, None, None model = vosk.Model(VOSK_MODEL_PATH) recognizer = vosk.KaldiRecognizer(model, 16000) p = pyaudio.PyAudio() stream = p.open( format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4000, input_device_index=None ) return recognizer, stream, p def monitor_voice(recognizer, stream): global detection_triggered, buzzer_active while buzzer_active and not detection_triggered: data = stream.read(4000, exception_on_overflow=False) if recognizer.AcceptWaveform(data): result = json.loads(recognizer.Result()) text = result.get("text", "").strip() clean_text = text.replace(" ", "").replace("!", "").replace(",", "") if "救命" in clean_text: detection_triggered = True print("1(人声识别到'救命')") break # ------------------- 资源释放 ------------------- def cleanup(): global buzzer_active, detection_triggered, cap buzzer_active = False detection_triggered = False if cap and cap.isOpened(): cap.release() print("摄像头已释放") if pwm: pwm.stop() GPIO.cleanup() cv2.destroyAllWindows() if 'stream' in globals() and 'p_audio' in globals(): stream.stop_stream() stream.close() p_audio.terminate() print("程序已停止,资源已释放") # ------------------- GPS 功能 ------------------- def check_dialout_permission(): try: groups = os.popen('groups').read().strip() if 'dialout' in groups: return True else: logging.warning("当前用户不在dialout组中,可能无法访问串口") logging.warning("请运行: sudo usermod -aG dialout $USER,然后重新登录") return False except Exception as e: logging.warning(f"检查权限时出错: {e}") return False class ATK1218GPS: def __init__(self, port='/dev/ttyS0', baudrate=9600, timeout=2): self.port = port self.baudrate = baudrate self.timeout = timeout self.ser = None self.db_conn = None self.init_database() logging.info(f"配置为使用 {self.port} 串口") def connect(self): try: self.ser = serial.Serial( self.port, self.baudrate, timeout=self.timeout, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, xonxoff=False, rtscts=False ) if self.ser.is_open: logging.info(f"成功连接到GPS模块: {self.port}") return True else: logging.error(f"无法打开 {self.port} 端口") return False except PermissionError: logging.error(f"权限不足,无法访问 {self.port}") logging.error("请确保用户已加入dialout组并重新登录") return False except Exception as e: logging.error(f"连接GPS模块失败: {e}") return False def init_database(self): try: self.db_conn = sqlite3.connect("gps_data/location.db") cursor = self.db_conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME, latitude REAL, longitude REAL, altitude REAL, satellites INTEGER, speed REAL, course REAL, fix_quality INTEGER ) ''') cursor.execute("PRAGMA table_info(locations)") columns = [column[1] for column in cursor.fetchall()] if 'speed' not in columns: cursor.execute("ALTER TABLE locations ADD COLUMN speed REAL") logging.info("已添加speed列到数据库表") if 'course' not in columns: cursor.execute("ALTER TABLE locations ADD COLUMN course REAL") logging.info("已添加course列到数据库表") self.db_conn.commit() logging.info("数据库初始化成功") except Exception as e: logging.error(f"数据库初始化失败: {e}") def parse_nmea_sentence(self, sentence): try: if not sentence.startswith('$'): return None msg = pynmea2.parse(sentence) if isinstance(msg, pynmea2.GGA): data = { 'timestamp': datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': float(msg.altitude) if msg.altitude else None, 'satellites': int(msg.num_sats) if msg.num_sats else None, 'speed': None, 'course': None, 'fix_quality': int(msg.gps_qual) if msg.gps_qual else 0 } return data elif isinstance(msg, pynmea2.RMC): data = { 'timestamp': datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': None, 'satellites': None, 'speed': float(msg.spd_over_grnd) if msg.spd_over_grnd else None, 'course': float(msg.true_course) if msg.true_course else None, 'fix_quality': 1 if msg.status == 'A' else 0 } return data return None except pynmea2.ParseError: return None except Exception as e: logging.warning(f"解析NMEA数据出错: {e}, 数据: {sentence}") return None def convert_to_decimal(self, value, direction): if not value: return None try: val = float(value) degrees = int(val // 100) minutes = val % 100 decimal_degrees = degrees + minutes / 60 if direction in ['S', 'W']: decimal_degrees = -decimal_degrees return round(decimal_degrees, 6) except: return None def save_location(seimport os import time import threading import RPi.GPIO as GPIO import cv2 import numpy as np import pyaudio import vosk import json import serial import pynmea2 import datetime import sqlite3 from pathlib import Path import logging import sys # ------------------- 硬件与模型配置 ------------------- BUZZER_PIN = 18 # BCM模式 FREQ_LOW = 1000 FREQ_HIGH = 2000 BUZZER_DURATION = 60 # 蜂鸣器持续秒数 PIR_PIN = 17 # BCM模式 FACE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_alt2.xml' PROFILE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_profileface.xml' VOSK_MODEL_PATH = "/home/pi/vosk-model-small-cn-0.22" # ------------------- 全局变量 ------------------- pwm = None detection_triggered = False # 检测到人/救命标记 buzzer_active = False # 蜂鸣器运行标记 cap = None # 全局摄像头对象 face_cascade = None # 全局人脸分类器 profile_cascade = None # 全局侧脸分类器 # ------------------- 蜂鸣器控制 ------------------- def setup_buzzer(): global pwm GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(BUZZER_PIN, GPIO.OUT) pwm = GPIO.PWM(BUZZER_PIN, FREQ_LOW) def run_buzzer(): global buzzer_active, detection_triggered buzzer_active = True pwm.start(50) start_time = time.time() while (time.time() - start_time < BUZZER_DURATION) and buzzer_active and not detection_triggered: pwm.ChangeFrequency(FREQ_LOW) time.sleep(0.5) pwm.ChangeFrequency(FREQ_HIGH) time.sleep(0.5) pwm.stop() buzzer_active = False # ------------------- PIR + 人脸检测 ------------------- def setup_pir(): GPIO.setup(PIR_PIN, GPIO.IN) def setup_camera_and_cascades(): global cap, face_cascade, profile_cascade cap = cv2.VideoCapture(0) if not cap.isOpened(): print("错误:摄像头无法打开!") return False cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH) profile_cascade = cv2.CascadeClassifier(PROFILE_CASCADE_PATH) if face_cascade.empty() or profile_cascade.empty(): print("错误:人脸分类器加载失败!") return False print("摄像头+分类器初始化完成") return True def detect_human(): global cap, face_cascade, profile_cascade if not cap or not cap.isOpened(): return False ret, img = cap.read() if not ret: return False img = cv2.flip(img, 1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30)) profiles = profile_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30)) if len(faces) > 0 or len(profiles) > 0: print(f"检测到:正脸{len(faces)}个,侧脸{len(profiles)}个") return len(faces) > 0 or len(profiles) > 0 def monitor_pir(): global detection_triggered, buzzer_active print("PIR监控线程启动") while buzzer_active and not detection_triggered: current_val = GPIO.input(PIR_PIN) if current_val == 1: print("PIR检测到活动,持续人脸检测...") if detect_human(): detection_triggered = True print("1(检测到人体)") break time.sleep(0.5) print("PIR监控线程退出") # ------------------- Vosk 人声识别 ------------------- def setup_voice_recognition(): if not os.path.exists(VOSK_MODEL_PATH): print("错误:Vosk模型目录不存在!") return None, None, None model = vosk.Model(VOSK_MODEL_PATH) recognizer = vosk.KaldiRecognizer(model, 16000) p = pyaudio.PyAudio() stream = p.open( format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4000, input_device_index=None ) return recognizer, stream, p def monitor_voice(recognizer, stream): global detection_triggered, buzzer_active while buzzer_active and not detection_triggered: data = stream.read(4000, exception_on_overflow=False) if recognizer.AcceptWaveform(data): result = json.loads(recognizer.Result()) text = result.get("text", "").strip() clean_text = text.replace(" ", "").replace("!", "").replace(",", "") if "救命" in clean_text: detection_triggered = True print("1(人声识别到'救命')") break # ------------------- 资源释放 ------------------- def cleanup(): global buzzer_active, detection_triggered, cap buzzer_active = False detection_triggered = False if cap and cap.isOpened(): cap.release() print("摄像头已释放") if pwm: pwm.stop() GPIO.cleanup() cv2.destroyAllWindows() if 'stream' in globals() and 'p_audio' in globals(): stream.stop_stream() stream.close() p_audio.terminate() print("程序已停止,资源已释放") # ------------------- GPS 功能 ------------------- def check_dialout_permission(): try: groups = os.popen('groups').read().strip() if 'dialout' in groups: return True else: logging.warning("当前用户不在dialout组中,可能无法访问串口") logging.warning("请运行: sudo usermod -aG dialout $USER,然后重新登录") return False except Exception as e: logging.warning(f"检查权限时出错: {e}") return False class ATK1218GPS: def __init__(self, port='/dev/ttyS0', baudrate=9600, timeout=2): self.port = port self.baudrate = baudrate self.timeout = timeout self.ser = None self.db_conn = None self.init_database() logging.info(f"配置为使用 {self.port} 串口") def connect(self): try: self.ser = serial.Serial( self.port, self.baudrate, timeout=self.timeout, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, xonxoff=False, rtscts=False ) if self.ser.is_open: logging.info(f"成功连接到GPS模块: {self.port}") return True else: logging.error(f"无法打开 {self.port} 端口") return False except PermissionError: logging.error(f"权限不足,无法访问 {self.port}") logging.error("请确保用户已加入dialout组并重新登录") return False except Exception as e: logging.error(f"连接GPS模块失败: {e}") return False def init_database(self): try: self.db_conn = sqlite3.connect("gps_data/location.db") cursor = self.db_conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME, latitude REAL, longitude REAL, altitude REAL, satellites INTEGER, speed REAL, course REAL, fix_quality INTEGER ) ''') cursor.execute("PRAGMA table_info(locations)") columns = [column[1] for column in cursor.fetchall()] if 'speed' not in columns: cursor.execute("ALTER TABLE locations ADD COLUMN speed REAL") logging.info("已添加speed列到数据库表") if 'course' not in columns: cursor.execute("ALTER TABLE locations ADD COLUMN course REAL") logging.info("已添加course列到数据库表") self.db_conn.commit() logging.info("数据库初始化成功") except Exception as e: logging.error(f"数据库初始化失败: {e}") def parse_nmea_sentence(self, sentence): try: if not sentence.startswith('$'): return None msg = pynmea2.parse(sentence) if isinstance(msg, pynmea2.GGA): data = { 'timestamp': datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': float(msg.altitude) if msg.altitude else None, 'satellites': int(msg.num_sats) if msg.num_sats else None, 'speed': None, 'course': None, 'fix_quality': int(msg.gps_qual) if msg.gps_qual else 0 } return data elif isinstance(msg, pynmea2.RMC): data = { 'timestamp': datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': None, 'satellites': None, 'speed': float(msg.spd_over_grnd) if msg.spd_over_grnd else None, 'course': float(msg.true_course) if msg.true_course else None, 'fix_quality': 1 if msg.status == 'A' else 0 } return data return None except pynmea2.ParseError: return None except Exception as e: logging.warning(f"解析NMEA数据出错: {e}, 数据: {sentence}") return None def convert_to_decimal(self, value, direction): if not value: return None try: val = float(value) degrees = int(val // 100) minutes = val % 100 decimal_degrees = degrees + minutes / 60 if direction in ['S', 'W']: decimal_degrees = -decimal_degrees return round(decimal_degrees, 6) except: return None def save_location(self, location_data): if not location_data or not self.db_conn: return False try: cursor = self.db_conn.cursor() cursor.execute(''' INSERT INTO locations (timestamp, latitude, longitude, altitude, satellites, speed, course, fix_quality) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', ( location_data['timestamp'], location_data['latitude'], location_data['longitude'], location_data['altitude'], location_data['satellites'], location_data['speed'], location_data['course'], location_data['fix_quality'] )) self.db_conn.commit() with open("gps_data/latest_location.txt", "w") as f: f.write(f"时间: {location_data['timestamp']}\n") f.write(f"纬度: {location_data['latitude']}\n") f.write(f"经度: {location_data['longitude']}\n") if location_data['altitude']: f.write(f"海拔: {location_data['altitude']} 米\n") if location_data['speed']: f.write(f"速度: {location_data['speed']} 节\n") f.write(f"航向: {location_data['course']} 度\n") if location_data['satellites']: f.write(f"卫星数量: {location_data['satellites']}\n") f.write(f"定位质量: {location_data['fix_quality']}\n") return True except Exception as e: logging.error(f"保存定位信息失败: {e}") return False def get_location(self, timeout=30): """获取有效位置信息,超时返回None""" if not self.ser or not self.ser.is_open: logging.warning("请先连接GPS模块") return None start_time = time.time() logging.info("开始获取GPS定位...") try: while time.time() - start_time < timeout: data = self.ser.readline().decode('utf-8', errors='ignore').strip() if data: location_data = self.parse_nmea_sentence(data) if location_data and location_data.get('fix_quality', 0) > 0: logging.info(f"成功获取定位: {location_data}") self.save_location(location_data) return location_data time.sleep(0.1) logging.warning("获取GPS定位超时") return None except Exception as e: logging.error(f"获取定位数据出错: {e}") return None def close(self): if self.ser and self.ser.is_open: self.ser.close() logging.info("已关闭GPS模块连接") if self.db_conn: self.db_conn.close() logging.info("已关闭数据库连接") # ------------------- LORA 功能 ------------------- class LoRaReceiver: def __init__(self, port='/dev/ttyACM0', baudrate=9600, timeout=0.1): self.port = port self.baaudrate = baudrate self.timeout = timeout self.ser = None self.running = False def open(self): try: self.ser = serial.Serial(self.port, self.baudrate, timeout=self.timeout) print(f"成功打开串口 {self.ser.name}") self.running = True return True except Exception as e: print(f"打开串口失败:{e}") return False def receive_data(self): if not self.ser or not self.ser.is_open: print("串口未打开,请先调用open()方法") return None if self.ser.in_waiting > 0: try: data = self.ser.read(self.ser.in_waiting).decode('utf-8', errors='ignore') timestamp = time.strftime('%H:%M:%S') return { 'timestamp': timestamp, 'data': data.strip() } except Exception as e: print(f"接收数据错误:{e}") return None return None def close(self): if self.ser and self.ser.is_open: self.ser.close() self.running = False print("串口已关闭") def start_listening(self, callback=None): if not self.open(): return try: print("开始监听LoRa数据... (按Ctrl+C停止)") while self.running: data = self.receive_data() if data: print(f"[{data['timestamp']}] 收到LoRa数据:{data['data']}") if callback and callable(callback): callback(data) time.sleep(0.1) except KeyboardInterrupt: print("\n用户中断监听") finally: self.close() class LoRaSender: def __init__(self, port='/dev/ttyACM0', baud_rate=9600, timeout=1): self.port = port self.baud_rate = baud_rate self.timeout = timeout self.ser = None def open(self): try: self.ser = serial.Serial(self.port, self.baud_rate, timeout=self.timeout) print(f"成功打开串口 {self.ser.name}") return True except Exception as e: print(f"打开串口失败:{e}") return False def send_message(self, message): if not self.ser or not self.ser.is_open: print("串口未打开,请先调用open()方法") return False if not message: print("消息为空,不发送") return False try: self.ser.write(message.encode('utf-8')) print(f"✅ 已发送:{message}") return True except Exception as e: print(f"发送失败:{e}") return False def close(self): if self.ser and self.ser.is_open: self.ser.close() print("串口已关闭") def send_and_close(self, message): try: if self.open(): self.send_message(message) time.sleep(0.1) finally: self.close() # ------------------- 主函数 ------------------- def main(): # 确保数据目录存在 data_dir = Path("gps_data") data_dir.mkdir(exist_ok=True) # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("gps_data/gps_log.log"), logging.StreamHandler() ] ) # 检查权限 if not check_dialout_permission(): logging.warning("串口访问权限可能存在问题") # 初始化LoRa接收器 lora_receiver = LoRaReceiver(port='/dev/ttyACM0') # 等待接收LoRa信号 print("等待接收LoRa信号...") lora_receiver.open() try: while True: data = lora_receiver.receive_data() if data: print(f"接收到LoRa信号: {data['data']}") # 如果接收到信号,启动检测流程 start_detection() # 检测完成后退出循环 break time.sleep(1) except KeyboardInterrupt: print("\n用户中断程序") finally: lora_receiver.close() cleanup() def start_detection(): global detection_triggered, buzzer_active # 初始化硬件 setup_buzzer() setup_pir() if not setup_camera_and_cascades(): cleanup() return recognizer, stream, p_audio = setup_voice_recognition() if not recognizer or not stream or not p_audio: cleanup() return # 启动状态 detection_triggered = False buzzer_active = True # 启动线程 buzzer_thread = threading.Thread(target=run_buzzer, daemon=True) pir_thread = threading.Thread(target=monitor_pir, daemon=True) voice_thread = threading.Thread(target=monitor_voice, args=(recognizer, stream), daemon=True) buzzer_thread.start() pir_thread.start() voice_thread.start() # 主线程等待 while buzzer_active and not detection_triggered: time.sleep(1) # 如果检测到人,获取GPS位置并通过LoRa发送 if detection_triggered: # 获取GPS位置 gps = ATK1218GPS(port='/dev/ttyAMA0', baudrate=38400) if gps.connect(): location_data = gps.get_location(timeout=30) gps.close() if location_data: # 格式化位置信息 location_str = f"紧急位置: 纬度 {location_data['latitude']}, 经度 {location_data['longitude']}" if location_data['altitude']: location_str += f", 海拔 {location_data['altitude']}米" # 通过LoRa发送位置信息 lora_sender = LoRaSender(port='/dev/ttyACM0') lora_sender.send_and_close(location_str) else: logging.error("无法获取GPS定位信息") else: logging.error("无法连接GPS模块") # 清理资源 cleanup() if __name__ == '__main__': try: main() except Exception as e: logging.error(f"程序执行出错: {e}") cleanup() sys.exit(1)我把多个入口程序合并成一个主函数入口,按照我的逻辑来写主函数的代码,首先需要用接收函数读出接收到的信息,如果接收到了这个信息以后那么进行原来靠前的_main_块(直接启动就行,不需要再让用户输入1),如果检测到有人就进行GPS的定位,然后读取出GPS的信息以后在通过LORA模块发送函数,把这个信息发送出去。你看我发给你的代码能不能满足我的要求,有什么缺陷,可以订正了一个给我完整
09-11
### 分析及完整修正代码 您的代码整体设计符合需求,但存在几个关键问题需要修正: 1. **GPS模块连接问题**: - 在`ATK1218GPS.connect()`中,波特率设置错误(GPS模块通常使用9600或115200波特率) - GPS数据解析函数逻辑需要优化 2. **LoRa模块问题**: - `LoRaReceiver`类中波特率拼写错误(`baaudrate`) - 缺少数据接收超时处理机制 3. **线程管理问题**: - 缺少线程退出条件检查 - 蜂鸣器控制逻辑需要优化 4. **资源泄露风险**: - 音频流未正确关闭 - GPS数据库连接未关闭 ### 完整修正代码 ```python import os import time import threading import RPi.GPIO as GPIO import cv2 import numpy as np import pyaudio import vosk import json import serial import pynmea2 import datetime import sqlite3 from pathlib import Path import logging import sys # ------------------- 硬件与模型配置 ------------------- BUZZER_PIN = 18 # BCM模式 FREQ_LOW = 1000 FREQ_HIGH = 2000 BUZZER_DURATION = 60 # 蜂鸣器持续秒数 PIR_PIN = 17 # BCM模式 FACE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_alt2.xml' PROFILE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_profileface.xml' VOSK_MODEL_PATH = "/home/pi/vosk-model-small-cn-0.22" # ------------------- 全局变量 ------------------- pwm = None detection_triggered = False buzzer_active = False cap = None face_cascade = None profile_cascade = None recognizer = None audio_stream = None audio_p = None gps_module = None # ------------------- 蜂鸣器控制 ------------------- def setup_buzzer(): global pwm GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(BUZZER_PIN, GPIO.OUT) pwm = GPIO.PWM(BUZZER_PIN, FREQ_LOW) print("蜂鸣器初始化完成") def run_buzzer(): global buzzer_active, detection_triggered buzzer_active = True pwm.start(50) start_time = time.time() while buzzer_active and not detection_triggered and (time.time() - start_time < BUZZER_DURATION): pwm.ChangeFrequency(FREQ_LOW) time.sleep(0.5) if buzzer_active and not detection_triggered: pwm.ChangeFrequency(FREQ_HIGH) time.sleep(0.5) pwm.stop() buzzer_active = False print("蜂鸣器停止") # ------------------- PIR + 人脸检测 ------------------- def setup_pir(): GPIO.setup(PIR_PIN, GPIO.IN) print("PIR传感器初始化完成") def setup_camera_and_cascades(): global cap, face_cascade, profile_cascade cap = cv2.VideoCapture(0) if not cap.isOpened(): print("错误:摄像头无法打开!") return False cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH) profile_cascade = cv2.CascadeClassifier(PROFILE_CASCADE_PATH) if face_cascade.empty() or profile_cascade.empty(): print("错误:人脸分类器加载失败!") return False print("摄像头+分类器初始化完成") return True def detect_human(): global cap, face_cascade, profile_cascade if not cap or not cap.isOpened(): return False ret, img = cap.read() if not ret: return False img = cv2.flip(img, 1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 优化检测参数 faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(40, 40)) profiles = profile_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(40, 40)) if len(faces) > 0 or len(profiles) > 0: print(f"检测到:正脸{len(faces)}个,侧脸{len(profiles)}个") return True return False def monitor_pir(): global detection_triggered, buzzer_active print("PIR监控线程启动") while buzzer_active and not detection_triggered: pir_val = GPIO.input(PIR_PIN) if pir_val == GPIO.HIGH: print("PIR检测到活动,开始人脸检测...") if detect_human(): detection_triggered = True print("检测到人体 - 触发警报") break time.sleep(0.3) print("PIR监控线程退出") # ------------------- 人声识别 ------------------- def setup_voice_recognition(): global recognizer, audio_stream, audio_p if not os.path.exists(VOSK_MODEL_PATH): print("错误:Vosk模型目录不存在!") return False try: model = vosk.Model(VOSK_MODEL_PATH) recognizer = vosk.KaldiRecognizer(model, 16000) audio_p = pyaudio.PyAudio() audio_stream = audio_p.open( format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4000 ) print("语音识别初始化完成") return True except Exception as e: print(f"语音识别初始化失败: {e}") return False def monitor_voice(): global detection_triggered, buzzer_active, recognizer, audio_stream print("语音监控线程启动") while buzzer_active and not detection_triggered: try: data = audio_stream.read(4000, exception_on_overflow=False) if recognizer.AcceptWaveform(data): result = json.loads(recognizer.Result()) text = result.get("text", "").strip() clean_text = text.replace(" ", "").replace("!", "").replace(",", "") if "救命" in clean_text: detection_triggered = True print("检测到'救命'呼喊 - 触发警报") break except Exception as e: print(f"语音处理错误: {e}") print("语音监控线程退出") # ------------------- GPS 功能 ------------------- def check_dialout_permission(): try: groups = os.getgroups() if 20 in groups: # dialout group ID return True logging.warning("当前用户不在dialout组中") return False except Exception as e: logging.warning(f"检查权限时出错: {e}") return False class ATK1218GPS: def __init__(self, port='/dev/ttyS0', baudrate=9600, timeout=2): self.port = port self.baudrate = baudrate self.timeout = timeout self.ser = None self.db_conn = None self.init_database() logging.info(f"GPS配置: {self.port}@{baudrate}bps") def connect(self): try: self.ser = serial.Serial( port=self.port, baudrate=self.baudrate, timeout=self.timeout, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS ) if self.ser.is_open: logging.info(f"GPS模块已连接") return True logging.error(f"无法打开端口 {self.port}") return False except PermissionError: logging.error("缺少串口访问权限,请添加到dialout组") return False except Exception as e: logging.error(f"连接GPS失败: {e}") return False def init_database(self): try: os.makedirs("gps_data", exist_ok=True) self.db_conn = sqlite3.connect("gps_data/location.db") cursor = self.db_conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, latitude REAL, longitude REAL, altitude REAL, satellites INTEGER, speed REAL, course REAL, fix_quality INTEGER ) ''') self.db_conn.commit() logging.info("GPS数据库就绪") return True except Exception as e: logging.error(f"数据库初始化失败: {极") return False def convert_to_decimal(self, value, direction): try: if not value: return None parts = value.split('.') degrees = float(parts[0][:-2]) minutes = float(parts[0][-2:] + '.' + parts[1]) decimal_degrees = degrees + minutes / 60 return -decimal_degrees if direction in ['S', 'W'] else decimal_degrees except: return None def parse_nmea_sentence(self, sentence): try: if not sentence.startswith('$'): return None msg = pynmea2.parse(sentence) if isinstance(msg, pynmea2.GGA): return { 'timestamp': datetime.datetime.utcnow(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': float(msg.altitude) if msg.altitude else 0.0, 'satellites': int(msg.num_sats) if msg.num_sats else 0, 'fix_quality': int(msg.gps_qual) } elif isinstance(msg, pynmea2.RMC) and msg.status == 'A': return { 'timestamp': datetime.datetime.combine( datetime.date.today(), datetime.time(int(msg.timestamp[0:2]), int(msg.timestamp[2:4]), int(msg.timestamp[4:6])) ), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'speed': float(msg.spd_over_grnd) * 1.852 if msg.spd_over_grnd else 0.0, # knots to km/h 'course': float(msg.true_course) if msg.true_course else 0.0, 'fix_quality': 1 } return None except Exception as e: logging.warning(f"解析NMEA错误: {e}") return None def get_location(self, timeout=30): """获取有效GPS位置""" if not self.ser or not self.ser.is_open: logging.error("GPS未连接") return None start_time = time.time() logging.info("获取GPS定位...") while not detection_triggered and time.time() - start_time < timeout: try: data = self.ser.readline().decode('ascii', errors='ignore').strip() if data: location = ### 分析及完整修正代码 您的代码整体设计符合需求,但存在几个关键问题需要修正: 1. **GPS模块连接问题**: - 在`ATK1218GPS.connect()`中,波特率设置错误(GPS模块通常使用9600或115200波特率) - GPS数据解析函数逻辑需要优化 2. **LoRa模块问题**: - `LoRaReceiver`类中波特率拼写错误(`baaudrate`) - 缺少数据接收超时处理机制 3. **线程管理问题**: - 缺少线程退出条件检查 - 蜂鸣器控制逻辑需要优化 4. **资源泄露风险**: - 音频流未正确关闭 - GPS数据库连接未关闭 ### 完整修正代码 ```python import os import time import threading import RPi.GPIO as GPIO import cv2 import numpy as np import pyaudio import vosk import json import serial import pynmea2 import datetime import sqlite3 from pathlib import Path import logging import sys # ------------------- 硬件与模型配置 ------------------- BUZZER_PIN = 18 # BCM模式 FREQ_LOW = 1000 FREQ_HIGH = 2000 BUZZER_DURATION = 60 # 蜂鸣器持续秒数 PIR_PIN = 17 # BCM模式 FACE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_alt2.xml' PROFILE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_profileface.xml' VOSK_MODEL_PATH = "/home/pi/vosk-model-small-cn-0.22" # ------------------- 全局变量 ------------------- pwm = None detection_triggered = False buzzer_active = False cap = None face_cascade = None profile_cascade = None recognizer = None audio_stream = None audio_p = None gps_module = None # ------------------- 蜂鸣器控制 ------------------- def setup_buzzer(): global pwm GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(BUZZER_PIN, GPIO.OUT) pwm = GPIO.PWM(BUZZER_PIN, FREQ_LOW) print("蜂鸣器初始化完成") def run_buzzer(): global buzzer_active, detection_triggered buzzer_active = True pwm.start(50) start_time = time.time() while buzzer_active and not detection_triggered and (time.time() - start_time < BUZZER_DURATION): pwm.ChangeFrequency(FREQ_LOW) time.sleep(0.5) if buzzer_active and not detection_triggered: pwm.ChangeFrequency(FREQ_HIGH) time.sleep(0.5) pwm.stop() buzzer_active = False print("蜂鸣器停止") # ------------------- PIR + 人脸检测 ------------------- def setup_pir(): GPIO.setup(PIR_PIN, GPIO.IN) print("PIR传感器初始化完成") def setup_camera_and_cascades(): global cap, face_cascade, profile_cascade cap = cv2.VideoCapture(0) if not cap.isOpened(): print("错误:摄像头无法打开!") return False cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH) profile_cascade = cv2.CascadeClassifier(PROFILE_CASCADE_PATH) if face_cascade.empty() or profile_cascade.empty(): print("错误:人脸分类器加载失败!") return False print("摄像头+分类器初始化完成") return True def detect_human(): global cap, face_cascade, profile_cascade if not cap or not cap.isOpened(): return False ret, img = cap.read() if not ret: return False img = cv2.flip(img, 1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 优化检测参数 faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(40, 40)) profiles = profile_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(40, 40)) if len(faces) > 0 or len(profiles) > 0: print(f"检测到:正脸{len(faces)}个,侧脸{len(profiles)}个") return True return False def monitor_pir(): global detection_triggered, buzzer_active print("PIR监控线程启动") while buzzer_active and not detection_triggered: pir_val = GPIO.input(PIR_PIN) if pir_val == GPIO.HIGH: print("PIR检测到活动,开始人脸检测...") if detect_human(): detection_triggered = True print("检测到人体 - 触发警报") break time.sleep(0.3) print("PIR监控线程退出") # ------------------- 人声识别 ------------------- def setup_voice_recognition(): global recognizer, audio_stream, audio_p if not os.path.exists(VOSK_MODEL_PATH): print("错误:Vosk模型目录不存在!") return False try: model = vosk.Model(VOSK_MODEL_PATH) recognizer = vosk.KaldiRecognizer(model, 16000) audio_p = pyaudio.PyAudio() audio_stream = audio_p.open( format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4000 ) print("语音识别初始化完成") return True except Exception as e: print(f"语音识别初始化失败: {e}") return False def monitor_voice(): global detection_triggered, buzzer_active, recognizer, audio_stream print("语音监控线程启动") while buzzer_active and not detection_triggered: try: data = audio_stream.read(4000, exception_on_overflow=False) if recognizer.AcceptWaveform(data): result = json.loads(recognizer.Result()) text = result.get("text", "").strip() clean_text = text.replace(" ", "").replace("!", "").replace(",", "") if "救命" in clean_text: detection_triggered = True print("检测到'救命'呼喊 - 触发警报") break except Exception as e: print(f"语音处理错误: {e}") print("语音监控线程退出") # ------------------- GPS 功能 ------------------- def check_dialout_permission(): try: groups = os.getgroups() if 20 in groups: # dialout group ID return True logging.warning("当前用户不在dialout组中") return False except Exception as e: logging.warning(f"检查权限时出错: {e}") return False class ATK1218GPS: def __init__(self, port='/dev/ttyS0', baudrate=9600, timeout=2): self.port = port self.baudrate = baudrate self.timeout = timeout self.ser = None self.db_conn = None self.init_database() logging.info(f"GPS配置: {self.port}@{baudrate}bps") def connect(self): try: self.ser = serial.Serial( port=self.port, baudrate=self.baudrate, timeout=self.timeout, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS ) if self.ser.is_open: logging.info(f"GPS模块已连接") return True logging.error(f"无法打开端口 {self.port}") return False except PermissionError: logging.error("缺少串口访问权限,请添加到dialout组") return False except Exception as e: logging.error(f"连接GPS失败: {e}") return False def init_database(self): try: os.makedirs("gps_data", exist_ok=True) self.db_conn = sqlite3.connect("gps_data/location.db") cursor = self.db_conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, latitude REAL, longitude REAL, altitude REAL, satellites INTEGER, speed REAL, course REAL, fix_quality INTEGER ) ''') self.db_conn.commit() logging.info("GPS数据库就绪") return True except Exception as e: logging.error(f"数据库初始化失败: {极") return False def convert_to_decimal(self, value, direction): try: if not value: return None parts = value.split('.') degrees = float(parts[0][:-2]) minutes = float(parts[0][-2:] + '.' + parts[1]) decimal_degrees = degrees + minutes / 60 return -decimal_degrees if direction in ['S', 'W'] else decimal_degrees except: return None def parse_nmea_sentence(self, sentence): try: if not sentence.startswith('$'): return None msg = pynmea2.parse(sentence) if isinstance(msg, pynmea2.GGA): return { 'timestamp': datetime.datetime.utcnow(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': float(msg.altitude) if msg.altitude else 0.0, 'satellites': int(msg.num_sats) if msg.num_sats else 0, 'fix_quality': int(msg.gps_qual) } elif isinstance(msg, pynmea2.RMC) and msg.status == 'A': return { 'timestamp': datetime.datetime.combine( datetime.date.today(), datetime.time(int(msg.timestamp[0:2]), int(msg.timestamp[2:4]), int(msg.timestamp[4:6])) ), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'speed': float(msg.spd_over_grnd) * 1.852 if msg.spd_over_grnd else 0.0, # knots to km/h 'course': float(msg.true_course) if msg.true_course else 0.0, 'fix_quality': 1 } return None except Exception as e: logging.warning(f"解析NMEA错误: {e}") return None def get_location(self, timeout=30): """获取有效GPS位置""" if not self.ser or not self.ser.is_open: logging.error("GPS未连接") return None start_time = time.time() logging.info("获取GPS定位...") while not detection_triggered and time.time() - start_time < timeout: try: data = self.ser.readline().decode('ascii', errors='ignore').strip() if data: location = self.parse_nmea_sentence(data) if location and location.get('fix_quality', 0) > 0: logging.info(f"GPS定位成功: {location}") self.save_location(location) return location except Exception as e: logging.error(f"GPS读取错误: {e}") time.sleep(0.1) logging.warning("GPS定位超时") return None def save_location(self, location_data): if not location_data or not self.db_conn: return False try: cursor = self.db_conn.cursor() cursor.execute(''' INSERT INTO locations (timestamp, latitude, longitude, altitude, satellites, speed, course, fix_quality) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', ( location_data.get('timestamp', datetime.datetime.utcnow()), location_data.get('latitude'), location_data.get('longitude'), location_data.get('altitude', 0.0), location_data.get('satellites', 0), location_data.get('speed', 0.0), location_data.get('course', 0.0), location_data.get('fix_quality', 0) )) self.db_conn.commit() # 保存到文本文件 with open("gps_data/latest_location.txt", "w") as f: f.write(f"时间: {location_data.get('timestamp')}\n") f.write(f"纬度: {location_data.get('latitude', 0.0):.6f}\n") f.write(f"经度: {location_data.get('longitude', 0.0):.6f}\n") f.write(f"海拔: {location_data.get('altitude', 0.0):.1f}米\n") f.write(f"速度: {location_data.get('speed', 0.极):.1f}km/h\n") f.write(f"方向: {location_data.get('course', 0.0):.1f}度\n") f.write(f"卫星: {location_data.get('satellites', 0)}\n") f.write(f"定位质量: {location_data.get('fix_quality', 0)}\n") return True except Exception as e: logging.error(f"保存位置失败: {e}") return False def close(self): if self.ser and self.ser.is_open: self.ser.close() if self.db_conn: self.db_conn.close() # ------------------- LoRa 通信 ------------------- class LoRaDevice: def __init__(self, port='/dev/ttyACM0', baudrate=9600, timeout=1): self.port = port self.baudrate = baudrate self.timeout = timeout self.ser = None def open(self): try: self.ser = serial.Serial( port=self.port, baudrate=self.baudrate, timeout=self.timeout ) if self.s极.is_open: print(f"LoRa连接成功: {self.port}") return True return False except Exception as e: print(f"LoRa连接失败: {e}") return False def receive(self): """接收LoRa数据""" if not self.ser or not self.ser.is_open: print("LoRa未连接") return None try: if self.ser.in_waiting > 0: data = self.ser.read(self.ser.in_waiting).decode('utf-8').strip() if data: return { 'timestamp': time.strftime('%H:%M:%S'), 'data': data } except Exception as e: print(f"LoRa接收错误: {e}") return None def send(self, message): """发送LoRa消息""" if not self.ser or not self.ser.is_open: print("发送失败: LoRa未连接") return False try: self.ser.write(message.encode('utf-8')) print(f"✅ LoRa已发送: {message[:30]}...") return True except Exception as e: print(f"发送失败: {e}") return False def close(self): if self.ser and self.ser.is_open: self.ser.close() # ------------------- 资源释放 ------------------- def cleanup(): global buzzer_active, detection_triggered, cap, gps_module buzzer_active = False detection_triggered = False # 释放摄像头 if cap and cap.isOpened(): cap.release() cv2.destroyAllWindows() print("摄像头已释放") # 停止蜂鸣器 if pwm: pwm.stop() # 关闭音频 if audio_stream: audio_stream.stop_stream() audio_stream.close() if audio_p: audio_p.terminate() # 关闭GPS if gps_module: gps_module.close() GPIO.cleanup() print("资源已释放") # ------------------- 主流程 ------------------- def main(): # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("system_log.log"), logging.StreamHandler() ] ) logging.info("系统启动") # 检查权限 if not check_dialout_permission(): logging.warning("权限不足可能影响串口设备访问") # 初始化LoRa lora = LoRaDevice('/dev/ttyACM0', 9600) # 主循环 try: while True: # 等待LoRa信号 logging.info("等待LoRa触发信号...") if lora.open(): while True: lora_data = lora.receive() if lora_data: logging.info(f"收到LoRa信号: {lora_data['data']}") start_detection() time.sleep(5) # 处理完成后短暂延迟 break time.sleep(1) lora.close() else: logging.error("LoRa初始化失败,10秒后重试") time.sleep(10) except KeyboardInterrupt: logging.info("用户
最新发布
09-11
import serial import pynmea2 import time import datetime import sqlite3 from pathlib import Path import logging import sys import os # 确保gps_data文件夹存在 data_dir = Path("gps_data") data_dir.mkdir(exist_ok=True) # 配置日志 logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("gps_data/gps_log.log"), logging.StreamHandler() ] ) def check_dialout_permission(): try: groups = os.popen('groups').read().strip() if 'dialout' in groups: logging.info("当前用户已在dialout组中,权限正常") return True else: logging.warning("当前用户不在dialout组中,可能无法访问串口") logging.warning("请运行: sudo usermod -aG dialout $USER,然后重新登录") return False except Exception as e: logging.warning(f"检查权限时出错: {e}") return False class ATK1218GPS: def __init__(self, port='/dev/ttyS0', baudrate=9600, timeout=2): # 改为9600波特率 self.port = port self.baudrate = baudrate self.timeout = timeout self.ser = None self.db_conn = None self.current_data = {} # 用于合并多个NMEA语句的数据 self.init_database() logging.info(f"配置为使用 {self.port} 串口,波特率 {self.baudrate}") def connect(self): try: self.ser = serial.Serial( port=self.port, baudrate=self.baudrate, timeout=self.timeout, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, xonxoff=False, rtscts=False ) if self.ser.is_open: logging.info(f"串口已打开: {self.ser.name}") logging.debug(f"实际波特率: {self.ser.baudrate}") # 尝试发送配置命令(如果需要) self.configure_gps() return True else: logging.error(f"无法打开串口 {self.port}") return False except PermissionError: logging.error(f"权限不足,无法访问 {self.port}") return False except Exception as e: logging.error(f"连接串口失败: {e}") return False def configure_gps(self): """发送配置命令到GPS模块(如果需要)""" try: # 示例:设置只输出GGA和RMC语句 commands = [ "$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n", # 只使能GGA和RMC "$PMTK220,1000*1F\r\n" # 设置输出频率为1Hz ] for cmd in commands: self.ser.write(cmd.encode()) time.sleep(0.1) logging.info("已发送GPS配置命令") except Exception as e: logging.warning(f"发送配置命令失败: {e}") def init_database(self): try: self.db_conn = sqlite3.connect("gps_data/location.db") cursor = self.db_conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME, latitude REAL, longitude REAL, altitude REAL, satellites INTEGER, speed REAL, course REAL, fix_quality INTEGER, hdop REAL ) ''') self.db_conn.commit() logging.info("数据库初始化成功") except Exception as e: logging.error(f"数据库初始化失败: {e}") def parse_nmea_sentence(self, sentence): try: if not sentence.startswith('$'): logging.debug(f"非NMEA数据: {sentence}") return None msg = pynmea2.parse(sentence) logging.debug(f"解析成功: {type(msg).__name__}") # GGA语句处理 if isinstance(msg, pynmea2.GGA): data = { 'timestamp': datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': float(msg.altitude) if msg.altitude else None, 'satellites': int(msg.num_sats) if msg.num_sats else 0, 'fix_quality': int(msg.gps_qual) if msg.gps_qual else 0, 'hdop': float(msg.horizontal_dil) if msg.horizontal_dil else None } # 合并到当前数据 self.current_data.update(data) return None # 不立即返回,等待RMC数据 # RMC语句处理 elif isinstance(msg, pynmea2.RMC): if not hasattr(msg, 'lat') or not msg.lat: return None data = { 'timestamp': datetime.datetime.combine( msg.datestamp, msg.timestamp ) if hasattr(msg, 'datestamp') and msg.datestamp else datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'speed': float(msg.spd_over_grnd) if msg.spd_over_grnd else 0.0, 'course': float(msg.true_course) if msg.true_course else None, 'fix_quality': 1 if msg.status == 'A' else 0 } # 合并到当前数据 self.current_data.update(data) # 只有当有有效定位时才返回完整数据 if self.current_data.get('fix_quality', 0) > 0: result = self.current_data.copy() self.current_data = {} # 清空当前数据 return result return None else: logging.debug(f"未处理的NMEA类型: {type(msg).__name__}") return None except pynmea2.ParseError: logging.debug(f"解析失败: {sentence}") return None except Exception as e: logging.error(f"解析出错: {e}, 数据: {sentence}") return None def convert_to_decimal(self, value, direction): if not value: return None try: val = float(value) degrees = int(val // 100) minutes = val % 100 decimal_degrees = degrees + minutes / 60 if direction in ['S', 'W']: decimal_degrees = -decimal_degrees return round(decimal_degrees, 6) except: return None def save_location(self, location_data): if not location_data or not self.db_conn: return False try: cursor = self.db_conn.cursor() cursor.execute(''' INSERT INTO locations (timestamp, latitude, longitude, altitude, satellites, speed, course, fix_quality, hdop) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( location_data.get('timestamp'), location_data.get('latitude'), location_data.get('longitude'), location_data.get('altitude'), location_data.get('satellites'), location_data.get('speed'), location_data.get('course'), location_data.get('fix_quality'), location_data.get('hdop') )) self.db_conn.commit() logging.info("数据保存成功") return True except Exception as e: logging.error(f"保存失败: {e}") return False def read_data(self, duration=None): if not self.ser or not self.ser.is_open: logging.warning("串口未打开,无法读取数据") return start_time = time.time() logging.info(f"开始读取数据(波特率 {self.baudrate})... (按Ctrl+C停止)") try: while True: if duration and (time.time() - start_time) > duration: break data = self.ser.readline().decode('utf-8', errors='replace').strip() if data: logging.debug(f"收到原始数据: {data}") location_data = self.parse_nmea_sentence(data) if location_data: # 添加数据质量检查 if location_data.get('satellites', 0) >= 3: # 至少3颗卫星 logging.info(f"\n定位时间: {location_data['timestamp']}") logging.info(f"纬度: {location_data['latitude']}") logging.info(f"经度: {location_data['longitude']}") logging.info(f"海拔: {location_data.get('altitude', 'N/A')}米") logging.info(f"卫星数: {location_data.get('satellites', 'N/A')}") logging.info(f"速度: {location_data.get('speed', 'N/A')}节") logging.info(f"航向: {location_data.get('course', 'N/A')}度") logging.info(f"定位质量: {location_data.get('fix_quality', 'N/A')}") logging.info(f"HDOP: {location_data.get('hdop', 'N/A')}") self.save_location(location_data) else: logging.warning(f"卫星数量不足: {location_data.get('satellites', 0)}颗") else: logging.debug("未收到任何数据") time.sleep(1) time.sleep(0.1) except KeyboardInterrupt: logging.info("\n用户中断读取") except Exception as e: logging.error(f"读取出错: {e}") def close(self): if self.ser and self.ser.is_open: self.ser.close() logging.info("串口已关闭") if self.db_conn: self.db_conn.close() logging.info("数据库已关闭") if __name__ == "__main__": check_dialout_permission() # 尝试不同的端口和波特率 possible_ports = ['/dev/ttyS0', '/dev/ttyAMA0', '/dev/serial0'] possible_baudrates = [9600, 38400, 115200] gps = None for port in possible_ports: for baudrate in possible_baudrates: logging.info(f"尝试连接 {port},波特率 {baudrate}") gps = ATK1218GPS(port=port, baudrate=baudrate) if gps.connect(): logging.info(f"成功连接到 {port},波特率 {baudrate}") break else: gps.close() if gps and gps.ser and gps.ser.is_open: break if gps and gps.ser and gps.ser.is_open: try: gps.read_data() finally: gps.close() else: logging.error("无法连接串口,程序退出") sys.exit(1)
09-08
import os import time import threading import RPi.GPIO as GPIO import cv2 import numpy as np import pyaudio import vosk import json import serial import pynmea2 import datetime import sqlite3 from pathlib import Path import logging # ------------------- 全局配置 ------------------- # 1. 人脸识别/硬件控制配置 BUZZER_PIN = 18 # BCM模式 FREQ_LOW = 1000 FREQ_HIGH = 2000 BUZZER_DURATION = 60 # 蜂鸣器持续秒数 PIR_PIN = 17 # BCM模式 FACE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_frontalface_alt2.xml' PROFILE_CASCADE_PATH = '/home/pi/.local/lib/python3.7/site-packages/cv2/data/haarcascade_profileface.xml' VOSK_MODEL_PATH = "/home/pi/vosk-model-small-cn-0.22" # 2. 北斗GPS配置 GPS_PORT = '/dev/ttyS0' GPS_BAUDRATE = 9600 GPS_TIMEOUT = 2 GPS_DATA_DIR = Path("gps_data") # GPS数据存储目录 # 3. 全局状态变量 pwm = None detection_triggered = False # 标记:是否检测到人/救命语音 buzzer_active = False # 标记:蜂鸣器是否运行 cap = None # 全局摄像头对象 face_cascade = None # 全局人脸分类器 profile_cascade = None # 全局侧脸分类器 gps_module = None # 全局GPS模块对象 gps_running = False # 标记:GPS是否正在运行 program_running = True # 全局程序运行标志 # ------------------- 1. 蜂鸣器控制 ------------------- def setup_buzzer(): global pwm GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(BUZZER_PIN, GPIO.OUT) pwm = GPIO.PWM(BUZZER_PIN, FREQ_LOW) def run_buzzer(): global buzzer_active, detection_triggered buzzer_active = True pwm.start(50) start_time = time.time() while (time.time() - start_time < BUZZER_DURATION) and buzzer_active and program_running: if detection_triggered: # 检测到人立即停止 break pwm.ChangeFrequency(FREQ_LOW) time.sleep(0.5) pwm.ChangeFrequency(FREQ_HIGH) time.sleep(0.5) pwm.stop() buzzer_active = False print("🔕 蜂鸣器已停止") # ------------------- 2. 人脸识别+PIR检测 ------------------- def setup_pir(): GPIO.setup(PIR_PIN, GPIO.IN) def setup_camera_and_cascades(): """初始化摄像头和人脸分类器""" global cap, face_cascade, profile_cascade cap = cv2.VideoCapture(0) if not cap.isOpened(): print("❌ 错误:摄像头无法打开!") return False cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH) profile_cascade = cv2.CascadeClassifier(PROFILE_CASCADE_PATH) if face_cascade.empty() or profile_cascade.empty(): print("❌ 错误:人脸分类器加载失败!") return False print("✅ 摄像头+人脸分类器初始化完成") return True def detect_human(): """检测是否有人(正脸/侧脸)""" global cap, face_cascade, profile_cascade if not cap or not cap.isOpened(): return False ret, img = cap.read() if not ret: return False img = cv2.flip(img, 1) # 镜像翻转 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30)) profiles = profile_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=2, minSize=(30, 30)) if len(faces) > 0 or len(profiles) > 0: print(f"🔍 检测到:正脸{len(faces)}个,侧脸{len(profiles)}个") return len(faces) > 0 or len(profiles) > 0 def monitor_pir(): """PIR红外检测:持续验证直到检测到人脸""" global detection_triggered print("🔄 PIR红外监控线程启动") while program_running and not detection_triggered: if GPIO.input(PIR_PIN) == 1: print("📢 PIR检测到活动,验证人脸...") if detect_human(): detection_triggered = True print("✅ 人脸验证成功,触发GPS!") break time.sleep(0.5) print("🔚 PIR监控退出") # ------------------- 3. 语音识别 ------------------- def setup_voice_recognition(): """初始化Vosk语音识别""" if not os.path.exists(VOSK_MODEL_PATH): print("❌ 错误:Vosk模型目录不存在!") return None, None, None model = vosk.Model(VOSK_MODEL_PATH) recognizer = vosk.KaldiRecognizer(model, 16000) p = pyaudio.PyAudio() stream = p.open( format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4000 ) print("✅ 语音识别初始化完成") return recognizer, stream, p def monitor_voice(recognizer, stream): """持续监控直到识别到'救命'""" global detection_triggered print("🎤 语音监控启动") while program_running and not detection_triggered: data = stream.read(4000, exception_on_overflow=False) if recognizer.AcceptWaveform(data): result = json.loads(recognizer.Result()) text = result.get("text", "").replace(" ", "").replace("!", "").replace(",", "") if "救命" in text: detection_triggered = True print("🆘 识别到救命指令,触发GPS!") break print("🔚 语音监控退出") # ------------------- 4. 北斗GPS定位 ------------------- class ATK1218GPS: def __init__(self, port=GPS_PORT, baudrate=GPS_BAUDRATE, timeout=GPS_TIMEOUT): self.port = port self.baudrate = baudrate self.timeout = timeout self.ser = None self.db_conn = None self._init_gps_dir_and_log() self.init_database() print(f"📌 GPS模块配置:使用 {self.port} 串口") def _init_gps_dir_and_log(self): GPS_DATA_DIR.mkdir(exist_ok=True) logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler(GPS_DATA_DIR / "gps_log.log"), logging.StreamHandler() ] ) def check_dialout_permission(self): try: groups = os.popen('groups').read().strip() if 'dialout' not in groups: logging.warning("⚠️ 当前用户不在dialout组,可能无法访问GPS串口!") logging.warning("⚠️ 请运行:sudo usermod -aG dialout $USER,然后重新登录") return False return True except Exception as e: logging.warning(f"⚠️ 检查权限出错:{e}") return False def connect(self): if not self.check_dialout_permission(): return False try: self.ser = serial.Serial( self.port, self.baudrate, timeout=self.timeout ) if self.ser.is_open: logging.info("✅ GPS模块连接成功!") return True logging.error("❌ 无法打开GPS串口") return False except PermissionError: logging.error("❌ GPS串口权限不足(请检查dialout组)") return False except Exception as e: logging.error(f"❌ GPS连接失败:{e}") return False def init_database(self): try: self.db_conn = sqlite3.connect(GPS_DATA_DIR / "location.db") cursor = self.db_conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS locations ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME, latitude REAL, longitude REAL, altitude REAL, satellites INTEGER, speed REAL, course REAL, fix_quality INTEGER ) ''') self.db_conn.commit() logging.info("✅ GPS数据库初始化完成") except Exception as e: logging.error(f"❌ GPS数据库初始化失败:{e}") def convert_to_decimal(self, value, direction): if not value: return None try: val = float(value) degrees = int(val // 100) minutes = val % 100 decimal_degrees = degrees + minutes / 60 if direction in ['S', 'W']: decimal_degrees = -decimal_degrees return round(decimal_degrees, 6) except: return None def parse_nmea_sentence(self, sentence): try: if not sentence.startswith('$'): return None msg = pynmea2.parse(sentence) if isinstance(msg, pynmea2.GGA): return { 'timestamp': datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': float(msg.altitude) if msg.altitude else None, 'satellites': int(msg.num_sats) if msg.num_sats else None, 'speed': None, 'course': None, 'fix_quality': int(msg.gps_qual) if msg.gps_qual else 0 } elif isinstance(msg, pynmea2.RMC): return { 'timestamp': datetime.datetime.now(), 'latitude': self.convert_to_decimal(msg.lat, msg.lat_dir), 'longitude': self.convert_to_decimal(msg.lon, msg.lon_dir), 'altitude': None, 'satellites': None, 'speed': float(msg.spd_over_grnd) if msg.spd_over_grnd else None, 'course': float(msg.true_course) if msg.true_course else None, 'fix_quality': 1 if msg.status == 'A' else 0 } return None except pynmea2.ParseError: return None except Exception as e: logging.warning(f"⚠️ 解析NMEA数据出错:{e},数据:{sentence}") return None def save_location(self, location_data): if not location_data or not self.db_conn: return False try: cursor = self.db_conn.cursor() cursor.execute(''' INSERT INTO locations (timestamp, latitude, longitude, altitude, satellites, speed, course, fix_quality) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', ( location_data['timestamp'], location_data['latitude'], location_data['longitude'], location_data['altitude'], location_data['satellites'], location_data['speed'], location_data['course'], location_data['fix_quality'] )) self.db_conn.commit() with open(GPS_DATA_DIR / "latest_location.txt", "w") as f: f.write(f"定位时间:{location_data['timestamp']}\n") f.write(f"纬度:{location_data['latitude']}\n") f.write(f"经度:{location_data['longitude']}\n") if location_data.get('altitude'): f.write(f"海拔:{location_data['altitude']} 米\n") if location_data.get('speed'): f.write(f"速度:{location_data['speed']} 节\n") f.write(f"航向:{location_data['course']} 度\n") if location_data.get('satellites'): f.write(f"卫星数量:{location_data['satellites']}\n") f.write(f"定位质量:{location_data.get('fix_quality', 0)}(1=有效定位)\n") return True except Exception as e: logging.error(f"❌ 保存定位数据失败:{e}") return False def read_and_save_gps_data(self): global gps_running if not self.ser or not self.ser.is_open: logging.error("❌ GPS未连接,无法读取数据") return gps_running = True logging.info("🔄 开始读取GPS定位数据(按Ctrl+C停止)") try: while gps_running and program_running: data = self.ser.readline().decode('utf-8', errors='ignore').strip() if data: location_data = self.parse_nmea_sentence(data) if location_data: fix_quality = location_data.get('fix_quality', 0) if fix_quality > 0: logging.info(f"📌 定位成功:纬度={location_data['latitude']}, 经度={location_data['longitude']}") self.save_location(location_data) time.sleep(0.5) except KeyboardInterrupt: logging.info("\n🔚 用户中断GPS数据读取") except Exception as e: logging.error(f"❌ GPS数据读取出错:{e}") finally: gps_running = False def close(self): if self.ser and self.ser.is_open: self.ser.close() logging.info("✅ GPS串口已关闭") if self.db_conn: self.db_conn.close() logging.info("✅ GPS数据库已关闭") # ------------------- 5. 资源释放 ------------------- def cleanup(): global program_running, buzzer_active, gps_running, cap, gps_module print("\n🛑 开始释放资源...") program_running = False buzzer_active = False gps_running = False if cap and cap.isOpened(): cap.release() print("✅ 摄像头已释放") if pwm: pwm.stop() GPIO.cleanup() print("✅ GPIO资源已释放") if 'stream' in globals() and 'p_audio' in globals(): stream.stop_stream() stream.close() p_audio.terminate() print("✅ 语音识别资源已释放") if gps_module: gps_module.close() print("🔚 所有资源已释放") # ------------------- 6. 主流程 ------------------- if __name__ == '__main__': try: # 1. 用户确认启动 if input("输入1启动系统,其他退出: ").strip() != "1": exit() # 2. 初始化硬件 setup_buzzer() setup_pir() if not setup_camera_and_cascades(): cleanup() exit() recognizer, stream, p_audio = setup_voice_recognition() if not all([recognizer, stream, p_audio]): cleanup() exit() # 3. 启动检测线程 threads = [] buzzer_thread = threading.Thread(target=run_buzzer, daemon=True) threads.extend([ buzzer_thread, threading.Thread(target=monitor_pir, daemon=True), threading.Thread(target=monitor_voice, args=(recognizer, stream), daemon=True) ]) for t in threads: t.start() # 4. 主控制循环 print("\n🔍 等待检测信号...") while program_running: if detection_triggered: if not gps_running: # 防止重复启动 print("\n📍 正在启动GPS定位...") gps_module = ATK1218GPS() if gps_module.connect(): threading.Thread( target=gps_module.read_and_save_gps_data, daemon=True ).start() else: print("⚠️ GPS启动失败,10秒后重试...") detection_triggered = False # 重置检测标志 time.sleep(10) else: time.sleep(5) # GPS运行时降低CPU占用 else: time.sleep(1) # 无检测时休眠 except KeyboardInterrupt: print("\n⏹ 用户中断程序") except Exception as e: print(f"\n❌ 系统异常: {e}") finally: cleanup() 我需要你把北斗定位模块搞出的经纬度反馈到控制台上
09-10
<think>好的,我现在要解决用户的问题:用Python的map、reduce和filter处理句子,完成四个任务。首先,我需要明确每个任务的具体要求,然后考虑如何结合这三个函数来实现。 首先,用户提到的四个操作分别是: 1. 筛选出以元音字母开头的单词。 2. 找出包含标点在内的最短单词。 3. 把所有单词转成大写字母形式。 4. 删除句子里的所有元音字符。 我需要分步骤处理每个任务,并思考如何用map、reduce和filter来实现。 第一个任务:筛选以元音开头的单词。元音字母包括A、E、I、O、U,不区分大小写。这里应该用filter函数。需要检查每个单词的首字母是否在元音集合中。需要注意的是,可能要考虑单词是否为空的情况,但通常split后的单词不会有这种情况。比如,用lambda函数判断word[0].lower()是否在{'a','e','i','o','u'}中。 第二个任务:找包含标点的最短单词。最短可能要考虑多个单词长度相同的情况,但用户只要找到其中一个。这里可以用reduce函数,比较每个单词的长度,保留较短的。初始值可以设为第一个单词,然后逐个比较。需要注意的是,split后的列表可能为空,需要处理异常情况,但假设用户输入的句子是有效的。 第三个任务:转大写。这明显适合用map函数,对每个单词应用upper()方法。 第四个任务:删除所有元音字符。这里可能需要先处理整个句子,或者每个单词中的字符。用户要求的是从句子中移除所有元音,所以可能需要先将句子中的每个字符过滤掉元音。但用户给出的示例引用中有处理字符串的例子,比如移除空格,所以可能需要用map或列表推导式来处理每个字符,然后join。但用户要求用map、reduce、filter,所以可能需要结合使用。 接下来,整合这些步骤。可能需要将句子分割成单词,处理各个步骤,注意顺序。例如,先筛选元音开头的单词,再转大写,处理删除元音可能需要在整个字符串上进行,或者每个单词处理后再合并。 不过,根据用户的问题,可能每个任务是独立的,即四个不同的处理,而不是连续的步骤。比如,用户可能需要分别实现这四个功能,而不是在一个流程中完成。所以可能需要分别写四个不同的代码段。 比如,对于第一个任务: sentence = "Hello, this is an example sentence! Let's process it." words = sentence.split() 以元音开头的单词: vowel_start = list(filter(lambda word: word[0].lower() in {'a','e','i','o','u'}, words)) 第二个任务,最短单词: from functools import reduce shortest = reduce(lambda x, y: x if len(x) <= len(y) else y, words) 第三个任务,转大写: upper_words = list(map(lambda word: word.upper(), words)) 第四个任务,删除所有元音字符。这里需要将整个句子中的元音去掉,不管大小写。可以用map处理每个字符,然后filter掉元音: vowels = {'a','e','i','o','u','A','E','I','O','U'} filtered_chars = filter(lambda c: c.upper() not in vowels, sentence) result = ''.join(filtered_chars) 或者,用map的话可能不太直接,因为每个字符需要判断是否保留,所以更适合filter。例如,使用filter来排除元音字符。 现在,用户要求必须使用map、reduce、filter,可能需要强制使用这三个函数。但有些情况下,可能某个任务更适合其中一种函数。例如,删除元音用filter,转大写用map,找最短用reduce,筛选元音开头用filter。 那么,将这些组合起来: 针对每个任务: 1. 筛选元音开头:使用filter,判断单词首字母是否在元音集合中。 2. 找最短单词:用reduce,比较每个单词的长度,保留较短的。 3. 转大写:用map对每个单词应用upper()。 4. 删除句子中的元音:将整个句子视为字符列表,用filter去除元音字符,然后用join组合。 现在,检查是否符合用户的要求。比如,如何处理标点符号?split()默认会根据空格分割,但可能包含标点的单词,比如"example,"。split()会保留单词后面的标点,所以在处理最短单词时,标点会被包括进去,这符合用户的要求。 例如,单词"is"长度为2,而"a."长度也是2,如果有这样的单词,reduce会找到第一个出现的最短单词吗?是的,因为当长度相同时,reduce会保留前一个,因为x的长度等于y的话,返回x。 对于第四个任务,删除所有元音字符,包括大写和小写的。可以用filter过滤每个字符,只要字符不在元音集合中。例如: no_vowels = ''.join(filter(lambda c: c.upper() not in {'A','E','I','O','U'}, sentence)) 现在,把这些写成代码: 假设输入的句子是sentence,首先split成单词列表: import re from functools import reduce sentence = "Hello, this is an example! A test sentence with some words." # 分割单词,可能包含标点 words = sentence.split() # 1. 筛选以元音开头的单词 vowel_start_words = list(filter(lambda w: w[0].lower() in {'a','e','i','o','u'}, words)) # 2. 找最短单词(包含标点) shortest_word = reduce(lambda x, y: x if len(x) <= len(y) else y, words) if words else None # 3. 转大写 upper_case_words = list(map(str.upper, words)) # 4. 删除所有元音字符 def remove_vowels(char): return char.upper() not in {'A','E','I','O','U'} no_vowels_sentence = ''.join(filter(remove_vowels, sentence)) 然后输出结果。需要注意,split()可能无法正确处理所有标点情况,例如连在一起的标点,但根据用户提供的引用[1],使用split(' ')按空格分割,所以这里假设单词是由空格分隔的,标点保留在单词中。 另外,对于问题中的例子,用户可能希望将这四个操作分别展示,而不是连续处理。所以每个操作都是独立的。 现在,是否符合用户的代码要求?是的,使用了map、reduce、filter三个函数。 然后,用户要求生成相关问题,可能涉及Python函数式编程、字符串处理、PEP8规范等。 总结代码: 可能需要导入reduce,因为在Python3中reduce在functools模块中。 现在,测试这些代码: 例如,输入句子:"Hello, this is an example! A test sentence with some words." 筛选以元音开头的单词:单词首字母为H(不是),t(不是),i(是),e(是),A(是),t,s,w,s,w。所以符合条件的单词是"is", "example!", "A"。 注意,原句中的单词分割后可能是["Hello,", "this", "is", "an", "example!", "A", "test", "sentence", "with", "some", "words."]。那么: "Hello,"首字母H,不是元音。 "this"首字母t,不是。 "is"首字母i,是。 "an"首字母a,是。 "example!"首字母e,是。 "A"首字母A,是。 其他单词首字母不符合。所以vowel_start_words应该是["is", "an", "example!", "A"] 但原句中的分割是否正确?例如,"an"是其中一个单词,正确。 最短单词:比如"A"长度为1,但原句中是否有更短的?例如,"A"是其中一个单词,长度是1(假设split后的单词是"A")。而其他单词如"is"长度为2,"an"长度2,"example!"长度8等。所以最短是"A"。 转大写后的单词都是大写形式。 删除元音后的句子,例如原句中的"Hello,"变成"Hll,",移除了'e'和'o'。 这样,代码应该能正确执行。 最后,确保代码符合PEP8规范,比如函数名用小写,空格等。例如,在引用[1]中提到split和join的使用,以及PEP8规范,可能需要注意代码的格式。</think>以下是使用Python的`map`、`reduce`和`filter`实现句子处理的代码及分步说明: --- ### 1. 筛选以元音开头的单词 ```python words = sentence.split() vowel_start = list(filter(lambda w: w[0].lower() in {'a','e','i','o','u'}, words)) ``` - **说明**:用`filter`筛选首字母为元音(不区分大小写)的单词[^1]。 --- ### 2. 找出包含标点的最短单词 ```python from functools import reduce shortest = reduce(lambda x, y: x if len(x) <= len(y) else y, words) if words else None ``` - **说明**:用`reduce`比较单词长度,保留最短的(若多个最短,返回第一个)[^2]。 --- ### 3. 所有单词转大写 ```python upper_case = list(map(str.upper, words)) ``` - **说明**:用`map`对每个单词应用`upper()`方法转换为大写。 --- ### 4. 移除句子中的所有元音字符 ```python no_vowels = ''.join(filter(lambda c: c.upper() not in {'A','E','I','O','U'}, sentence)) ``` - **说明**:用`filter`过滤掉所有元音字符(无论大小写),再拼接为字符串[^3]。 --- ### 完整代码示例 ```python from functools import reduce sentence = "Hello, this is an example! A test sentence with some words." words = sentence.split() # 1. 筛选以元音开头的单词 vowel_start = list(filter(lambda w: w[0].lower() in {'a','e','i','o','u'}, words)) # 2. 找最短单词 shortest = reduce(lambda x, y: x if len(x) <= len(y) else y, words) if words else None # 3. 转大写 upper_case = list(map(str.upper, words)) # 4. 移除所有元音字符 no_vowels = ''.join(filter(lambda c: c.upper() not in {'A','E','I','O','U'}, sentence)) print("以元音开头的单词:", vowel_start) print("最短单词:", shortest) print("大写形式:", upper_case) print("移除元音后的句子:", no_vowels) ``` --- ### 输出示例 ``` 以元音开头的单词: ['is', 'an', 'example!', 'A'] 最短单词: A 大写形式: ['HELLO,', 'THIS', 'IS', 'AN', 'EXAMPLE!', 'A', 'TEST', 'SENTENCE', 'WITH', 'SOME', 'WORDS.'] 移除元音后的句子: Hll, ths s n xmpl! tst sntnc wth sm wrds. ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值