#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 手动提取PWM-速度关系(使用航向角和位移计算前向速度) """ import sys import numpy as np import math def main(): if len(sys.argv) < 2: print("用法: python extract_pwm_manual.py calibration.log") return log_file = sys.argv[1] # 读取所有数据 data_points = [] with open(log_file, 'r', encoding='utf-8', errors='ignore') as f: for line in f: if not line.startswith('$CAL'): continue try: parts = line.strip().split(',') if len(parts) < 18: continue data_points.append({ 'seq': int(parts[1]), 'time_ms': int(parts[2]), 'state': parts[3], 'throttle': int(parts[4]), 'steering': int(parts[5]), 'enu_x': float(parts[6]), 'enu_y': float(parts[7]), 'enu_z': float(parts[8]), 'hdg': float(parts[9]), 'pitch': float(parts[10]), 'roll': float(parts[11]) }) except: continue print(f"解析了 {len(data_points)} 条数据") # 分析每个巡航状态的平均速度 cruise_states = ['FWD_VLOW_C', 'FWD_LOW_C', 'FWD_MID_C', 'FWD_HIGH_C', 'FWD_VHIGH_C', 'FWD_MAX_C'] print("\n========== 前进速度分析(巡航阶段)==========") pwm_speed_pairs = [] for state_name in cruise_states: state_data = [d for d in data_points if d['state'] == state_name] if len(state_data) < 20: continue # 取中间80%的数据(去除加速和减速影响) start_idx = len(state_data) // 10 end_idx = len(state_data) - len(state_data) // 10 stable_data = state_data[start_idx:end_idx] if len(stable_data) < 10: continue # 计算总位移和总时间 total_dist = 0 for i in range(1, len(stable_data)): dx = stable_data[i]['enu_x'] - stable_data[i-1]['enu_x'] dy = stable_data[i]['enu_y'] - stable_data[i-1]['enu_y'] total_dist += math.sqrt(dx*dx + dy*dy) total_time = (stable_data[-1]['time_ms'] - stable_data[0]['time_ms']) / 1000.0 if total_time > 0: avg_speed = total_dist / total_time pwm = stable_data[0]['throttle'] pwm_speed_pairs.append((pwm, avg_speed)) print(f"PWM {pwm}: 速度 {avg_speed:.3f} m/s (距离={total_dist:.2f}m, 时长={total_time:.1f}s)") # 线性拟合 if len(pwm_speed_pairs) >= 3: pwms = np.array([p[0] for p in pwm_speed_pairs]) speeds = np.array([p[1] for p in pwm_speed_pairs]) # v = k × (1500 - pwm) + bias x = 1500 - pwms y = speeds coef = np.polyfit(x, y, 1) k = coef[0] bias = coef[1] print(f"\n========== 线性拟合结果 ==========") print(f"模型:v = {k:.6f} × (1500 - pwm) + ({bias:.6f})") print(f"\n验证拟合质量:") for pwm, v_measured in pwm_speed_pairs: v_predicted = k * (1500 - pwm) + bias error = abs(v_measured - v_predicted) print(f" PWM {pwm}: 实测 {v_measured:.3f} m/s, 预测 {v_predicted:.3f} m/s, 误差 {error:.3f} m/s") # 预测极限 max_speed = k * (1500 - 1000) + bias print(f"\n========== 推荐参数 ==========") print(f"#define MC_CFG_FORWARD_K ({k:.6f}f)") print(f"#define MC_CFG_FORWARD_BIAS ({bias:.6f}f)") print(f"#define MC_CFG_MAX_FORWARD_MPS ({max_speed:.3f}f) // 预测1000PWM最大速度") print(f"#define MC_CFG_FORWARD_DEADZONE_PWM (30) // 可选死区") # 分析转向 print("\n\n========== 转向速度分析(原地转向)==========") turn_states_left = ['TURN_L_VLOW', 'TURN_L_LOW', 'TURN_L_MID', 'TURN_L_HIGH', 'TURN_L_MAX'] turn_states_right = ['TURN_R_VLOW', 'TURN_R_LOW', 'TURN_R_MID', 'TURN_R_HIGH', 'TURN_R_MAX'] turn_pwm_yaw = [] for state_name in turn_states_left + turn_states_right: state_data = [d for d in data_points if d['state'] == state_name] if len(state_data) < 20: continue # 取中间数据 start_idx = len(state_data) // 4 end_idx = len(state_data) - len(state_data) // 4 stable_data = state_data[start_idx:end_idx] if len(stable_data) < 5: continue # 计算航向变化率 hdg_changes = [] for i in range(1, len(stable_data)): dhdg = stable_data[i]['hdg'] - stable_data[i-1]['hdg'] # 处理360°跳变 if dhdg > 180: dhdg -= 360 elif dhdg < -180: dhdg += 360 dt = (stable_data[i]['time_ms'] - stable_data[i-1]['time_ms']) / 1000.0 if dt > 0: yaw_rate_deg = dhdg / dt hdg_changes.append(yaw_rate_deg) if hdg_changes: avg_yaw_deg = np.mean(hdg_changes) avg_yaw_rad = avg_yaw_deg * math.pi / 180.0 pwm = stable_data[0]['steering'] turn_pwm_yaw.append((pwm, avg_yaw_rad)) print(f"PWM {pwm}: 角速度 {avg_yaw_rad:.4f} rad/s ({avg_yaw_deg:.2f} °/s, {len(hdg_changes)}个样本)") # 拟合转向模型 if len(turn_pwm_yaw) >= 3: pwms = np.array([p[0] for p in turn_pwm_yaw]) yaw_rates = np.array([p[1] for p in turn_pwm_yaw]) # 分左转和右转 left_mask = pwms < 1500 right_mask = pwms > 1500 if np.sum(left_mask) >= 2: x_left = 1500 - pwms[left_mask] y_left = yaw_rates[left_mask] k_left = np.polyfit(x_left, y_left, 1)[0] print(f"\n左转模型:ω = {k_left:.8f} × (1500 - pwm)") print(f"#define MC_CFG_STEERING_K_LEFT ({k_left:.8f}f)") if np.sum(right_mask) >= 2: x_right = pwms[right_mask] - 1500 y_right = -yaw_rates[right_mask] # 取反,因为右转是负角速度 k_right = np.polyfit(x_right, y_right, 1)[0] print(f"\n右转模型:ω = -{k_right:.8f} × (pwm - 1500)") print(f"#define MC_CFG_STEERING_K_RIGHT ({k_right:.8f}f)") if __name__ == '__main__': main()