Skip to content
Snippets Groups Projects
Commit 1e10477c authored by Frederic Aust's avatar Frederic Aust
Browse files

4 Pumpen laufen, windows Programm funktioniert

parent 2ed11266
No related branches found
No related tags found
No related merge requests found
Showing
with 501 additions and 54 deletions
......@@ -22,7 +22,7 @@ Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
#define USMIN 600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX 2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates but in this case it's 60 Hz
#define NUM_PUMPS 3
#define NUM_PUMPS 4
#define PIN_AIR_PUMP 13
#define PIN_PSU 12
......@@ -31,16 +31,27 @@ bool waage_einstellen = false;
bool serving = false;
String input = "";
uint8_t servonum = 0;
unsigned long pumpTimer[NUM_PUMPS]; //pumps
unsigned long pumpValue[NUM_PUMPS]; //pumps
unsigned long goalWeight = 0;
unsigned long empty = 0;
float magic = 461.3;
unsigned long g600 = 419667;
typedef enum {
pump_ms,
pump_g,
tara,
idle
} action;
action currentAction = idle;
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
Serial.begin(115200);
Serial.println("######### Started #########");
......@@ -60,8 +71,8 @@ void setup()
for (int i = 0; i < NUM_PUMPS; i++)
{
openPump(i, 1000);
//closePump(i);
//openPumpForMs(i, 1000);
closePump(i);
}
// power on PSU
......@@ -77,41 +88,190 @@ void setup()
void loop()
{
// Check if any pump reached it's limit
unsigned long now = millis(); //get current timestamp
bool keepPumping = false;
float weight = 0;
if (scale.is_ready()) {
long reading = abs(scale.read());
//Serial.print("HX711 reading: ");
//Serial.println(reading);
weight = getWeight(reading);
Serial.println(String(weight));
}
if (currentAction == pump_ms)
{
// Check if any pump reached it's timelimit
unsigned long now = millis(); //get current timestamp
for (uint8_t i = 0; i < NUM_PUMPS; i++)
{
if (pumpTimer[i] > 0 and pumpTimer[i] <= now)
if (pumpValue[i] > 0 and pumpValue[i] <= now)
{
pumpTimer[i] = 0;
Serial.println("Pump " + String(i) + " is done");
pumpValue[i] = 0;
closePump(i);
}
if (pumpTimer[i] > 0)
if (pumpValue[i] > 0)
{
keepPumping = true;
}
}
} else if (currentAction == pump_g)
{
// if weightlimit reached stop pummping
if (scale.is_ready()) {
long reading = scale.read();
//Serial.print("HX711 reading: ");
//Serial.println(reading);
Serial.println(String(getWeight(-reading)));
bool readyForNext = false;
for (uint8_t i = 0; i < NUM_PUMPS; i++)
{
if (pumpValue[i] == 0)
{
//Serial.println("Pump " + String(i) + " nope");
//not current pump
continue;
}
if (pumpValue[i] > 0) {
if (readyForNext == true)
{
Serial.println("Pump " + String(i) + " started");
goalWeight += pumpValue[i];
Serial.println("Goal weight " + String(goalWeight));
openPump(i);
keepPumping = true;
readyForNext = false;
}
if (weight >= goalWeight) {
Serial.println("Pump " + String(i) + " done");
pumpValue[i] = 0;
closePump(i);
readyForNext = true;
} else
{
//currentPump, keep pumping and exit loop
keepPumping = true;
}
}
}
}
else if (currentAction == tara)
{
currentAction = idle;
initScale();
}
if (keepPumping == false)
{
deactivateAirPump();
currentAction = idle;
goalWeight = 0;
}
if (Serial.available())
{
String input = Serial.readString();
interpretInput(input);
}
delay(10); // just chilling a bit to reduce power consumtion (perhaps)
}
void interpretInput(String input)
{
//for Debugging
Serial.println("Got input: " + input);
// TODO get ';' separated line and returns array
Serial.println(" Convert from String Object to String.");
// https://forum.arduino.cc/index.php?topic=387175.0
int laenge = input.length();
char sz[laenge];
char buf[sizeof(sz)];
input.toCharArray(buf, sizeof(buf));
char *p = buf;
char *str;
int i = 0;
unsigned long pumpMS[NUM_PUMPS];
unsigned long pumpG[NUM_PUMPS];
currentAction = idle;
while ((str = strtok_r(p, ";", &p)) != NULL) // delimiter is the semicolon
{
Serial.println(str);
String pumpId = "";
String goalWeight = "";
// get Action
if (String(str) == "t")
{
currentAction = pump_ms;
continue;
} else if (String(str) == "g")
{
currentAction = pump_g;
continue;
} else if (String(str) == "tara")
{
currentAction = tara;
continue;
}
// get g /ms based on action
if (currentAction == pump_ms)
{
pumpMS[i] = strtoul(str, NULL, 10); // := milliseconds
}
else if (currentAction == pump_g)
{
//pumpId = str;
//if ((goalWeight = strtok_r(p, ";", &p)) != NULL)
//{
// pumpG[strtoul(pumpId, NULL, 10)] = strtoul(goalWeight, NULL, 10);
//
// Serial.println(goalWeight);
// }
pumpG[i] = strtoul(str, NULL, 10); // := milliseconds
}
i++;
}
Serial.println("done");
if (currentAction == pump_ms)
{
for (uint8_t i = 0; i < NUM_PUMPS; i++)
{
if (pumpMS[i] > 0)
{
openPumpForMs(i, pumpMS[i]);
}
else
{
closePump(i);
}
}
} else if (currentAction == pump_g)
{
goalWeight = 0;
bool firstSet = false;
for (uint8_t i = 0; i < NUM_PUMPS; i++)
{
pumpValue[i] = pumpG[i];
if (pumpG[i] > 0 && firstSet == false) {
firstSet = true;
goalWeight += pumpValue[i];
openPump(i);
}
Serial.println("Got weight goal for pump " + String(i) + ": " + String(pumpG[i]));
}
}
}
void interpretInput_old(String input)
{
//for Debugging
Serial.println("Got input: " + input);
// TODO get ';' separated line and returns array
......@@ -138,7 +298,7 @@ void loop()
{
if (pumpMS[i] > 0)
{
openPump(i, pumpMS[i]);
openPumpForMs(i, pumpMS[i]);
}
else
{
......@@ -146,5 +306,3 @@ void loop()
}
}
}
delay(10); // just chilling a bit to reduce power consumtion (perhaps)
}
......@@ -14,12 +14,17 @@ void closePump(uint8_t servo)
Serial.println("Servo: "+String(servo)+" closed");
}
void openPump(uint8_t servo, unsigned long milliseconds)
void openPumpForMs(uint8_t servo, unsigned long milliseconds)
{
openPump(servo);
pumpValue[servo] = millis() + milliseconds; // here save current timestamp + seconds the tube should be open
Serial.println("Servo: "+String(servo)+" opened for "+String(milliseconds));
}
void openPump(uint8_t servo)
{
activateAirPump();
setServoToDegree(servo, 100); //tubes are free
pumpTimer[servo] = millis() + milliseconds; // here save current timestamp + seconds the tube should be open
Serial.println("Servo: "+String(servo)+" opened for "+String(milliseconds));
Serial.println("Servo: "+String(servo)+" opened");
}
void activateAirPump()
......@@ -49,14 +54,18 @@ void setServoToDegree(uint8_t servo,int degree)
}
void initScale() {
Serial.println("Begin: Init Scale - Tara");
unsigned long initMedian = 0;
int i = 0;
for (; i < 10; i++) {
for (; i < 100; i++) {
long reading = scale.read();
initMedian += abs(reading);
delay(100);
}
empty = initMedian / i;
magic = (g600-empty)/600;
Serial.println("Done: Init Scale - Tara");
}
float getWeight(long scaleValue){
......
File added
......@@ -5,9 +5,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Cocktailmaker"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
Title="MainWindow" Height="450" Width="953.107" Closing="Window_Closing">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="20"/>
......@@ -15,16 +16,24 @@
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button x:Name="But_StatTask" Grid.Row="0" Grid.ColumnSpan="2" Content="Start Task" Click="But_StatTask_Click"/>
<TextBox x:Name="Tb_Result" Grid.Row="1" Grid.Column="0" Text="{Binding Result}" />
<DataGrid x:Name="dataGrid" Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Liste, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="True" CanUserReorderColumns="True" CanUserResizeColumns="True" CanUserResizeRows="True" CanUserSortColumns="True" RowBackground="White" AlternatingRowBackground="GhostWhite">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" Grid.Row="0" Grid.ColumnSpan="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ComboBox Name="cBPortList" Width="100" VerticalAlignment="Stretch" VerticalContentAlignment="Center" DropDownOpened="cBPortList_DropDownOpened"/>
<Label Content="Port" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
<Button x:Name="but_Connect" Content="Verbinden" Click="but_Connect_Click" VerticalAlignment="Stretch" Padding="5,0"/>
</StackPanel>
<Button x:Name="But_StatTask_Timer" Grid.Row="1" Grid.Column="1" Content="Rum Cola (ms)" ToolTip="t;2500;35000" Click="But_StatTask_Timer_Click"/>
<Button x:Name="But_StartTask_Weight" Grid.Row="2" Grid.Column="1" Content="Rum Cola (g)" ToolTip="1. g;1;20 - 2. g;2;280" Click="But_StartTask_Weight_Click"/>
<Button x:Name="But_Tara" Grid.Row="1" Grid.Column="2" Content="Tara" Click="But_Tara_Click"/>
<TextBox x:Name="Tb_Result" Grid.Row="1" Grid.RowSpan="2" Grid.Column="0" Text="{Binding Result}" />
<!--<DataGrid x:Name="dataGrid" Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Liste, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="True" CanUserReorderColumns="True" CanUserResizeColumns="True" CanUserResizeRows="True" CanUserSortColumns="True" RowBackground="White" AlternatingRowBackground="GhostWhite">
<DataGrid.Columns>
<DataGridTextColumn Header="Number" Binding="{Binding Number}" Width="SizeToHeader" IsReadOnly="True"/>
<DataGridTextColumn Header="Text" Binding="{Binding Text}" Width="*" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
<ProgressBar x:Name="progressDecoding" Grid.Row="2" Grid.ColumnSpan="2" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Minimum="{Binding ProgressMin, Mode=OneWay, UpdateSourceTrigger=PropertyChanged }" Maximum="{Binding ProgressMax, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="{Binding ProgressValue, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid>-->
<ProgressBar x:Name="progressDecoding" Grid.Row="3" Grid.ColumnSpan="2" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Minimum="{Binding ProgressMin, Mode=OneWay, UpdateSourceTrigger=PropertyChanged }" Maximum="{Binding ProgressMax, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="{Binding ProgressValue, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
......@@ -14,11 +16,13 @@ namespace Cocktailmaker
public partial class MainWindow : Window
{
private readonly MainWindowViewModel vm = new MainWindowViewModel();
private SerialComWrapper serComWrapper;
public MainWindow()
{
InitializeComponent();
Tb_Result.DataContext = vm;
dataGrid.DataContext = vm;
//dataGrid.DataContext = vm;
progressDecoding.DataContext = vm;
}
......@@ -80,6 +84,107 @@ namespace Cocktailmaker
}
return liste;
}
private void But_StatTask_Timer_Click(object sender, RoutedEventArgs e)
{
if (serComWrapper?.IsConnected == true)
{
serComWrapper.Send(Encoding.ASCII.GetBytes("t;1000;2000;3000;4000\n"));
}
}
private void But_StartTask_Weight_Click(object sender, RoutedEventArgs e)
{
if (serComWrapper?.IsConnected == true)
{
serComWrapper.Send(Encoding.ASCII.GetBytes("g;20;40;100;100\n"));
}
}
private void but_Connect_Click(object sender, RoutedEventArgs e)
{
if (serComWrapper?.IsConnected == true)
{
serComWrapper.Close();
but_Connect.Content = "Open";
}
else
{
if (cBPortList.SelectedItem != null)
{
serComWrapper = new SerialComWrapper(cBPortList.SelectedItem.ToString(), 115200);
if (!serComWrapper.IsConnected)
serComWrapper.Open();
if (serComWrapper.IsConnected)
{
serComWrapper.OnReceive -= SerComWrapper_OnReceive;
serComWrapper.OnConnectionStatusChanged -= SerComWrapper_OnConnectionStatusChanged;
serComWrapper.OnReceive += SerComWrapper_OnReceive;
serComWrapper.OnConnectionStatusChanged += SerComWrapper_OnConnectionStatusChanged;
but_Connect.Content = "Close";
}
Console.WriteLine($"Port: {serComWrapper.ComPort} is {(serComWrapper.IsConnected ? "Open" : "Closed")}");
}
else
{
MessageBox.Show("Bitte erst einen Port auswählen!");
}
}
}
private void SerComWrapper_OnConnectionStatusChanged(object sender, SerialComWrapperConnectionStatusChangedEventArgs e) => Console.WriteLine($"New connection status: {e.State} : {e.Text}");
//private void SerComWrapper_OnReceive(object sender, SerialComWrapperOnReceiveEventArgs e) => Console.Write($"Recv >>> {ByteArrayToHex(e.Data)} : {Encoding.ASCII.GetString(e.Data)}");
private void SerComWrapper_OnReceive(object sender, SerialComWrapperOnReceiveEventArgs e) => Console.Write($"{Encoding.ASCII.GetString(e.Data)}");
public static string ByteArrayToHex(byte[] data, bool addSpacer = true)
{
var result = "";
var isFrist = true;
foreach (var b in data)
{
if (!isFrist && addSpacer)
{
isFrist = true;
result += " ";
}
result += $"{b:X2}";
}
return result;
}
private void cBPortList_DropDownOpened(object sender, EventArgs e)
{
var ports = SerialPort.GetPortNames();
Console.WriteLine("The following serial ports were found:");
// Display each port name to the console.
foreach (var port in ports)
{
cBPortList.Items.Add(port);
}
}
private void closeSerCom() => serComWrapper?.Close();
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) => closeSerCom();
private void But_Tara_Click(object sender, RoutedEventArgs e)
{
if (serComWrapper?.IsConnected == true)
{
serComWrapper.Send(Encoding.ASCII.GetBytes("tara\n"));
}
}
}
}
......@@ -73,12 +73,12 @@ namespace Cocktailmaker
/// <summary>
/// Event is called when the serial com receives data.
/// </summary>
private event SerialComWrapperOnReceiveEventHandler OnReceive;
public event SerialComWrapperOnReceiveEventHandler OnReceive;
/// <summary>
/// Event is called when the connection status of the physical layer changes.
/// </summary>
private event SerialComWrapperOnConnectionStatusChangedEventHandler OnConnectionStatusChanged;
public event SerialComWrapperOnConnectionStatusChangedEventHandler OnConnectionStatusChanged;
/// <summary>
/// COM Port of the serial communication.
/// </summary>
......
File added
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>
\ No newline at end of file
File added
File added
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
#pragma checksum "..\..\App.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "D496E74774D6DFBB024BF9391C476EB317E853F35011D8EC2034F16ED6FA76F6"
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
using Cocktailmaker;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;
namespace Cocktailmaker {
/// <summary>
/// App
/// </summary>
public partial class App : System.Windows.Application {
/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public void InitializeComponent() {
#line 5 "..\..\App.xaml"
this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
#line default
#line hidden
}
/// <summary>
/// Application Entry Point.
/// </summary>
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public static void Main() {
Cocktailmaker.App app = new Cocktailmaker.App();
app.InitializeComponent();
app.Run();
}
}
}
#pragma checksum "..\..\App.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "D496E74774D6DFBB024BF9391C476EB317E853F35011D8EC2034F16ED6FA76F6"
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
using Cocktailmaker;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;
namespace Cocktailmaker {
/// <summary>
/// App
/// </summary>
public partial class App : System.Windows.Application {
/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public void InitializeComponent() {
#line 5 "..\..\App.xaml"
this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative);
#line default
#line hidden
}
/// <summary>
/// Application Entry Point.
/// </summary>
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public static void Main() {
Cocktailmaker.App app = new Cocktailmaker.App();
app.InitializeComponent();
app.Run();
}
}
}
File added
File added
1d5470ce73d8c441342c6f1c37f77e063ac5e665
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\bin\Debug\Cocktailmaker.exe.config
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\bin\Debug\Cocktailmaker.exe
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\bin\Debug\Cocktailmaker.pdb
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\MainWindow.g.cs
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\App.g.cs
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker_MarkupCompile.cache
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker_MarkupCompile.lref
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\MainWindow.baml
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker.g.resources
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker.Properties.Resources.resources
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker.csproj.GenerateResource.cache
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker.csproj.CoreCompileInputs.cache
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker.exe
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker.pdb
C:\Users\aust_\GitProjects\cocktailmaschine\UI\Cocktailmaker\obj\Debug\Cocktailmaker.csproj.AssemblyReference.cache
File added
File added
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment