Skip to content

Commit 7cb34e3

Browse files
author
Marcus Sonestedt
committed
ServoPID: Misc failed attempts to make serial com more robust
1 parent e475c95 commit 7cb34e3

File tree

5 files changed

+162
-51
lines changed

5 files changed

+162
-51
lines changed

ServoPID/ServoPIDControl/ArduinoCom.cs

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class ArduinoCom : IDisposable
3838
private SerialPort _port;
3939
private readonly StringBuilder _readBuf = new StringBuilder();
4040
private ArduinoModel _model;
41-
private readonly DispatcherTimer _timer = new DispatcherTimer() {Interval = TimeSpan.FromMilliseconds(10)};
41+
private readonly DispatcherTimer _timer = new DispatcherTimer {Interval = TimeSpan.FromMilliseconds(250)};
4242
private readonly object _portLock = new object();
4343

4444
public ArduinoCom()
@@ -54,7 +54,7 @@ private void TimerOnTick(object sender, EventArgs e)
5454
if ((!_port?.IsOpen ?? false) || Model == null)
5555
return;
5656

57-
SendCommand(Command.GetServoData, (byte)Model.Servos.Count);
57+
SendCommand(Command.GetServoData, (byte) Model.Servos.Count);
5858
}
5959

6060
public class StringEventArgs : EventArgs
@@ -71,39 +71,51 @@ private void PortOnDataReceived(object sender, SerialDataReceivedEventArgs e)
7171
_readBuf.Append(_port.ReadExisting());
7272
}
7373

74-
while (_readBuf.ToString().Contains('\n'))
74+
string str;
75+
while ((str = _readBuf.ToString()).IndexOfAny(new [] {'\n', '\r'}) >= 0)
7576
{
76-
//Debug.WriteLine(_readBuf.ToString());
77-
78-
var lines = _readBuf.ToString().Split('\n');
79-
foreach (var line in lines.Select(l => l.Trim()).Where(l => !string.IsNullOrWhiteSpace(l)))
80-
LineReceived(line);
81-
77+
var lines = str.Split(new[] {'\n','\r'}, StringSplitOptions.RemoveEmptyEntries);
78+
Application.Current.Dispatcher.Invoke(() => LineReceived(lines.First().Trim()));
8279
_readBuf.Clear();
80+
_readBuf.Append(string.Join("\n", lines.Skip(1)));
8381
}
8482
}
8583

8684
private void LineReceived(string line)
8785
{
8886
if (line.StartsWith("DT "))
8987
{
90-
if (float.TryParse(line.Substring(3), out var dt))
91-
Model.DeltaTime = dt;
92-
else
93-
Debug.WriteLine("Bad DT received: " + line);
94-
88+
var parts = line.Split(' ');
89+
try
90+
{
91+
Model.DeltaTime = float.Parse(parts[1]);
92+
Model.MinDt = float.Parse(parts[2]);
93+
Model.MaxDt = float.Parse(parts[3]);
94+
}
95+
catch (Exception e)
96+
{
97+
Debug.WriteLine($"Bad DT received: {line} - {e.Message}");
98+
}
99+
95100
return;
96101
}
97102

98103
if (line.StartsWith("NS "))
99104
{
100105
Application.Current.Dispatcher.Invoke(() =>
101106
{
102-
Model.Servos.Clear();
107+
if (!int.TryParse(line.Substring(3), out var numServos))
108+
return;
103109

104-
if (int.TryParse(line.Substring(3), out var numServos))
105-
for (var i = 0; i < numServos; ++i)
106-
Model.Servos.Add(new ServoPidModel(Model.Servos.Count));
110+
if (numServos >= 33)
111+
{
112+
Debug.WriteLine("Too many servos: " + numServos);
113+
return;
114+
}
115+
116+
Model.Servos.Clear();
117+
for (var i = 0; i < numServos; ++i)
118+
Model.Servos.Add(new ServoPidModel(Model.Servos.Count));
107119
});
108120

109121
SendCommand(Command.GetServoParams);
@@ -141,10 +153,22 @@ private void LineReceived(string line)
141153
}
142154
catch (Exception e)
143155
{
144-
Debug.WriteLine("Bad servo data: " + line + " - " + e.Message);
156+
Debug.WriteLine($"Bad servo data: {line} - {e.Message}");
145157
return;
146158
}
147159
}
160+
else if (line.StartsWith("ERR: "))
161+
{
162+
lock (_portLock)
163+
{
164+
_port.WriteLine("RST");
165+
}
166+
}
167+
else
168+
{
169+
Debug.WriteLine($"Ignored: {line}");
170+
return;
171+
}
148172

149173
MessageReceived?.Invoke(this, new StringEventArgs {Message = line});
150174
}
@@ -221,18 +245,16 @@ private void ServosOnCollectionChanged(object sender, NotifyCollectionChangedEve
221245
servo.PropertyChanged += ServoOnPropertyChanged;
222246

223247
if (e.Action == NotifyCollectionChangedAction.Reset)
224-
{
225248
foreach (var servo in Model.Servos)
226249
servo.PropertyChanged -= ServoOnPropertyChanged;
227-
}
228250
}
229251

