Skip to content

Commit a341cfb

Browse files
author
Marcus Sonestedt
committed
ServoPIDControl: Record data from Ardunio into time series. Discard old data.
1 parent a49cb14 commit a341cfb

File tree

8 files changed

+65
-55
lines changed

8 files changed

+65
-55
lines changed

ServoPIDControl/ArduinoCom.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ private void LineReceived(string line)
153153
servo.Output = float.Parse(parts[3]);
154154
servo.Integrator = float.Parse(parts[4]);
155155
servo.DFiltered = float.Parse(parts[5]);
156+
157+
servo.RecordTimePoint();
156158
}
157159
catch (Exception e)
158160
{
@@ -192,7 +194,6 @@ public ViewModel Model
192194

193195
_model = value;
194196

195-
// ReSharper disable once InvertIf
196197
if (Model != null)
197198
{
198199
Model.PropertyChanged += ModelOnPropertyChanged;
@@ -248,6 +249,7 @@ private void ServosOnCollectionChanged(object sender, NotifyCollectionChangedEve
248249
servo.PropertyChanged += ServoOnPropertyChanged;
249250

250251
if (e.Action == NotifyCollectionChangedAction.Reset)
252+
// it's probably empty, but just in case...
251253
foreach (var servo in Model.Servos)
252254
servo.PropertyChanged -= ServoOnPropertyChanged;
253255
}

ServoPIDControl/Helper/README_NLog_WpfRichTextBox.txt

Lines changed: 0 additions & 28 deletions
This file was deleted.

ServoPIDControl/VisibilityToCheckedConverter.cs renamed to ServoPIDControl/Helper/VisibilityToCheckedConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using System.Windows;
33
using System.Windows.Data;
44

5-
namespace ServoPIDControl
5+
namespace ServoPIDControl.Helper
66
{
77
public class VisibilityToCheckedConverter : IValueConverter
88
{

ServoPIDControl/MainWindow.xaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
xmlns:d3="clr-namespace:InteractiveDataDisplay.WPF;assembly=mpolewaczyk.InteractiveDataDisplay.WPF"
88
xmlns:local="clr-namespace:ServoPIDControl"
99
xmlns:model="clr-namespace:ServoPIDControl.Model"
10+
xmlns:helper="clr-namespace:ServoPIDControl.Helper"
1011
mc:Ignorable="d"
1112
Title="Arduino Servo PID Control">
1213
<Window.DataContext>
1314
<model:ViewModel x:Name="Model" />
1415
</Window.DataContext>
1516
<Window.Resources>
16-
<local:VisibilityToCheckedConverter x:Key="VisibilityToCheckedConverter" />
17+
<helper:VisibilityToCheckedConverter x:Key="VisibilityToCheckedConverter" />
1718
</Window.Resources>
1819
<Grid>
1920
<Grid.ColumnDefinitions>

ServoPIDControl/MainWindow.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ private void ConnectNLogToUi()
9292
AutoScroll = true,
9393
// ReSharper disable StringLiteralTypo
9494
Layout = "${processtime} [${level:uppercase=true}] " +
95-
"${logger:shortName=true}: ${message}" +
95+
"${logger:shortName=true}: ${message} " +
9696
"${exception:innerFormat=tostring:maxInnerExceptionLevel=10:separator=,:format=tostring}",
9797
// ReSharper restore StringLiteralTypo
9898
};

ServoPIDControl/Model/ServoPidModel.cs

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
using System;
2-
using System.Collections;
32
using System.Collections.Generic;
43
using System.Collections.ObjectModel;
54
using System.ComponentModel;
5+
using System.Diagnostics;
66
using System.Linq;
77
using System.Runtime.CompilerServices;
8-
using InteractiveDataDisplay.WPF;
98
using ServoPIDControl.Annotations;
109

1110
namespace ServoPIDControl.Model
1211
{
1312
public class ServoPidModel : INotifyPropertyChanged
1413
{
14+
public static float TimeSeriesLengthSec = 5.0f;
15+
1516
private float _p;
1617
private float _i;
1718
private float _d;
@@ -24,24 +25,33 @@ public class ServoPidModel : INotifyPropertyChanged
2425
private float _integrator;
2526
private float _dFiltered;
2627

28+
private readonly Stopwatch _stopWatch = Stopwatch.StartNew();
29+
private readonly object _timeSeriesLock = new object();
30+
2731
public ServoPidModel(int id)
2832
{
2933
Id = id;
3034

3135
#if DEBUG
32-
Times = new ObservableCollection<float>(Enumerable.Range(0, 500).Select(i => i / 100.0f));
33-
SetPoints = new ObservableCollection<float>(Enumerable.Range(id * 100, 500)
34-
.Select(i => i / 100 % 2 == 0 ? 80.0f : 100.0f));
35-
Inputs = new ObservableCollection<float>(Enumerable.Range(id * 100, 500)
36-
.Select(i => 90 + (float) Math.Sin(i / 50.0f)));
37-
Outputs = new ObservableCollection<float>(Enumerable.Range(id * 100, 500)
38-
.Select(i => 90 + (float) Math.Cos(i / 50.0f)));
36+
lock (_timeSeriesLock)
37+
{
38+
const int ts = 500;
39+
40+
Times = Enumerable.Range(0, ts)
41+
.Select(i => i / 100.0f).ToList();
42+
SetPoints = Enumerable.Range(id * 100, ts)
43+
.Select(i => i / 100 % 2 == 0 ? 80.0f : 100.0f).ToList();
44+
Inputs = Enumerable.Range(id * 100, ts)
45+
.Select(i => 90 + (float) Math.Cos(i / 20.0f) * 9).ToList();
46+
Outputs = Enumerable.Range(id * 100, ts)
47+
.Select(i => 90 + (float) Math.Sin(i / 20.0f) * 5).ToList();
48+
}
3949
#endif
4050
}
4151

4252
public int Id { get; }
4353

44-
public float P
54+
public float P
4555
{
4656
get => _p;
4757
set
@@ -163,26 +173,35 @@ internal set
163173
}
164174

165175
// ReSharper disable MemberInitializerValueIgnored
166-
public ObservableCollection<float> Times { get; } = new ObservableCollection<float>();
167-
public ObservableCollection<float> SetPoints { get; } = new ObservableCollection<float>();
168-
public ObservableCollection<float> Inputs { get; } = new ObservableCollection<float>();
169-
public ObservableCollection<float> Outputs { get; } = new ObservableCollection<float>();
176+
public List<float> Times { get; } = new List<float>();
177+
public List<float> SetPoints { get; } = new List<float>();
178+
public List<float> Inputs { get; } = new List<float>();
179+
180+
public List<float> Outputs { get; } = new List<float>();
170181
// ReSharper restore MemberInitializerValueIgnored
171182

172183
public struct TimeSeries
173184
{
174-
public ObservableCollection<float> X;
175-
public ObservableCollection<float> Y;
185+
public float[] X;
186+
public float[] Y;
176187
public string Name;
177188
}
178189

179190
public IEnumerable<TimeSeries> AllTimeSeries
180191
{
181192
get
182193
{
183-
yield return new TimeSeries {X = Times, Y = SetPoints, Name = "SetPoint"};
184-
yield return new TimeSeries {X = Times, Y = Inputs, Name = "Input"};
185-
yield return new TimeSeries {X = Times, Y = Outputs, Name = "Output"};
194+
lock (_timeSeriesLock)
195+
{
196+
if (!Times.Any())
197+
yield break;
198+
199+
var timeArray = Times.ToArray();
200+
201+
yield return new TimeSeries {X = timeArray, Y = SetPoints.ToArray(), Name = "SetPoint"};
202+
yield return new TimeSeries {X = timeArray, Y = Inputs.ToArray(), Name = "Input"};
203+
yield return new TimeSeries {X = timeArray, Y = Outputs.ToArray(), Name = "Output"};
204+
}
186205
}
187206
}
188207

@@ -193,5 +212,24 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName
193212
{
194213
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
195214
}
215+
216+
public void RecordTimePoint()
217+
{
218+
lock (_timeSeriesLock)
219+
{
220+
Times.Add((float) _stopWatch.Elapsed.TotalSeconds);
221+
SetPoints.Add(SetPoint);
222+
Inputs.Add(Input);
223+
Outputs.Add(Output);
224+
225+
var lastTime = Times.Last();
226+
var removeCount = Times.TakeWhile(t => lastTime - t > TimeSeriesLengthSec).Count();
227+
228+
Times.RemoveRange(0, removeCount);
229+
SetPoints.RemoveRange(0, removeCount);
230+
Inputs.RemoveRange(0, removeCount);
231+
Outputs.RemoveRange(0, removeCount);
232+
}
233+
}
196234
}
197235
}

ServoPIDControl/ServoPidControl.csproj

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
<Compile Include="ISerialPort.cs" />
9292
<Compile Include="Properties\Annotations.cs" />
9393
<Compile Include="Model\ServoPidModel.cs" />
94-
<Compile Include="VisibilityToCheckedConverter.cs" />
94+
<Compile Include="Helper\VisibilityToCheckedConverter.cs" />
9595
<Page Include="MainWindow.xaml">
9696
<Generator>MSBuild:Compile</Generator>
9797
<SubType>Designer</SubType>
@@ -141,8 +141,5 @@
141141
<ItemGroup>
142142
<Folder Include="Tests\" />
143143
</ItemGroup>
144-
<ItemGroup>
145-
<Resource Include="Helper\README_NLog_WpfRichTextBox.txt" />
146-
</ItemGroup>
147144
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
148145
</Project>

ServoPIDControl/screenshot.png

179 KB
Loading

0 commit comments

Comments
 (0)