コード例 #1
0
ファイル: Peripherals.cs プロジェクト: vishalishere/AutoStill
        public static ArduinoDriver.ArduinoDriver InitializeArduinoDriver()
        {
            if (driver == null)
            {
                driver = (ArduinoCOMPort() == null) ? null : new ArduinoDriver.ArduinoDriver(ArduinoModel.Mega2560, ArduinoCOMPort(), true);
            }
            if (driver != null)
            {
                foreach (string Key in ConfigurationManager.AppSettings.AllKeys)
                {
                    string Value = ConfigurationManager.AppSettings.Get(Key);

                    //Use regex to search teh appconfig values for the pin numbers and pin types
                    if (Regex.IsMatch(Value, @"Type=(\D+)InputPin") == true)
                    {
                        DriverFunctions.SetInput(driver, Convert.ToByte(Regex.Match(Value, @"(?<=Pin=)\d+").Value));
                    }
                    if (Regex.IsMatch(Value, @"Type=(\D+)OutputPin") == true)
                    {
                        DriverFunctions.SetOutput(driver, Convert.ToByte(Regex.Match(Value, @"(?<=Pin=)\d+").Value));
                        if (ConfigurationManager.AppSettings.Get("InvertPinPolarity") == "True" && Regex.IsMatch(Value, @"Type=RelayOutputPin") == true)
                        {
                            driver.Send(new DigitalWriteRequest(Convert.ToByte(Regex.Match(Value, @"(?<=Pin=)\d+").Value), DigitalValue.High));
                        }
                    }
                }
            }

            //Send the initialized driver object (or null) back to whatever called this sub
            return(driver);
        }
コード例 #2
0
        public static BackgroundWorker InitializePressureWorker(ArduinoDriver.ArduinoDriver driver, Dispatcher MainDispatcher)
        {
            PressureWorker = new BackgroundWorker();
            PressureWorker.WorkerSupportsCancellation = true;
            PressureWorker.DoWork += new DoWorkEventHandler((state, args) =>
            {
                //Make sure the pump is off
                MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.VacuumPump); }));
                Main.VacuumPumpOn = false;
                do
                {
                    try
                    {
                        if (Main.Run != true || PressureWorker.CancellationPending == true)
                        {
                            break;
                        }

                        System.Threading.Thread.Sleep(1000);
                        if (Convert.ToDouble(Main.Pressure) > SystemProperties.TargetPressure && Main.VacuumPumpOn == false)
                        {
                            //Turn the vacuum pump on
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOn(driver, SystemProperties.VacuumPump); }));
                            Main.VacuumPumpOn = true;

                            //Refresh the pressure has changed every second -- Note that the pressure is set in the still monitor background worker
                            do
                            {
                                System.Threading.Thread.Sleep(1000);
                            }while (Convert.ToDouble(Main.Pressure) > (SystemProperties.TargetPressure - SystemProperties.TgtPresHysteresisBuffer) && PressureWorker.CancellationPending == false);

                            //Once the pressure has reached its target turn the pump off
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.VacuumPump); }));
                            Main.VacuumPumpOn = false;
                        }
                    }
                    catch { MainDispatcher.Invoke(new Action(() => { driver = Periphrials.InitializeArduinoDriver(); })); }
                } while (true);
            });
            return(PressureWorker);
        }
