feat: integrate tangential force HUD

This commit is contained in:
lenn
2026-05-20 08:33:20 +08:00
parent 59e9203363
commit 6187976b6b
8 changed files with 1058 additions and 82 deletions

View File

@@ -1,13 +1,13 @@
#[cfg(feature = "devkit")]
use crate::devkit::{proto::SensorFrame, DevKitState};
use crate::serial_core::codec::Codec;
use crate::serial_core::codecs::tactile_a::TactileACodec;
use crate::serial_core::frame::{FrameHandler, TactileAFrame, TestFrame};
use crate::serial_core::model::{HudChartState, HudPacket};
use crate::serial_core::model::{HudChartState, HudPacket, HudSpatialForce};
#[cfg(feature = "multi-dim")]
use crate::serial_core::multi_dim_force::PztProcessor;
use crate::serial_core::record::Recording;
use crate::serial_core::record::{FrameTiming, RecordedFrame};
#[cfg(feature = "devkit")]
use crate::devkit::{proto::SensorFrame, DevKitState};
use anyhow::Result;
use log::debug;
use std::future::pending;
@@ -15,9 +15,9 @@ use std::future::pending;
use std::sync::atomic::Ordering;
use std::sync::{Arc, Mutex};
use std::time::Instant;
use tauri::{AppHandle, Emitter};
#[cfg(feature = "devkit")]
use tauri::Manager;
use tauri::{AppHandle, Emitter};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::time::{self, Duration, MissedTickBehavior};
use tokio_serial::SerialStream;
@@ -33,6 +33,7 @@ pub enum PollMode<F> {
struct PendingSubFrame<F> {
frame: F,
values: Vec<i32>,
spatial_force: Option<HudSpatialForce>,
}
pub trait SerialFrame: Clone + Send + 'static {
@@ -266,6 +267,7 @@ where
let display_values = build_display_values(
&mut chart_state,
pending.values.as_slice(),
pending.spatial_force,
);
if let Some(packet) = pending
@@ -309,11 +311,22 @@ where
drop(record);
if let Some(vals) = decode_res {
let mut spatial_force = None;
#[cfg(feature = "multi-dim")]
{
let pzt_values = vals.iter().map(|value| *value as f32).collect::<Vec<f32>>();
if let Ok(angle) = pzt_processor.get_pzt_angle(&pzt_values) {
// debug!("pzt angle: {:.2}", angle);
if let Ok(analysis) = pzt_processor.get_pzt_analysis(&pzt_values) {
debug!(
"spatial force: angle={:.2}°, magnitude={:.2}, dx={:.2}, dy={:.2}",
analysis.angle_deg, analysis.magnitude, analysis.planar_x, analysis.planar_y
);
if PztProcessor::should_report(&analysis) {
spatial_force = Some(HudSpatialForce {
angle_deg: analysis.angle_deg,
magnitude: analysis.magnitude,
confidence: analysis.confidence,
});
}
}
}
#[cfg(feature = "devkit")]
@@ -326,6 +339,7 @@ where
pending_sub_frame = Some(PendingSubFrame {
frame: frame.clone(),
values: vals,
spatial_force,
});
} else if let Some(packet) = frame.to_hud_packet(&mut chart_state, None) {
app.emit("hud_stream", packet)?;
@@ -337,11 +351,16 @@ where
Ok(())
}
fn build_display_values(chart_state: &mut HudChartState, values: &[i32]) -> Option<Vec<i32>> {
fn build_display_values(
chart_state: &mut HudChartState,
values: &[i32],
spatial_force: Option<HudSpatialForce>,
) -> Option<Vec<i32>> {
let summary = values.iter().copied().sum::<i32>();
let force = raw_to_g1(summary as u32);
chart_state.record_summary(force as f32);
chart_state.record_pressure_matrix(values);
chart_state.record_spatial_force(spatial_force);
Some(vec![summary])
}