优化云台跟踪效果

This commit is contained in:
myperworld committed 2025-12-26 23:28:23 +08:00
1 parent aa0c27d499
commit 1b12e76fdb
1860 files changed
+537 -480293

No files matched your search

+145
View File
@@ -0,0 +1,145 @@
import threading
import time
import re
import traceback
import paho.mqtt.client as mqtt
from flask import Blueprint, Response, session
from app.glo import *
# ==================== 全局配置 ====================
mqtt_client = None
MQTT_SUB_TOPIC = ""
latest_frame_cache = {}
cache_lock = threading.Lock()
mqtt_sub_lock = threading.Lock()
wrobot_cam = Blueprint('wrobot_cam', __name__)
# ==================== MQTT 核心逻辑 ====================
def on_mqtt_connect(client, userdata, flags, rc):
"""MQTT连接成功回调:此时暂不订阅(等第一次页面访问时再订阅)"""
if rc == 0:
print("MQTT连接成功(暂未订阅任何主题,等待页面访问)")
else:
print(f"MQTT连接失败 错误码: {rc}")
def on_mqtt_message(client, userdata, message):
"""MQTT消息回调:仅处理已订阅的主题"""
try:
if not MQTT_SUB_TOPIC or message.topic != MQTT_SUB_TOPIC:
return
device_id = message.topic.split('/')[0]
if len(message.payload) < 100:
return
with cache_lock:
latest_frame_cache[device_id] = message.payload
except Exception as e:
print(f"MQTT消息处理异常: {e}")
traceback.print_exc()
def start_mqtt_background():
"""启动MQTT客户端(仅连接,不订阅)"""
global mqtt_client
if mqtt_client is not None:
return
mqtt_client = mqtt.Client()
mqtt_client.on_connect = on_mqtt_connect
mqtt_client.on_message = on_mqtt_message
try:
mqtt_client.connect(MQTT_BROKER, MQTT_PORT, keepalive=60)
mqtt_client.loop_start()
print(f"MQTT客户端已启动 🚀(仅连接,未订阅主题)")
except Exception as e:
print(f"MQTT启动失败: {e}")
traceback.print_exc()
def subscribe_first_topic(new_topic):
"""第一次订阅主题(初始化订阅)"""
global MQTT_SUB_TOPIC
if not mqtt_client or not mqtt_client.is_connected():
raise RuntimeError("MQTT客户端未连接")
with mqtt_sub_lock:
MQTT_SUB_TOPIC = new_topic
mqtt_client.subscribe(MQTT_SUB_TOPIC)
print(f"MQTT首次订阅: {MQTT_SUB_TOPIC}")
def update_mqtt_subscription(new_topic):
"""更新订阅主题(非首次)"""
global MQTT_SUB_TOPIC
if not mqtt_client or not mqtt_client.is_connected():
raise RuntimeError("MQTT客户端未连接")
with mqtt_sub_lock:
# 取消旧主题订阅
mqtt_client.unsubscribe(MQTT_SUB_TOPIC)
print(f"MQTT取消订阅: {MQTT_SUB_TOPIC}")
# 订阅新主题
MQTT_SUB_TOPIC = new_topic
mqtt_client.subscribe(MQTT_SUB_TOPIC)
print(f"MQTT重新订阅: {MQTT_SUB_TOPIC}")
# ==================== Flask 路由核心逻辑 ====================
def generate_video_frame(device_id):
"""生成视频流"""
blank_jpeg = b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xd9'
while True:
try:
with cache_lock:
frame_data = latest_frame_cache.get(device_id, blank_jpeg)
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_data + b'\r\n')
time.sleep(0.01)
except GeneratorExit:
break
except Exception as e:
print(f"视频流生成异常: {e}")
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + blank_jpeg + b'\r\n')
time.sleep(0.1)
@wrobot_cam.route('/wrobot_cam/<string:device_id>')
@wrobot_cam.route('/wrobot_cam')
def main(device_id=None):
"""核心逻辑:第一次访问时初始化订阅,后续访问时更新订阅"""
# 1. 校验设备ID(无参数时直接报错,因为启动时未知默认设备)
if not device_id:
return Response("必须指定设备ID(访问方式:/wrobot_cam/设备ID)", status=400, mimetype='text/plain')
device_list = GetUserDeviceIdList(session['user']['user_id'])
if device_id not in device_list:
return Response(f"设备ID不合法", status=400, mimetype='text/plain')
# 2. 构建真实主题
new_mqtt_topic = f"{device_id}/head_video"
# 3. 区分「首次订阅」和「更新订阅」
try:
if not MQTT_SUB_TOPIC: # 初始值为空 → 第一次访问,初始化订阅
threading.Thread(target=subscribe_first_topic, args=(new_mqtt_topic,), daemon=True).start()
elif new_mqtt_topic != MQTT_SUB_TOPIC: # 非首次,更新订阅
threading.Thread(target=update_mqtt_subscription, args=(new_mqtt_topic,), daemon=True).start()
except RuntimeError as e:
return Response(f"MQTT客户端异常:{str(e)}", status=500, mimetype='text/plain')
# 4. 返回视频流
return Response(
generate_video_frame(device_id),
mimetype='multipart/x-mixed-replace; boundary=frame'
)
# ==================== 启动初始化 ====================
start_mqtt_background()