From 4bf8ac52d26c61b088653504e4bc0d6e74064b1f Mon Sep 17 00:00:00 2001
From: Jose Cruz Toledo <1273555+jctoledo@users.noreply.github.com>
Date: Thu, 1 Jan 2026 08:14:44 -0800
Subject: [PATCH 1/7] various updates to autotune feature
---
sensors/blackbox/src/websocket_server.rs | 1058 +++++++++++++++++++++-
1 file changed, 1047 insertions(+), 11 deletions(-)
diff --git a/sensors/blackbox/src/websocket_server.rs b/sensors/blackbox/src/websocket_server.rs
index 1e94344..e3e1c08 100644
--- a/sensors/blackbox/src/websocket_server.rs
+++ b/sensors/blackbox/src/websocket_server.rs
@@ -267,7 +267,7 @@ body{font-family:-apple-system,system-ui,sans-serif;background:#0a0a0f;color:#f0
.cfg-btn.cfg-save{background:linear-gradient(135deg,#1e3a5f,#1a2d4a);color:#60a5fa}
-
@@ -332,17 +332,51 @@ const $=id=>document.getElementById(id);
const cv=$('gfc'),ctx=cv.getContext('2d');
const CX=70,CY=70,R=55,SCL=R/2;
-// Preset definitions based on real-world G-forces (tested values):
-// City: gentle-normal inputs (0.10-0.20g accel, 0.15-0.30g brake, 0.10-0.25g lateral)
-// Highway: mostly cruising, higher speed threshold to filter parking maneuvers
-// Canyon: spirited driving (0.20-0.40g range)
-// Track: racing (0.35-0.80g+ range)
-const PRESETS={
-track:{acc:0.35,acc_exit:0.17,brake:0.55,brake_exit:0.27,lat:0.50,lat_exit:0.25,yaw:0.15,min_speed:4.0,desc:'Racing/track days'},
+// Scaling factors: multiply city (baseline) thresholds by these for other modes
+// Based on physics: track pushes vehicle harder, highway is gentle lane changes
+const PROFILE_SCALES={
+track:{acc:2.5,brake:2.0,lat:3.0,yaw:2.5,min_speed:5.0,desc:'Racing/track days'},
+canyon:{acc:1.5,brake:1.5,lat:1.8,yaw:1.6,min_speed:3.0,desc:'Spirited mountain roads'},
+city:{acc:1.0,brake:1.0,lat:1.0,yaw:1.0,min_speed:2.0,desc:'Daily street driving'},
+highway:{acc:0.8,brake:0.7,lat:0.6,yaw:0.6,min_speed:12.0,desc:'Highway cruising'}
+};
+
+// Default presets (used when no calibration exists)
+const DEFAULT_PRESETS={
+track:{acc:0.35,acc_exit:0.17,brake:0.55,brake_exit:0.27,lat:0.50,lat_exit:0.25,yaw:0.15,min_speed:5.0,desc:'Racing/track days'},
canyon:{acc:0.22,acc_exit:0.11,brake:0.35,brake_exit:0.17,lat:0.28,lat_exit:0.14,yaw:0.10,min_speed:3.0,desc:'Spirited mountain roads'},
city:{acc:0.10,acc_exit:0.05,brake:0.18,brake_exit:0.09,lat:0.12,lat_exit:0.06,yaw:0.05,min_speed:2.0,desc:'Daily street driving'},
-highway:{acc:0.12,acc_exit:0.06,brake:0.22,brake_exit:0.11,lat:0.14,lat_exit:0.07,yaw:0.04,min_speed:5.0,desc:'Highway cruising'}
+highway:{acc:0.12,acc_exit:0.06,brake:0.22,brake_exit:0.11,lat:0.14,lat_exit:0.07,yaw:0.04,min_speed:12.0,desc:'Highway cruising'}
+};
+
+// Generate all profiles from city baseline thresholds
+function generateAllProfiles(cityBase){
+const profiles={};
+for(const[mode,scale]of Object.entries(PROFILE_SCALES)){
+profiles[mode]={
+acc:Math.max(0.05,cityBase.acc*scale.acc),
+acc_exit:Math.max(0.02,cityBase.acc_exit*scale.acc),
+brake:Math.max(0.08,cityBase.brake*scale.brake),
+brake_exit:Math.max(0.04,cityBase.brake_exit*scale.brake),
+lat:Math.max(0.05,cityBase.lat*scale.lat),
+lat_exit:Math.max(0.02,cityBase.lat_exit*scale.lat),
+yaw:Math.max(0.02,cityBase.yaw*scale.yaw),
+min_speed:scale.min_speed,
+desc:scale.desc
};
+}
+return profiles;
+}
+
+// Get presets - prefer calibrated profiles, fall back to defaults
+function getPresets(){
+const calib=localStorage.getItem('bb_profiles');
+if(calib){
+try{return JSON.parse(calib).profiles}catch(e){}
+}
+return DEFAULT_PRESETS;
+}
+const PRESETS=getPresets();
function fmtTime(ms){const s=Math.floor(ms/1000),m=Math.floor(s/60);return String(m).padStart(2,'0')+':'+String(s%60).padStart(2,'0')}
@@ -501,6 +535,18 @@ $('s-yaw').value=p.yaw;$('v-yaw').textContent=p.yaw.toFixed(3);
$('s-minspd').value=p.min_speed;$('v-minspd').textContent=p.min_speed.toFixed(1);
}
+// Get most recent autotune profile from localStorage
+function getCalibrationData(){
+try{
+const data=JSON.parse(localStorage.getItem('bb_profiles')||'null');
+return data;
+}catch(e){return null}
+}
+function isCalibrated(){
+const data=getCalibrationData();
+return data&&data.profiles;
+}
+
// Select preset and apply
function selectPreset(name){
currentPreset=name;
@@ -518,6 +564,14 @@ const p=PRESETS[name];
updateSummary(p);
applyPresetToSliders(p);
sendSettings(p);
+}else if(isCustom){
+// For custom, try to load from autotune profile
+const at=getAutotuneProfile();
+if(at){
+const p={acc:at.acc,acc_exit:at.acc_exit,brake:at.brake,brake_exit:at.brake_exit,lat:at.lat,lat_exit:at.lat_exit,yaw:at.yaw,min_speed:at.min_speed};
+applyPresetToSliders(p);
+sendSettings(p);
+}
}
}
@@ -574,6 +628,21 @@ if(Math.abs(s.acc-p.acc)<0.01&&Math.abs(s.lat-p.lat)<0.01&&Math.abs(s.min_speed-
matched=name;break;
}
}
+// Update preset buttons to show calibration status
+const calib=getCalibrationData();
+document.querySelectorAll('.preset-btn:not(.custom)').forEach(btn=>{
+const name=btn.dataset.preset;
+if(calib&&calib.profiles){
+// Show calibrated indicator
+btn.innerHTML=name.charAt(0).toUpperCase()+name.slice(1)+' ●';
+btn.title='Calibrated '+new Date(calib.date).toLocaleDateString();
+}
+});
+// Update custom button
+const customBtn=document.querySelector('.preset-btn.custom');
+if(customBtn){
+customBtn.textContent='Custom';
+}
currentPreset=matched;
// Update UI
document.querySelectorAll('.preset-btn').forEach(b=>{
@@ -716,6 +785,952 @@ update();