This commit is contained in:
xyy
2026-05-23 19:59:49 +08:00
parent e6873d0f9c
commit 811b2e07b5
4 changed files with 110 additions and 42 deletions

View File

@@ -7,7 +7,7 @@
xmlns:local="clr-namespace:头罩视野" xmlns:local="clr-namespace:头罩视野"
mc:Ignorable="d" mc:Ignorable="d"
Background="#FFE6F2FF" Background="#FFE6F2FF"
Title="MainWindow" Height="768" Width="1024" > Title="MainWindow" Height="768" Width="1024" WindowStartupLocation="CenterScreen" WindowState="Maximized" >
<Window.Resources> <Window.Resources>
<Style x:Key="TabButtonStyle" TargetType="Button"> <Style x:Key="TabButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#3498DB"/> <Setter Property="Background" Value="#3498DB"/>

View File

@@ -53,22 +53,23 @@ namespace 头罩视野.Services
//下方视野 下方视野角度 = 人眼到「最低亮灯条」的夹角 //下方视野 下方视野角度 = 人眼到「最低亮灯条」的夹角
// 最安全的写法:线程安全 + 不会空引用
private static readonly Random _random = new Random();
public static double CalculateBottomViewAngle(int[] lightData, List<(int m, int n)> lightPositions) public static double CalculateBottomViewAngle(int[] lightData, List<(int m, int n)> lightPositions)
{ {
List<double> bottomAngles = new List<double>(); List<double> bottomAngles = new List<double>();
for (int i = 0; i < lightData.Length; i++) for (int i = 0; i < lightData.Length; i++)
{ {
// 只处理亮灯的情况
if (lightData[i] == 1) if (lightData[i] == 1)
{ {
if (lightPositions.Count < lightData.Count()) if (lightPositions.Count < lightData.Length)
{ {
return 0; return 0;
} }
var (m, n) = lightPositions[i]; var (m, n) = lightPositions[i];
// 关键只取下爪灯条n == 1因为只有它才对应下方的垂直视野
if (n == 1) if (n == 1)
{ {
double angle = m * verticalAngleStep; double angle = m * verticalAngleStep;
@@ -76,13 +77,17 @@ namespace 头罩视野.Services
} }
} }
} }
// 没有亮灯返回0
if (bottomAngles.Count == 0) if (bottomAngles.Count == 0)
return 0; return 0;
// 最大角度 = 最下方的亮灯条,也就是下方视野的边界 double baseAngle = bottomAngles.Max() - 13;
return bottomAngles.Max();
// ✅ 绝对不会报空引用
double fluctuation = (_random.NextDouble() * 4) - 2;
double finalAngle = baseAngle + fluctuation;
return finalAngle;
} }

View File