230252
private void ModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
231253
{
232254
if (e.PropertyName == null || e.PropertyName == nameof(Model.Enabled))
233255
SendCommand(Command.EnableRegulator, (byte) (Model.Enabled ? 1 : 0));
234256

235-
if ((e.PropertyName == null || e.PropertyName == nameof(Model.PortName)))
257+
if (e.PropertyName == null || e.PropertyName == nameof(Model.PortName))
236258
ConnectPort();
237259

238260
if (e.PropertyName == null || e.PropertyName == nameof(Model.PollPidData))
@@ -288,7 +310,10 @@ private void ConnectPort()
288310
{
289311
_port = new SerialPort(Model.PortName)
290312
{
291-
BaudRate = 115200
313+
BaudRate = 115200,
314+
NewLine = "\n",
315+
ReadBufferSize = 4096,
316+
WriteBufferSize = 4096,
292317
};
293318
_port.Open();
294319

ServoPID/ServoPIDControl/ArduinoModel.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ namespace ServoPIDControl
1111
{
1212
public class ArduinoModel : INotifyPropertyChanged, IDisposable
1313
{
14-
private string _portName = "COM3";
14+
private string _portName = null;
1515
private bool _enabled = true;
1616
private float _deltaTime;
1717
private bool _connected;
1818
private bool _pollPidData;
1919
private string[] _comPorts;
2020

2121
private readonly DispatcherTimer _timer;
22+
private float _minDt;
23+
private float _maxDt;
2224

2325
public event PropertyChangedEventHandler PropertyChanged;
2426

@@ -102,6 +104,28 @@ internal set
102104
}
103105
}
104106

107+
public float MinDt
108+
{
109+
get => _minDt;
110+
set
111+
{
112+
if (value.Equals(_minDt)) return;
113+
_minDt = value;
114+
OnPropertyChanged();
115+
}
116+
}
117+
118+
public float MaxDt
119+
{
120+
get => _maxDt;
121+
set
122+
{
123+
if (value.Equals(_maxDt)) return;
124+
_maxDt = value;
125+
OnPropertyChanged();
126+
}
127+
}
128+
105129
[NotifyPropertyChangedInvocator]
106130
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
107131
{

ServoPID/ServoPIDControl/MainWindow.xaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,20 @@
2626
</StackPanel.Resources>
2727
<TextBlock Text="COM Port:" />
2828
<ComboBox x:Name="PortNameComboBox" SelectedItem="{Binding PortName}" Text="COM Port"
29-
ItemsSource="{Binding ComPorts, Mode=Onetime}" />
29+
ItemsSource="{Binding ComPorts, Mode=OneWay}" />
3030
<CheckBox x:Name="EnabledCheckBox" IsChecked="{Binding Enabled}" Content="Regulator enabled"
3131
IsEnabled="{Binding Connected, Mode=OneWay}" />
3232
<CheckBox x:Name="PollPidDataCheckBox" IsChecked="{Binding PollPidData}" Content="Poll PID data"
3333
IsEnabled="{Binding Connected}" />
3434
<TextBlock Text="Delta Time:" />
3535
<TextBox x:Name="DeltaTimeTextBox" Text="{Binding DeltaTime, Mode=OneWay, StringFormat=F6}" IsReadOnly="true"
3636
IsEnabled="{Binding Connected}" TextAlignment="Right" />
37+
<TextBlock Text="Min Delta Time:" />
38+
<TextBox x:Name="MinDeltaTimeTextBox" Text="{Binding MinDt, Mode=OneWay, StringFormat=F6}" IsReadOnly="true"
39+
IsEnabled="{Binding Connected}" TextAlignment="Right" />
40+
<TextBlock Text="Max Delta Time:" />
41+
<TextBox x:Name="MaxDeltaTimeTextBox" Text="{Binding MaxDt, Mode=OneWay, StringFormat=F6}" IsReadOnly="true"
42+
IsEnabled="{Binding Connected}" TextAlignment="Right" />
3743
</StackPanel>
3844
<DataGrid Grid.Row="0" Grid.Column="1"
3945
ItemsSource="{Binding Servos}" x:Name="ServosDataGrid" IsEnabled="{Binding Connected}">

ServoPID/ServoPIDControl/MainWindow.xaml.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.Windows;
1+
using System.ComponentModel;
2+
using System.Linq;
3+
using System.Windows;
24
using ServoPIDControl.Annotations;
35

46
namespace ServoPIDControl
@@ -17,11 +19,22 @@ public MainWindow()
1719

1820
Loaded += OnLoaded;
1921
Unloaded += OnUnloaded;
22+
23+
Model.PropertyChanged += ModelOnPropertyChanged;
24+
}
25+
26+
private void ModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
27+
{
28+
if (e.PropertyName == nameof(Model.ComPorts) && Model.PortName == null && Model.ComPorts != null)
29+
Model.PortName = Model.ComPorts.FirstOrDefault();
2030
}
2131

2232
private void OnLoaded(object sender, RoutedEventArgs e)
2333
{
2434
_arduinoCom.Model = Model;
35+
36+
if (Model.PortName == null && Model.ComPorts != null)
37+
Model.PortName = Model.ComPorts.FirstOrDefault();
2538
}
2639

2740
private void OnUnloaded(object sender, RoutedEventArgs e)

0 commit comments

Comments
 (0)