コード例 #3
0
        private static BackgroundWorker FanController2;  //Turns the fan set for the condensor on, off, up and down depending on target temperature and distillation speed

        //Background worker to monitor all sensor valuess and switch states on the still and keep global variables and the UI updated
        //The idea here is to imtermittently check all variables and write to a local variable in memory to minimize commands sent to the arduino
        //This is also convienent as it minimizes the amount of long of code required to message the arduino in the control loop
        public static BackgroundWorker InitializeSystemMonitor(ArduinoDriver.ArduinoDriver driver, Dispatcher MainDispatcher)
        {
            SystemMonitor = new BackgroundWorker();
            SystemMonitor.WorkerSupportsCancellation = true;
            SystemMonitor.DoWork += new DoWorkEventHandler((state, args) =>

            {
                do
                {
                    if (Main.Run != true || driver == null) //The periphrials class returns null if no arduino is found on any of the com ports
                    {
                        break;
                    }
                    System.Threading.Thread.Sleep(1000);
                    //Check Temperature
                    bool success = false;
                    while (success == false)
                    {
                        try
                        {
                            MainDispatcher.Invoke(new Action(() =>
                            {
                                Main.ColumnTemp      = DriverFunctions.GetTemperature(driver, SystemProperties.SensorColumnTemp).ToString();
                                Main.RefluxTemp      = DriverFunctions.GetTemperature(driver, SystemProperties.SensorCoolantTemp1);
                                Main.CondensorTemp   = DriverFunctions.GetTemperature(driver, SystemProperties.SensorCoolantTemp2);
                                Main.ElementAmperage = DriverFunctions.GetAmperage(driver, SystemProperties.SensorColumnTemp);
                            }));
                            success = true;
                        }
                        catch
                        {
                            MainDispatcher.Invoke(new Action(() => {
                                driver.Dispose();
                                driver = Periphrials.InitializeArduinoDriver();
                            }));
                        }
                    }

                    //Check the low level switch -- a value of low means the lower still switch is open
                    MainDispatcher.Invoke(new Action(() => {
                        if (driver.Send(new DigitalReadRequest(SystemProperties.StillLowSwitch)).PinValue == DigitalValue.Low)
                        {
                            Main.StillEmpty = true;
                        }
                        else
                        {
                            Main.StillEmpty = false;
                        }
                    }));

                    //Check the high level switch -- a value of high means the upper still switch is closed
                    MainDispatcher.Invoke(new Action(() => {
                        if (driver.Send(new DigitalReadRequest(SystemProperties.StillHighSwitch)).PinValue == DigitalValue.High)
                        {
                            Main.StillFull = true;
                        }
                        else
                        {
                            Main.StillFull = false;
                        }
                    }));

                    //Check the recieving vessel low level switch -- a value of high means the upper rv switch is closed
                    MainDispatcher.Invoke(new Action(() => {
                        if (driver.Send(new DigitalReadRequest(SystemProperties.RVEmptySwitch)).PinValue == DigitalValue.High)
                        {
                            Main.RVEmpty = true;
                        }
                        else
                        {
                            Main.RVEmpty = false;
                        }
                    }));

                    //Check the recieving vessel high level switch -- a value of high means the upper rv switch is closed
                    MainDispatcher.Invoke(new Action(() => {
                        if (driver.Send(new DigitalReadRequest(SystemProperties.RVFullSwitch)).PinValue == DigitalValue.Low)
                        {
                            Main.RVFull = true;
                        }
                        else
                        {
                            Main.RVFull = false;
                        }
                    }));

                    //Check the pressure (1024 is the resolution of the ADC on the arduino, 45.1 is the approximate pressure range in PSI that the sensor is capable of reading, the -15 makes sure that STP = 0 PSI/kPa)
                    MainDispatcher.Invoke(new Action(() => { Main.Pressure = Math.Round((((Convert.ToDouble(driver.Send(new AnalogReadRequest(SystemProperties.SensorPressure)).PinValue.ToString()) / 1024) * 45.1) - 16.5) * ((SystemProperties.Units == "Metric") ? 6.895 : 1), 2).ToString(); }));

                    if (Main.Phase == -1)
                    {
                        Main.Phase = 0;
                    }
                } while (true);
            });
            return(SystemMonitor);
        }