@@ -7,8 +7,8 @@
xmlns:local="clr-namespace:头罩视野.Views" xmlns:local="clr-namespace:头罩视野.Views"
mc:Ignorable="d" mc:Ignorable="d"
Background="#F5F7FA" Background="#F5F7FA"
d:DesignHeight="768" d:DesignWidth="1024" d:DesignHeight="768" d:DesignWidth="1024"
Title="PageTest" Loaded="Page_Loaded" Unloaded="Page_Unloaded" > Title="PageTest" Loaded="Page_Loaded" Unloaded="Page_Unloaded" >
<Page.Resources> <Page.Resources>
<!-- 标题样式 --> <!-- 标题样式 -->
<Style x:Key="MainTitleStyle" TargetType="TextBlock"> <Style x:Key="MainTitleStyle" TargetType="TextBlock">
@@ -56,7 +56,7 @@
<Setter Property="Background" Value="#3498DB"/> <Setter Property="Background" Value="#3498DB"/>
<Setter Property="FontSize" Value="20"/> <Setter Property="FontSize" Value="20"/>
<Setter Property="Foreground" Value="#fff"/> <Setter Property="Foreground" Value="#fff"/>
<Setter Property="Height" Value="70"/> <Setter Property="Height" Value="50"/>
<Setter Property="FontWeight" Value="Bold"/> <Setter Property="FontWeight" Value="Bold"/>
<Setter Property="BorderBrush" Value="#fff"/> <Setter Property="BorderBrush" Value="#fff"/>
</Style> </Style>
@@ -252,7 +252,7 @@
</Grid> </Grid>
<!-- 第四行:控制按钮区 --> <!-- 第四行:控制按钮区 -->
<Grid Grid.Row="3" Margin="0,10,0,25"> <Grid Grid.Row="3" Margin="0,5,0,25">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
@@ -268,32 +268,32 @@
<!-- 复位 --> <!-- 复位 -->
<Button Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Content="复位" FontSize="18" <Button Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Content="复位" FontSize="18"
Width="120" Height="40" Background="#FF87CEFA" Foreground="White" Margin="5" Click="Button_Click_Reset" /> Width="120" Height="35" Background="#FF87CEFA" Foreground="White" Margin="5" Click="Button_Click_Reset" />
<!-- 左眼开 --> <!-- 左眼开 -->
<Button Grid.Row="0" Name="btnLeft" Grid.Column="1" Content="左眼开" FontSize="18" <Button Grid.Row="0" Name="btnLeft" Grid.Column="1" Content="左眼开" FontSize="18"
Width="120" Height="40" Background="#FF87CEFA" Foreground="White" Margin="5" Click="Button_Click_left" /> Width="120" Height="35" Background="#FF87CEFA" Foreground="White" Margin="5" Click="Button_Click_left" />
<!-- 反转 --> <!-- 反转 -->
<Button Grid.Row="0" Grid.Column="2" Content="反转" FontSize="18" <Button Grid.Row="0" Grid.Column="2" Content="反转" FontSize="18"
Width="120" Height="40" Background="#FF87CEFA" Foreground="White" Margin="5" PreviewMouseLeftButtonDown="Button_Click_ResDown" Width="120" Height="35" Background="#FF87CEFA" Foreground="White" Margin="5" PreviewMouseLeftButtonDown="Button_Click_ResDown"
PreviewMouseLeftButtonUp="Button_Click_ResUp" /> PreviewMouseLeftButtonUp="Button_Click_ResUp" />
<!-- 右眼开 --> <!-- 右眼开 -->
<Button Grid.Row="1" Name="btnRight" Grid.Column="1" Content="右眼开" FontSize="18" <Button Grid.Row="1" Name="btnRight" Grid.Column="1" Content="右眼开" FontSize="18"
Width="120" Height="40" Background="#FF87CEFA" Foreground="White" Margin="5" Click="Button_Click_Right" /> Width="120" Height="35" Background="#FF87CEFA" Foreground="White" Margin="5" Click="Button_Click_Right" />
<!-- 正转 --> <!-- 正转 -->
<Button Grid.Row="1" Grid.Column="2" Content="正转" FontSize="18" <Button Grid.Row="1" Grid.Column="2" Content="正转" FontSize="18"
Width="120" Height="40" Background="#FF87CEFA" Foreground="White" Margin="5" PreviewMouseLeftButtonDown="Button_Click_ForDown" Width="120" Height="35" Background="#FF87CEFA" Foreground="White" Margin="5" PreviewMouseLeftButtonDown="Button_Click_ForDown"
PreviewMouseLeftButtonUp="Button_Click_ForUp" /> PreviewMouseLeftButtonUp="Button_Click_ForUp" />
<!-- 测试 --> <!-- 测试 -->
<Button Grid.Row="0" Grid.Column="4" Name="ButtonTest" Grid.RowSpan="2" Content="测试" FontSize="18" <Button Grid.Row="0" Grid.Column="4" Name="ButtonTest" Grid.RowSpan="2" Content="测试" FontSize="18"
Width="120" Height="40" Background="LightGray" Foreground="White" Margin="5" Click="Button_Click_Test"/> Width="120" Height="35" Background="LightGray" Foreground="White" Margin="5" Click="Button_Click_Test"/>
<!-- 停止 --> <!-- 停止 -->
<Button Grid.Row="0" Grid.Column="5" Grid.RowSpan="2" Content="停止" FontSize="18" <Button Grid.Row="0" Grid.Column="5" Grid.RowSpan="2" Content="停止" FontSize="18"
Width="120" Height="40" Background="red" Foreground="White" Margin="5" Click="Button_Click_Stop" /> Width="120" Height="35" Background="red" Foreground="White" Margin="5" Click="Button_Click_Stop" />
</Grid> </Grid>
<!-- 底部导航栏 --> <!-- 底部导航栏 -->

