498 lines
18 KiB
Python
498 lines
18 KiB
Python
![]() |
#!/usr/bin/env python3
|
|||
|
import fcntl
|
|||
|
import json
|
|||
|
import math
|
|||
|
import os
|
|||
|
import socket
|
|||
|
import struct
|
|||
|
import threading
|
|||
|
import time
|
|||
|
import traceback
|
|||
|
import zmq
|
|||
|
from datetime import datetime
|
|||
|
|
|||
|
import cereal.messaging as messaging
|
|||
|
from openpilot.common.realtime import Ratekeeper
|
|||
|
from openpilot.common.params import Params
|
|||
|
from openpilot.system.hardware import PC, TICI
|
|||
|
try:
|
|||
|
from selfdrive.car.car_helpers import interfaces
|
|||
|
HAS_CAR_INTERFACES = True
|
|||
|
except ImportError:
|
|||
|
HAS_CAR_INTERFACES = False
|
|||
|
interfaces = None
|
|||
|
|
|||
|
class CommaAssist:
|
|||
|
def __init__(self):
|
|||
|
print("初始化 CommaAssist 服务...")
|
|||
|
# 初始化参数
|
|||
|
self.params = Params()
|
|||
|
|
|||
|
# 订阅需要的数据源
|
|||
|
self.sm = messaging.SubMaster(['deviceState', 'carState', 'controlsState',
|
|||
|
'longitudinalPlan', 'liveLocationKalman',
|
|||
|
'navInstruction', 'modelV2'])
|
|||
|
|
|||
|
# 网络相关配置
|
|||
|
self.broadcast_ip = self.get_broadcast_address()
|
|||
|
if self.broadcast_ip is None:
|
|||
|
self.broadcast_ip = "255.255.255.255" # 使用通用广播地址作为备选
|
|||
|
self.broadcast_port = 8088
|
|||
|
self.ip_address = "0.0.0.0"
|
|||
|
self.is_running = True
|
|||
|
|
|||
|
# 获取车辆信息
|
|||
|
self.car_info = {}
|
|||
|
self.load_car_info()
|
|||
|
|
|||
|
# 启动广播线程
|
|||
|
threading.Thread(target=self.broadcast_data).start()
|
|||
|
|
|||
|
def load_car_info(self):
|
|||
|
"""加载车辆基本信息"""
|
|||
|
try:
|
|||
|
# 获取车辆型号信息
|
|||
|
try:
|
|||
|
car_model = self.params.get("CarModel", encoding='utf8')
|
|||
|
self.car_info["car_name"] = car_model if car_model else "Unknown"
|
|||
|
except Exception as e:
|
|||
|
print(f"无法获取CarModel参数: {e}")
|
|||
|
try:
|
|||
|
# 尝试获取其他可能的车辆参数
|
|||
|
car_params = self.params.get("CarParamsCache", encoding='utf8')
|
|||
|
self.car_info["car_name"] = "通过CarParamsCache获取" if car_params else "Unknown"
|
|||
|
except Exception:
|
|||
|
self.car_info["car_name"] = "Unknown Model"
|
|||
|
car_model = None
|
|||
|
|
|||
|
# 检查车辆接口是否可用
|
|||
|
if not HAS_CAR_INTERFACES:
|
|||
|
print("车辆接口模块不可用")
|
|||
|
elif not car_model:
|
|||
|
print("无有效的车型信息")
|
|||
|
elif not isinstance(interfaces, list):
|
|||
|
print("车辆接口不是列表类型,尝试转换...")
|
|||
|
# 尝试获取车辆接口的具体实现
|
|||
|
if hasattr(interfaces, '__call__'):
|
|||
|
# 如果interfaces是一个函数,尝试直接获取车辆指纹
|
|||
|
try:
|
|||
|
self.car_info["car_fingerprint"] = f"直接从车型{car_model}获取"
|
|||
|
print(f"直接从车型识别: {car_model}")
|
|||
|
except Exception as e:
|
|||
|
print(f"无法从车型直接获取指纹: {e}")
|
|||
|
else:
|
|||
|
# 正常遍历接口列表
|
|||
|
print("尝试从车辆接口中获取指纹信息...")
|
|||
|
for interface in interfaces:
|
|||
|
if not hasattr(interface, 'CHECKSUM'):
|
|||
|
continue
|
|||
|
|
|||
|
try:
|
|||
|
if isinstance(interface.CHECKSUM, dict) and 'pt' in interface.CHECKSUM:
|
|||
|
if car_model in interface.CHECKSUM["pt"]:
|
|||
|
platform = interface
|
|||
|
self.car_info["car_fingerprint"] = platform.config.platform_str
|
|||
|
|
|||
|
# 获取车辆规格参数
|
|||
|
specs = platform.config.specs
|
|||
|
if specs:
|
|||
|
if hasattr(specs, 'mass'):
|
|||
|
self.car_info["mass"] = specs.mass
|
|||
|
if hasattr(specs, 'wheelbase'):
|
|||
|
self.car_info["wheelbase"] = specs.wheelbase
|
|||
|
if hasattr(specs, 'steerRatio'):
|
|||
|
self.car_info["steerRatio"] = specs.steerRatio
|
|||
|
break
|
|||
|
except Exception as e:
|
|||
|
print(f"处理特定车辆接口异常: {e}")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
print(f"加载车辆信息失败: {e}")
|
|||
|
traceback.print_exc()
|
|||
|
|
|||
|
# 确保基本字段存在,避免后续访问出错
|
|||
|
if "car_name" not in self.car_info:
|
|||
|
self.car_info["car_name"] = "Unknown Model"
|
|||
|
if "car_fingerprint" not in self.car_info:
|
|||
|
self.car_info["car_fingerprint"] = "Unknown Fingerprint"
|
|||
|
|
|||
|
print(f"车辆信息加载完成: {self.car_info}")
|
|||
|
|
|||
|
def get_broadcast_address(self):
|
|||
|
"""获取广播地址"""
|
|||
|
try:
|
|||
|
if PC:
|
|||
|
iface = b'br0'
|
|||
|
else:
|
|||
|
iface = b'wlan0'
|
|||
|
|
|||
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
|||
|
ip = fcntl.ioctl(
|
|||
|
s.fileno(),
|
|||
|
0x8919, # SIOCGIFADDR
|
|||
|
struct.pack('256s', iface)
|
|||
|
)[20:24]
|
|||
|
ip_str = socket.inet_ntoa(ip)
|
|||
|
print(f"获取到IP地址: {ip_str}")
|
|||
|
# 从IP地址构造广播地址
|
|||
|
ip_parts = ip_str.split('.')
|
|||
|
return f"{ip_parts[0]}.{ip_parts[1]}.{ip_parts[2]}.255"
|
|||
|
except (OSError, Exception) as e:
|
|||
|
print(f"获取广播地址失败: {e}")
|
|||
|
return None
|
|||
|
|
|||
|
def get_local_ip(self):
|
|||
|
"""获取本地IP地址"""
|
|||
|
try:
|
|||
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
|||
|
s.connect(("8.8.8.8", 80))
|
|||
|
return s.getsockname()[0]
|
|||
|
except Exception as e:
|
|||
|
print(f"获取本地IP失败: {e}")
|
|||
|
return "127.0.0.1"
|
|||
|
|
|||
|
def make_data_message(self):
|
|||
|
"""构建广播消息内容"""
|
|||
|
# 基本消息结构
|
|||
|
message = {
|
|||
|
"timestamp": int(time.time()),
|
|||
|
"device": {
|
|||
|
"ip": self.ip_address,
|
|||
|
"battery": {},
|
|||
|
"mem_usage": 0,
|
|||
|
"cpu_temp": 0,
|
|||
|
"free_space": 0
|
|||
|
},
|
|||
|
"car": {
|
|||
|
"speed": 0,
|
|||
|
"cruise_speed": 0,
|
|||
|
"gear_shifter": "unknown",
|
|||
|
"steering_angle": 0,
|
|||
|
"steering_torque": 0,
|
|||
|
"brake_pressed": False,
|
|||
|
"gas_pressed": False,
|
|||
|
"door_open": False,
|
|||
|
"left_blinker": False,
|
|||
|
"right_blinker": False
|
|||
|
},
|
|||
|
"location": {
|
|||
|
"latitude": 0,
|
|||
|
"longitude": 0,
|
|||
|
"bearing": 0,
|
|||
|
"speed": 0,
|
|||
|
"altitude": 0,
|
|||
|
"accuracy": 0,
|
|||
|
"gps_valid": False
|
|||
|
},
|
|||
|
"car_info": {
|
|||
|
"basic": {
|
|||
|
"car_model": self.car_info.get("car_name", "Unknown"),
|
|||
|
"fingerprint": self.car_info.get("car_fingerprint", "Unknown"),
|
|||
|
"weight": f"{self.car_info.get('mass', 0):.0f} kg" if 'mass' in self.car_info else "Unknown",
|
|||
|
"wheelbase": f"{self.car_info.get('wheelbase', 0):.3f} m" if 'wheelbase' in self.car_info else "Unknown",
|
|||
|
"steering_ratio": f"{self.car_info.get('steerRatio', 0):.1f}" if 'steerRatio' in self.car_info else "Unknown"
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# 安全地获取设备信息
|
|||
|
try:
|
|||
|
if self.sm.updated['deviceState'] and self.sm.valid['deviceState']:
|
|||
|
device_state = self.sm['deviceState']
|
|||
|
|
|||
|
# 获取设备信息 - 使用getattr安全地访问属性
|
|||
|
message["device"]["mem_usage"] = getattr(device_state, 'memoryUsagePercent', 0)
|
|||
|
message["device"]["free_space"] = getattr(device_state, 'freeSpacePercent', 0)
|
|||
|
|
|||
|
# CPU温度
|
|||
|
cpu_temps = getattr(device_state, 'cpuTempC', [])
|
|||
|
if isinstance(cpu_temps, list) and len(cpu_temps) > 0:
|
|||
|
message["device"]["cpu_temp"] = cpu_temps[0]
|
|||
|
|
|||
|
# 电池信息
|
|||
|
try: # 额外的错误处理,因为这是常见错误点
|
|||
|
message["device"]["battery"]["percent"] = getattr(device_state, 'batteryPercent', 0)
|
|||
|
message["device"]["battery"]["status"] = getattr(device_state, 'batteryCurrent', 0)
|
|||
|
message["device"]["battery"]["voltage"] = getattr(device_state, 'batteryVoltage', 0)
|
|||
|
message["device"]["battery"]["charging"] = getattr(device_state, 'chargingError', False)
|
|||
|
except Exception as e:
|
|||
|
print(f"获取电池信息失败: {e}")
|
|||
|
except Exception as e:
|
|||
|
print(f"获取设备状态出错: {e}")
|
|||
|
|
|||
|
# 安全地获取车辆信息
|
|||
|
try:
|
|||
|
if self.sm.updated['carState'] and self.sm.valid['carState']:
|
|||
|
CS = self.sm['carState']
|
|||
|
|
|||
|
# 基本车辆信息
|
|||
|
message["car"]["speed"] = getattr(CS, 'vEgo', 0) * 3.6 # m/s转km/h
|
|||
|
message["car"]["gear_shifter"] = str(getattr(CS, 'gearShifter', "unknown"))
|
|||
|
message["car"]["steering_angle"] = getattr(CS, 'steeringAngleDeg', 0)
|
|||
|
message["car"]["steering_torque"] = getattr(CS, 'steeringTorque', 0)
|
|||
|
message["car"]["brake_pressed"] = getattr(CS, 'brakePressed', False)
|
|||
|
message["car"]["gas_pressed"] = getattr(CS, 'gasPressed', False)
|
|||
|
message["car"]["door_open"] = getattr(CS, 'doorOpen', False)
|
|||
|
message["car"]["left_blinker"] = getattr(CS, 'leftBlinker', False)
|
|||
|
message["car"]["right_blinker"] = getattr(CS, 'rightBlinker', False)
|
|||
|
|
|||
|
# 扩展的车辆状态信息
|
|||
|
is_car_started = getattr(CS, 'vEgo', 0) > 0.1
|
|||
|
is_car_engaged = False
|
|||
|
|
|||
|
# 详细车辆信息
|
|||
|
car_details = {}
|
|||
|
|
|||
|
# 车辆状态
|
|||
|
status = {
|
|||
|
"running_status": "Moving" if is_car_started else "Stopped",
|
|||
|
"door_open": getattr(CS, 'doorOpen', False),
|
|||
|
"seatbelt_unlatched": getattr(CS, 'seatbeltUnlatched', False),
|
|||
|
}
|
|||
|
|
|||
|
# 引擎信息
|
|||
|
engine_info = {}
|
|||
|
if hasattr(CS, 'engineRpm') and CS.engineRpm > 0:
|
|||
|
engine_info["rpm"] = f"{CS.engineRpm:.0f}"
|
|||
|
car_details["engine"] = engine_info
|
|||
|
|
|||
|
# 巡航控制
|
|||
|
cruise_info = {}
|
|||
|
if hasattr(CS, 'cruiseState'):
|
|||
|
is_car_engaged = getattr(CS.cruiseState, 'enabled', False)
|
|||
|
cruise_info["enabled"] = getattr(CS.cruiseState, 'enabled', False)
|
|||
|
cruise_info["available"] = getattr(CS.cruiseState, 'available', False)
|
|||
|
cruise_info["speed"] = getattr(CS.cruiseState, 'speed', 0) * 3.6
|
|||
|
|
|||
|
if hasattr(CS, 'pcmCruiseGap'):
|
|||
|
cruise_info["gap"] = CS.pcmCruiseGap
|
|||
|
|
|||
|
status["cruise_engaged"] = is_car_engaged
|
|||
|
car_details["cruise"] = cruise_info
|
|||
|
|
|||
|
# 车轮速度
|
|||
|
wheel_speeds = {}
|
|||
|
if hasattr(CS, 'wheelSpeeds'):
|
|||
|
ws = CS.wheelSpeeds
|
|||
|
wheel_speeds["fl"] = getattr(ws, 'fl', 0) * 3.6
|
|||
|
wheel_speeds["fr"] = getattr(ws, 'fr', 0) * 3.6
|
|||
|
wheel_speeds["rl"] = getattr(ws, 'rl', 0) * 3.6
|
|||
|
wheel_speeds["rr"] = getattr(ws, 'rr', 0) * 3.6
|
|||
|
car_details["wheel_speeds"] = wheel_speeds
|
|||
|
|
|||
|
# 方向盘信息
|
|||
|
steering = {
|
|||
|
"angle": getattr(CS, 'steeringAngleDeg', 0),
|
|||
|
"torque": getattr(CS, 'steeringTorque', 0),
|
|||
|
}
|
|||
|
if hasattr(CS, 'steeringRateDeg'):
|
|||
|
steering["rate"] = CS.steeringRateDeg
|
|||
|
car_details["steering"] = steering
|
|||
|
|
|||
|
# 踏板状态
|
|||
|
pedals = {
|
|||
|
"gas_pressed": getattr(CS, 'gasPressed', False),
|
|||
|
"brake_pressed": getattr(CS, 'brakePressed', False),
|
|||
|
}
|
|||
|
if hasattr(CS, 'gas'):
|
|||
|
pedals["throttle_position"] = CS.gas * 100
|
|||
|
if hasattr(CS, 'brake'):
|
|||
|
pedals["brake_pressure"] = CS.brake * 100
|
|||
|
car_details["pedals"] = pedals
|
|||
|
|
|||
|
# 安全系统
|
|||
|
safety_systems = {}
|
|||
|
if hasattr(CS, 'espDisabled'):
|
|||
|
safety_systems["esp_disabled"] = CS.espDisabled
|
|||
|
if hasattr(CS, 'absActive'):
|
|||
|
safety_systems["abs_active"] = CS.absActive
|
|||
|
if hasattr(CS, 'tcsActive'):
|
|||
|
safety_systems["tcs_active"] = CS.tcsActive
|
|||
|
if hasattr(CS, 'collisionWarning'):
|
|||
|
safety_systems["collision_warning"] = CS.collisionWarning
|
|||
|
car_details["safety_systems"] = safety_systems
|
|||
|
|
|||
|
# 车门状态
|
|||
|
doors = {
|
|||
|
"driver": getattr(CS, 'doorOpen', False)
|
|||
|
}
|
|||
|
if hasattr(CS, 'passengerDoorOpen'):
|
|||
|
doors["passenger"] = CS.passengerDoorOpen
|
|||
|
if hasattr(CS, 'trunkOpen'):
|
|||
|
doors["trunk"] = CS.trunkOpen
|
|||
|
if hasattr(CS, 'hoodOpen'):
|
|||
|
doors["hood"] = CS.hoodOpen
|
|||
|
car_details["doors"] = doors
|
|||
|
|
|||
|
# 灯光状态
|
|||
|
lights = {
|
|||
|
"left_blinker": getattr(CS, 'leftBlinker', False),
|
|||
|
"right_blinker": getattr(CS, 'rightBlinker', False),
|
|||
|
}
|
|||
|
if hasattr(CS, 'genericToggle'):
|
|||
|
lights["high_beam"] = CS.genericToggle
|
|||
|
if hasattr(CS, 'lowBeamOn'):
|
|||
|
lights["low_beam"] = CS.lowBeamOn
|
|||
|
car_details["lights"] = lights
|
|||
|
|
|||
|
# 盲点监测
|
|||
|
blind_spot = {}
|
|||
|
if hasattr(CS, 'leftBlindspot'):
|
|||
|
blind_spot["left"] = CS.leftBlindspot
|
|||
|
if hasattr(CS, 'rightBlindspot'):
|
|||
|
blind_spot["right"] = CS.rightBlindspot
|
|||
|
if blind_spot:
|
|||
|
car_details["blind_spot"] = blind_spot
|
|||
|
|
|||
|
# 其他可选信息
|
|||
|
other_info = {}
|
|||
|
if hasattr(CS, 'outsideTemp'):
|
|||
|
other_info["outside_temp"] = CS.outsideTemp
|
|||
|
if hasattr(CS, 'fuelGauge'):
|
|||
|
other_info["fuel_range"] = CS.fuelGauge
|
|||
|
if hasattr(CS, 'odometer'):
|
|||
|
other_info["odometer"] = CS.odometer
|
|||
|
if hasattr(CS, 'instantFuelConsumption'):
|
|||
|
other_info["fuel_consumption"] = CS.instantFuelConsumption
|
|||
|
if other_info:
|
|||
|
car_details["other"] = other_info
|
|||
|
|
|||
|
# 更新状态和详细信息
|
|||
|
message["car_info"]["status"] = status
|
|||
|
message["car_info"]["details"] = car_details
|
|||
|
|
|||
|
if self.sm.updated['controlsState'] and self.sm.valid['controlsState']:
|
|||
|
controls_state = self.sm['controlsState']
|
|||
|
message["car"]["cruise_speed"] = getattr(controls_state, 'vCruise', 0)
|
|||
|
|
|||
|
# 额外的控制状态信息
|
|||
|
controls_info = {}
|
|||
|
if hasattr(controls_state, 'enabled'):
|
|||
|
controls_info["enabled"] = controls_state.enabled
|
|||
|
if hasattr(controls_state, 'active'):
|
|||
|
controls_info["active"] = controls_state.active
|
|||
|
if hasattr(controls_state, 'alertText1'):
|
|||
|
controls_info["alert_text"] = controls_state.alertText1
|
|||
|
if controls_info:
|
|||
|
message["car_info"]["controls"] = controls_info
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
print(f"获取车辆信息出错: {e}")
|
|||
|
traceback.print_exc()
|
|||
|
|
|||
|
# 安全地获取GPS位置信息
|
|||
|
try:
|
|||
|
if self.sm.updated['liveLocationKalman'] and self.sm.valid['liveLocationKalman']:
|
|||
|
location = self.sm['liveLocationKalman']
|
|||
|
|
|||
|
# 检查GPS是否有效
|
|||
|
location_status = getattr(location, 'status', -1)
|
|||
|
position_valid = False
|
|||
|
if hasattr(location, 'positionGeodetic'):
|
|||
|
position_valid = getattr(location.positionGeodetic, 'valid', False)
|
|||
|
|
|||
|
gps_valid = (location_status == 0) and position_valid
|
|||
|
message["location"]["gps_valid"] = gps_valid
|
|||
|
|
|||
|
if gps_valid and hasattr(location, 'positionGeodetic') and hasattr(location.positionGeodetic, 'value'):
|
|||
|
# 获取位置信息
|
|||
|
pos_value = location.positionGeodetic.value
|
|||
|
if len(pos_value) >= 3:
|
|||
|
message["location"]["latitude"] = pos_value[0]
|
|||
|
message["location"]["longitude"] = pos_value[1]
|
|||
|
message["location"]["altitude"] = pos_value[2]
|
|||
|
|
|||
|
# 获取精度信息
|
|||
|
if hasattr(location, 'positionGeodeticStd') and hasattr(location.positionGeodeticStd, 'value'):
|
|||
|
std_value = location.positionGeodeticStd.value
|
|||
|
if len(std_value) > 0:
|
|||
|
message["location"]["accuracy"] = std_value[0]
|
|||
|
|
|||
|
# 获取方向信息
|
|||
|
if hasattr(location, 'calibratedOrientationNED') and hasattr(location.calibratedOrientationNED, 'value'):
|
|||
|
orientation = location.calibratedOrientationNED.value
|
|||
|
if len(orientation) > 2:
|
|||
|
message["location"]["bearing"] = math.degrees(orientation[2])
|
|||
|
|
|||
|
# 设置速度信息
|
|||
|
car_state = self.sm['carState'] if self.sm.valid['carState'] else None
|
|||
|
if car_state and hasattr(car_state, 'vEgo'):
|
|||
|
message["location"]["speed"] = car_state.vEgo * 3.6
|
|||
|
except Exception as e:
|
|||
|
print(f"获取位置信息出错: {e}")
|
|||
|
|
|||
|
# 如果有导航指令,添加导航信息
|
|||
|
try:
|
|||
|
if self.sm.valid['navInstruction']:
|
|||
|
nav_instruction = self.sm['navInstruction']
|
|||
|
|
|||
|
nav_info = {}
|
|||
|
nav_info["distance_remaining"] = getattr(nav_instruction, 'distanceRemaining', 0)
|
|||
|
nav_info["time_remaining"] = getattr(nav_instruction, 'timeRemaining', 0)
|
|||
|
nav_info["speed_limit"] = getattr(nav_instruction, 'speedLimit', 0) * 3.6
|
|||
|
nav_info["maneuver_distance"] = getattr(nav_instruction, 'maneuverDistance', 0)
|
|||
|
nav_info["maneuver_type"] = getattr(nav_instruction, 'maneuverType', "")
|
|||
|
nav_info["maneuver_modifier"] = getattr(nav_instruction, 'maneuverModifier', "")
|
|||
|
nav_info["maneuver_text"] = getattr(nav_instruction, 'maneuverPrimaryText', "")
|
|||
|
|
|||
|
message["navigation"] = nav_info
|
|||
|
except Exception as e:
|
|||
|
print(f"获取导航信息出错: {e}")
|
|||
|
|
|||
|
try:
|
|||
|
return json.dumps(message)
|
|||
|
except Exception as e:
|
|||
|
print(f"序列化消息出错: {e}")
|
|||
|
return "{}"
|
|||
|
|
|||
|
def broadcast_data(self):
|
|||
|
"""定期发送数据到广播地址"""
|
|||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|||
|
rk = Ratekeeper(10, print_delay_threshold=None) # 10Hz广播频率
|
|||
|
|
|||
|
print(f"开始广播数据到 {self.broadcast_ip}:{self.broadcast_port}")
|
|||
|
|
|||
|
while self.is_running:
|
|||
|
try:
|
|||
|
# 更新数据
|
|||
|
self.sm.update(0)
|
|||
|
|
|||
|
# 更新IP地址
|
|||
|
ip_address = self.get_local_ip()
|
|||
|
if ip_address != self.ip_address:
|
|||
|
self.ip_address = ip_address
|
|||
|
print(f"IP地址已更新: {ip_address}")
|
|||
|
|
|||
|
# 构建并发送消息
|
|||
|
msg = self.make_data_message()
|
|||
|
dat = msg.encode('utf-8')
|
|||
|
sock.sendto(dat, (self.broadcast_ip, self.broadcast_port))
|
|||
|
|
|||
|
# 减少日志输出频率
|
|||
|
if rk.frame % 50 == 0: # 每5秒打印一次日志
|
|||
|
print(f"广播数据: {self.broadcast_ip}:{self.broadcast_port}")
|
|||
|
|
|||
|
rk.keep_time()
|
|||
|
except Exception as e:
|
|||
|
print(f"广播数据错误: {e}")
|
|||
|
traceback.print_exc()
|
|||
|
time.sleep(1)
|
|||
|
|
|||
|
def main(gctx=None):
|
|||
|
"""主函数
|
|||
|
支持作为独立程序运行或由process_config启动
|
|||
|
gctx参数用于与openpilot进程管理系统兼容
|
|||
|
"""
|
|||
|
comma_assist = CommaAssist()
|
|||
|
|
|||
|
# 保持主线程运行
|
|||
|
try:
|
|||
|
while True:
|
|||
|
time.sleep(10) # 主线程休眠
|
|||
|
except KeyboardInterrupt:
|
|||
|
comma_assist.is_running = False
|
|||
|
print("CommaAssist服务已停止")
|
|||
|
|
|||
|
if __name__ == "__main__":
|
|||
|
main()
|