コード例 #4
0
ファイル: Main.cs プロジェクト: vishalishere/AutoStill
        public void StillLoop()
        {
            //Dispatcher to accept commands from the various background workers
            Dispatcher MainDispatcher = Dispatcher.CurrentDispatcher;

            //Instanciate the periphrial class and start up the arduino
            ArduinoDriver.ArduinoDriver driver = Periphrials.InitializeArduinoDriver();

            if (driver == null)
            {
                lblStatus.Text    = "No controller found";
                btnRescan.Visible = true;
            }
            else
            {
                btnRescan.Visible = false;
                lblStatus.Text    = "Starting";
            }

            //Declare the background workers
            SystemMonitor     = BackGroundWorkers.InitializeSystemMonitor(driver, MainDispatcher);
            PressureRegulator = BackGroundWorkers.InitializePressureWorker(driver, MainDispatcher);
            //StillController;
            FanController1 = BackGroundWorkers.InitializeFanController1(driver, MainDispatcher);
            FanController2 = BackGroundWorkers.InitializeFanController2(driver, MainDispatcher);

            //Datatable for statistics and calculating when to turn the element off
            DataTable StillStats = Statistics.InitializeTable();

            chartRun.DataSource = StillStats;


            StillController = new BackgroundWorker();
            StillController.WorkerSupportsCancellation = true;
            StillController.DoWork += new DoWorkEventHandler((state, args) =>

            {
                do
                {
                    try {
                        DateTime RunStart = DateTime.Now;
                        StillStats.Clear();
                        //Run unless a stop condition is hit
                        if (Run != true || driver == null)
                        {
                            break;
                        }

                        while (Phase == -1)//Wait for initial values to be collected before starting
                        {
                            System.Threading.Thread.Sleep(250);
                        }

                        //Check to see if the still is full, if not fill it. This ensures there is no product wasted if the previous batch was stopped half way
                        if (StillFull == false && Phase < 2)
                        {
                            {
                                //Open the inlet valve and turn the inlet pump on
                                MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOn(driver, SystemProperties.StillFillValve); }));
                                StillValveOpen = true;
                                //Wait 5 seconds for the valve to open
                                System.Threading.Thread.Sleep(3000);
                                MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOn(driver, SystemProperties.StillFluidPump); }));
                                MainDispatcher.Invoke(new Action(() => { lblStatus.Text = "Filling Still"; }));
                                StillPumpOn = true;


                                //Check once a second to see if the still is full now -- note that StillFull is updated by the monitor worker
                                while (StillFull == false)
                                {
                                    System.Threading.Thread.Sleep(1000);
                                }
                                //Close the valve and turn off the pump
                                MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.StillFillValve); }));
                                StillValveOpen = false;
                                MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.StillFluidPump); }));
                                MainDispatcher.Invoke(new Action(() => { lblStatus.Text = "Filling Complete"; }));

                                StillPumpOn = false;

                                //If this line is reached that means the still has liquid in it and is ready to start distilling
                                Phase = 1;
                            }
                        }

                        //Make sure the first loop was passed and the still didnt magically empty itself
                        if (Phase < 2 && StillFull == true)
                        {
                            //Turn on the element and vacuum pump
                            DriverFunctions.TurnOn(driver, SystemProperties.StillElement);
                            ElementOn = true;
                            PressureRegulator.RunWorkerAsync();
                            MainDispatcher.Invoke(new Action(() => { lblStatus.Text = "Heating"; }));



                            //Set up variables for calculating when to turn off the element
                            int CurrentTemp     = Convert.ToInt16(ColumnTemp);
                            int CurrentDelta    = 0;
                            int Counter         = 0;
                            PlateauTemp         = 0;
                            string StartTempRaw = null;
                            while (StartTempRaw == null)
                            {
                                try { StartTempRaw = driver.Send(new AnalogReadRequest(SystemProperties.SensorColumnTemp)).PinValue.ToString(); } catch { }
                            }
                            double StartTemp    = Convert.ToInt64((((Convert.ToDouble(StartTempRaw) * (5.0 / 1023.0)) - 1.25) / 0.005));
                            double Temp1        = 0.0;
                            double Temp2        = 0.0;
                            double AverageDelta = 0.0;
                            double TotalDelta   = 0.0;

                            DataRow row;

                            row                         = StillStats.NewRow();
                            row["Time"]                 = DateTime.Now;
                            row["Temperature"]          = CurrentTemp;
                            row["TemperatureDelta"]     = 0;
                            row["Pressure"]             = Convert.ToDecimal(Pressure);
                            row["Phase"]                = Phase;
                            row["Amperage"]             = ElementAmperage;
                            row["RefluxTemperature"]    = RefluxTemp;
                            row["CondensorTemperature"] = CondensorTemp;
                            StillStats.Rows.Add(row);

                            //Get the last written row for collecting temperature rise statistics
                            DataRow LastRow = StillStats.Rows[0];

                            //Get two rows from two points in time 2.5 minutes apart so an average temperature change can be obtained from the given time span
                            DataRow Delta1;
                            DataRow Delta2;

                            //Start both fan controllers to maintain the temperature of the coolant in Reflux column and the Condensor
                            //Note that these are started here because they are auto-regulating and will shut off by themselves when not necessary
                            //FanController1.RunWorkerAsync();
                            //FanController2.RunWorkerAsync();

                            //Keep the element on and keep collecting data every 10 seconds until the first plateau is reached then go to the next loop
                            //note thate the total delta is there incase it takes longer than 10 minutes to start seeing a temperature rise at the sensor
                            while ((StillEmpty == false && AverageDelta >= 0.02) || TotalDelta < 0.25)
                            {
                                //Change this back to 10 seconds
                                System.Threading.Thread.Sleep(250);
                                //Once the element has been on for 10 minutes start checking for the plateau
                                if (Counter < 60)
                                {
                                    Counter = Counter + 1;
                                }
                                else
                                {
                                    Delta1       = StillStats.Rows[StillStats.Rows.Count - 19];
                                    Delta2       = StillStats.Rows[StillStats.Rows.Count - 1];
                                    Temp1        = Delta1.Field <Int32>("Temperature");
                                    Temp2        = Delta2.Field <Int32>("Temperature");
                                    AverageDelta = Temp2 != 0 ? ((Temp2 - Temp1) / Temp2) : 0;
                                    if (Temp2 > Temp1)
                                    {
                                        TotalDelta = Temp2 != 0 ? ((Temp2 - StartTemp) / Temp2) : 0;
                                    }
                                }

                                CurrentTemp                 = Convert.ToInt32(ColumnTemp);
                                CurrentDelta                = CurrentTemp - LastRow.Field <Int32>("Temperature");
                                row                         = StillStats.NewRow();
                                row["Time"]                 = DateTime.Now;
                                row["Temperature"]          = CurrentTemp;
                                row["TemperatureDelta"]     = CurrentDelta;
                                row["Pressure"]             = Convert.ToDecimal(Pressure);
                                row["Phase"]                = Phase;
                                row["Amperage"]             = ElementAmperage;
                                row["RefluxTemperature"]    = RefluxTemp;
                                row["CondensorTemperature"] = CondensorTemp;
                                StillStats.Rows.Add(row);
                                LastRow = StillStats.Rows[StillStats.Rows.Count - 1];
                                MainDispatcher.Invoke(new Action(() => { chartRun.DataBind(); }));
                            }

                            //Prep variables related to the distillation phase and start the fan controller for the condensor
                            Phase        = 2;
                            AverageDelta = 0;
                            TotalDelta   = 0;
                            PlateauTemp  = LastRow.Field <Int32>("Temperature");
                            MainDispatcher.Invoke(new Action(() => { lblStatus.Text = "Distilling"; }));


                            //Once the first plateau is reached allowing for a 4 degree change at the most
                            //or end the batch if the saftey limit switch is triggered also reset the Delta counters so the next step is not skipped
                            while (StillEmpty == false && (Temp2 - PlateauTemp) < 5 && RVFull == false)
                            {
                                Delta1       = StillStats.Rows[StillStats.Rows.Count - 19];
                                Delta2       = StillStats.Rows[StillStats.Rows.Count - 1];
                                Temp1        = Delta1.Field <Int32>("Temperature");
                                Temp2        = Delta2.Field <Int32>("Temperature");
                                AverageDelta = Math.Abs(((Temp2 - Temp1) / Temp2));
                                System.Threading.Thread.Sleep(250); //Change this back to 10 seconds
                                CurrentTemp                 = Convert.ToInt32(ColumnTemp);
                                CurrentDelta                = CurrentTemp - LastRow.Field <Int32>("Temperature");
                                row                         = StillStats.NewRow();
                                row["Time"]                 = DateTime.Now;
                                row["Temperature"]          = CurrentTemp;
                                row["TemperatureDelta"]     = CurrentDelta;
                                row["Pressure"]             = Convert.ToDecimal(Pressure);
                                row["Phase"]                = Phase;
                                row["Amperage"]             = ElementAmperage;
                                row["RefluxTemperature"]    = RefluxTemp;
                                row["CondensorTemperature"] = CondensorTemp;
                                StillStats.Rows.Add(row);
                                LastRow = StillStats.Rows[StillStats.Rows.Count - 1];
                                MainDispatcher.Invoke(new Action(() => { chartRun.DataBind(); }));
                            }

                            //Batch complete!
                            MainDispatcher.Invoke(new Action(() => { lblStatus.Text = "Batch Complete, Saving Run Data"; }));
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.StillElement); }));
                            ElementOn = false;
                            Phase     = 3;
                        }
                        //If the run completed without issue then calculate the header info and write the data to a local sqldb
                        //Note that this must be done sequentially as the records must relate to a header record
                        //Once the table is succesfully written set the phase back to 0 and start another run
                        if (Phase == 3)
                        {
                            Statistics.CreateHeader(RunStart, DateTime.Now, true, SystemProperties.Units);
                            Statistics.SaveRun(StillStats, RunStart);

                            //Turn off the vacuum pump and fan controllers synchronously with the main thread
                            PressureRegulator.CancelAsync();
                            //FanController1.CancelAsync();
                            //FanController2.CancelAsync();
                            while (PressureRegulator.CancellationPending == true || FanController1.CancellationPending == true || FanController2.CancellationPending == true)
                            {
                                System.Threading.Thread.Sleep(100);
                            }


                            //Fill the system with air so it is at a neutral pressure before pumping any fluids -- note that the system will pull air from the drain valve
                            //since it eventually vents somewhere that is at atmospheric pressure
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOn(driver, SystemProperties.StillDrainValve); }));
                            MainDispatcher.Invoke(new Action(() => { lblStatus.Text = "Draining Still"; }));
                            while (StillEmpty == false || Convert.ToDouble(Pressure) <= -0.2)
                            {
                                System.Threading.Thread.Sleep(1500);
                            }
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.StillDrainValve); }));
                            System.Threading.Thread.Sleep(3000);


                            //Make sure that the switches are working then pump the Recieving vessels contents into a storage tank so the next run can begin
                            MainDispatcher.Invoke(new Action(() => { lblStatus.Text = "Draining Distillate"; }));
                            MainDispatcher.Invoke(new Action(() => { RVEmpty = (driver.Send(new DigitalReadRequest(SystemProperties.RVEmptySwitch)).PinValue == DigitalValue.Low) ? true : false; }));
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOn(driver, SystemProperties.RVDrainValve); }));
                            System.Threading.Thread.Sleep(3000); //3 second delay so the valve has time to open
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOn(driver, SystemProperties.RVFluidPump); }));
                            while (RVEmpty == false)
                            {
                                //MainDispatcher.Invoke(new Action(() => { RVEmpty = (driver.Send(new DigitalReadRequest(SystemProperties.RVEmptySwitch)).PinValue == DigitalValue.Low) ? true : false; }));
                                System.Threading.Thread.Sleep(1500);
                            }
                            //Turn off the pump and shut the valves and give them 3 seconds to close
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.RVFluidPump); }));
                            MainDispatcher.Invoke(new Action(() => { DriverFunctions.RelayOff(driver, SystemProperties.RVDrainValve); }));

                            Phase = 0;
                        }
                    }
                    //The arduino driver reference has a tendency to randomly throw null reference exceptions, for now I will handle it by just restarting the arduino
                    //the code is designed to pick up where it left off if it errors since the phase is still in memory
                    catch (NullReferenceException)
                    {
                        MainDispatcher.Invoke(new Action(() => { driver = Periphrials.InitializeArduinoDriver(); }));
                    }
                } while (true);
            });

            UIUpdater = new BackgroundWorker();
            UIUpdater.WorkerSupportsCancellation = true;
            UIUpdater.DoWork += new DoWorkEventHandler((state, args) =>
            {
                do
                {
                    System.Threading.Thread.Sleep(1000);
                    MainDispatcher.Invoke(new Action(() => { lblPressure.Text = Main.Pressure + ((SystemProperties.Units == "Metric") ? "kPa" : "PSI"); }));
                    MainDispatcher.Invoke(new Action(() => { lblTemp1.Text = Main.ColumnTemp + ((SystemProperties.Units == "Metric") ? "°C" : "°F"); }));
                }while (true);
            });

            //Start the workers and pause for 2 seconds to allow for initial values to be collected
            SystemMonitor.RunWorkerAsync();
            System.Threading.Thread.Sleep(2000);
            StillController.RunWorkerAsync();
            UIUpdater.RunWorkerAsync();
        }