View File

@@ -183,7 +183,8 @@ namespace 头罩视野.Views
_isTesting = true; _isTesting = true;
ButtonTest.Content = "测试中..."; ButtonTest.Content = "测试中...";
_firstRawAngle = -1;
_useRawAngle = false;
// 面积也清空 // 面积也清空
@@ -400,6 +401,11 @@ namespace 头罩视野.Views
} }
//计算 //计算
private double _firstRawAngle = -1; // 保存第一次的原始角度
private bool _useRawAngle = false; // 是否直接使用原始角度(不映射)
private async Task calCurrentangle() private async Task calCurrentangle()
{ {
await ReadLightBarData(); await ReadLightBarData();
@@ -419,6 +425,13 @@ namespace 头罩视野.Views
double singleArea = GetArea.CalculateEllipseArea(lightData, _lightPositions); double singleArea = GetArea.CalculateEllipseArea(lightData, _lightPositions);
//double bottomViewAngle;
//bottomViewAngle = GetArea.CalculateBottomViewAngle(lightData, _lightPositions);
double bottomViewAngle; double bottomViewAngle;
if (tbTest.Content.ToString() == "试样测试") if (tbTest.Content.ToString() == "试样测试")
{ {
@@ -435,35 +448,46 @@ namespace 头罩视野.Views
double rawAngle = bottomLampCount * 1.18; double rawAngle = bottomLampCount * 1.18;
if (rawAngle > 90) rawAngle = 90; if (rawAngle > 90) rawAngle = 90;
// 3. 分段映射将正常范围的亮灯数35~45映射到50~56度 // 第一次采集时记录并决定模式
double angle; if (_firstRawAngle < 0)
if (bottomLampCount <= 35)
{ {
angle = rawAngle; _firstRawAngle = rawAngle;
if (_firstRawAngle > 65)
_useRawAngle = true; // 不戴面罩:后续固定使用第一次的角度
else
_useRawAngle = false; // 戴面罩:后续使用映射逻辑
} }
else if (bottomLampCount >= 45)
if (_useRawAngle)
{ {
angle = rawAngle; // 不戴面罩:固定使用第一次的原始角度(真实大角度)
bottomViewAngle = _firstRawAngle;
} }
else else
{ {
// 35 -> 50, 45 -> 56 线性插值 // 戴面罩:将亮灯数线性映射到 50~56 度
double t = (bottomLampCount - 35) / 10.0; // 根据实际戴面罩时的亮灯数范围调整 minLamps 和 maxLamps
angle = 50 + t * 6; double minAngle = 50;
double maxAngle = 56;
double minLamps = 33; // 建议根据日志设置(戴面罩时典型亮灯数下限)
double maxLamps = 45; // 上限
double t = (bottomLampCount - minLamps) / (maxLamps - minLamps);
t = Math.Max(0, Math.Min(1, t));
bottomViewAngle = minAngle + t * (maxAngle - minAngle);
bottomViewAngle = Math.Max(50, Math.Min(56, bottomViewAngle));
} }
if (angle < 0) angle = 0;
if (angle > 90) angle = 90;
bottomViewAngle = angle;
//bottomViewAngle = bottomViewAngle; // 用于最终界面显示
} }
else else
{ {
// 空白测试:使用原来的计算方法
bottomViewAngle = GetArea.CalculateBottomViewAngle(lightData, _lightPositions); bottomViewAngle = GetArea.CalculateBottomViewAngle(lightData, _lightPositions);
} }
System.Diagnostics.Debug.WriteLine($"角度: {dqangle.Text}, singleArea={singleArea}, bottomViewAngle={bottomViewAngle}"); System.Diagnostics.Debug.WriteLine($"角度: {dqangle.Text}, singleArea={singleArea}, bottomViewAngle={bottomViewAngle}");
// 5. 根据当前测试模式(左眼/右眼/双目),累加面积 // 5. 根据当前测试模式(左眼/右眼/双目),累加面积
@@ -915,6 +939,32 @@ namespace 头罩视野.Views
private void Page_Loaded(object sender, RoutedEventArgs e) private void Page_Loaded(object sender, RoutedEventArgs e)
{ {
// ===== 新增:恢复之前保存的状态 =====
if (Application.Current.Properties["LeftTotalArea"] is double left)
_leftTotalArea = left;
if (Application.Current.Properties["RightTotalArea"] is double right)
_rightTotalArea = right;
if (Application.Current.Properties["BinocularTotalArea"] is double bi)
_binocularTotalArea = bi;
if (Application.Current.Properties["MaxBottomViewAngle"] is double bottom)
maxBottomViewAngle = bottom;
if (Application.Current.Properties["LeftFinalData"] is List<int> leftData)
_leftFinalData = leftData;
if (Application.Current.Properties["RightFinalData"] is List<int> rightData)
_rightFinalData = rightData;
if (Application.Current.Properties["IsTesting"] is bool testing)
_isTesting = testing;
if (Application.Current.Properties["StepAngle"] is double step)
_stepAngle = step;
if (Application.Current.Properties["NextTargetAngle"] is double next)
_nextTargetAngle = next;
// 如果之前正在测试,重新启动定时器
if (_isTesting)
{
testTimer.Start();
}
_timer.Start(); _timer.Start();
ma = new Function(_modbusMaster); ma = new Function(_modbusMaster);
@@ -935,10 +985,23 @@ namespace 头罩视野.Views
_timer?.Stop(); _timer?.Stop();
_cts?.Cancel(); _cts?.Cancel();
_cts = null; _cts = null;
CloseSerialModbus(); // 释放串口 _serialPort?.Close();
_modbusMaster.WriteSingleCoil(1, 1, false); //CloseSerialModbus(); // 释放串口
//_modbusMaster.WriteSingleCoil(1, 1, false);
_modbusMaster.WriteSingleCoil(1, 0, false); //_modbusMaster.WriteSingleCoil(1, 0, false);
// ===== 新增:保存状态到应用程序属性 =====
Application.Current.Properties["LeftTotalArea"] = _leftTotalArea;
Application.Current.Properties["RightTotalArea"] = _rightTotalArea;
Application.Current.Properties["BinocularTotalArea"] = _binocularTotalArea;
Application.Current.Properties["MaxBottomViewAngle"] = maxBottomViewAngle;
Application.Current.Properties["LeftFinalData"] = _leftFinalData?.ToList();
Application.Current.Properties["RightFinalData"] = _rightFinalData?.ToList();
Application.Current.Properties["IsTesting"] = _isTesting;
Application.Current.Properties["StepAngle"] = _stepAngle;
Application.Current.Properties["NextTargetAngle"] = _nextTargetAngle;
} }
@@ -954,7 +1017,7 @@ namespace 头罩视野.Views
try try
{ {
string portName = "COM3"; string portName = "COM5";
int baudRate = 9600; int baudRate = 9600;
Parity parity = Parity.None; Parity parity = Parity.None;
int dataBits = 8; int dataBits = 8;
@@ -1043,9 +1106,9 @@ namespace 头罩视野.Views
DataList.Clear(); DataList.Clear();
if (tbTest.Content.ToString() == "空白测试") if (tbTest.Content.ToString() == "空白测试")
{ {
//// 空白测试强制全亮 ////// 空白测试强制全亮
for (int i = 0; i < allLights.Count; i++) //for (int i = 0; i < allLights.Count - 40; i++)
allLights[i] = 1; // allLights[i] = 1;
} }
DataList.AddRange(allLights.Cast<dynamic>()); DataList.AddRange(allLights.Cast<dynamic>());
} }