Your SlideShare is downloading. ×
Form1.Cs
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Form1.Cs

143
views

Published on

Control and monitoring program for automated HLM

Control and monitoring program for automated HLM


0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
143
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. // Basic autopilot for heart-lung machine, monitor reservoir level and controlroller pump// used with a softshell reservoir and Omega load cell and meter, Stockert CAPSroller pump// and Omega digital-to-analog converter// Kenneth Wilkerson 2008 Midwestern Universityusing System;using System.Globalization;using System.IO;using System.Collections;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Runtime.InteropServices;using SpeechLib;using System.Media;namespace hlmautopilot{ public partial class Form1 : Form { public Form1() { InitializeComponent(); serialPort1.Open(); //setup request to load cell meter weightreq[0] = *; weightreq[1] = X; weightreq[2] = 0; weightreq[3] = 1; weightreq[4] = r; weightreq[5] = 0; //setup initial values minreslevel = (double)minreslvlctl.Value; lowreslevel = (double)lowreslvlctl.Value; maxflowrate = (double)flowctl.Value; maxrpm = (int)((maxflowrate * 1000) / strokevolume); pumpon = false; curreslevel = 0; waterbtn.Checked = true; density = waterdensity; recordon = false; nfi = new CultureInfo("en-US", false).NumberFormat; nfi.NumberDecimalDigits = 1; greenuparrow = new Bitmap(@"greenuparrow.bmp", false); reddownarrow = new Bitmap(@"reddownarrow.bmp", false); lvlchangerate.Minimum = 0; lvlchangerate.Maximum = (int)(maxflowrate * 1000); lvlchangerate.Value = 0; minpercentflow = (int)pctflowctl.Value; //Create voice object voice = new SpVoice(); } //Start monitoring reservoir event private void monstart_click(object sender, EventArgs e) { monstopbtn.Enabled = true;
  • 2. monstartbtn.Enabled = false; timer1.Enabled = true; monitortime = 0.0; reslevels = new Queue(); } //Stop monitoring reservoir event private void monstop_click(object sender, EventArgs e) { monstartbtn.Enabled = true; monstopbtn.Enabled = false; timer1.Enabled = false; curreslvl.Text = ""; } //Start roller pump event private void pumpstart_click(object sender, EventArgs e) { int rc = 0; ushort numcards; //rc = omega.pioda.PIODA_DriverInit(); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("DriverInit failed"); } unsafe { // rc = omega.pioda.PIODA_SearchCard(&numcards,omega.pioda.PIO_DA); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("SearchCard failed"); } } pumpstartbtn.Enabled = false; pumpstopbtn.Enabled = true; pumpon = true; pumpstate = pumpstates.FullFlow; oldpumpstate = pumpstates.FullFlow; } //Stop roller pump event private void pumpstop_click(object sender, EventArgs e) { omega.pioda.PIODA_Voltage(0, 0, 0.0F); omega.pioda.PIODA_Voltage(0, 1, 0.0F); omega.pioda.PIODA_Voltage(0, 2, 0.0F); omega.pioda.PIODA_Voltage(0, 3, 0.0F); omega.pioda.PIODA_DriverClose(); pumpstartbtn.Enabled = true; pumpstopbtn.Enabled = false; pumpon = false; } //Process timer event private void timer_tick(object sender, EventArgs e) { char[] buf = new char[15]; int nread; char chrread; double pctflow; int changerate;
  • 3. //Increment times elapsedtime += timer1.Interval / 1000.0; monitortime += timer1.Interval / 1000.0; //Send request to load cell meter and process response serialPort1.Write(weightreq, 0, 5); nread = 0; chrread = 0; while ((chrread != n) && (nread < 15)) { chrread = (char)serialPort1.ReadChar(); buf[nread] = chrread; nread++; } weight = parseweightrsp(buf); curreslevel = (weight * 1000) / density; reslevels.Enqueue(curreslevel); curreslvl.Text = curreslevel.ToString("F"); //Keep five seconds of weight responses if (monitortime < 5.0) { } else if (monitortime >= 5.0) { previousreslevel = (double)reslevels.Dequeue(); if (curreslevel - previousreslevel > 25.0) {//res level rising leveltrend.Image = (Image)greenuparrow; changerate = (int)((curreslevel - previousreslevel) / 5) *60; if (changerate > (int)(maxflowrate * 1000)) { changerate = (int)(maxflowrate * 1000); } lvlchangerate.Value = changerate; } else if (previousreslevel - curreslevel > 25.0) {//res level falling leveltrend.Image = (Image)reddownarrow; changerate = (int)((previousreslevel - curreslevel) / 5) *60; if (changerate > (int)(maxflowrate * 1000)) { changerate = (int)(maxflowrate * 1000); } lvlchangerate.Value = changerate; } else {//res level steady leveltrend.Image = null; lvlchangerate.Value = 0; } } if (pumpon == true) { oldpumpstate = pumpstate;// save current pump state pctflow = manageflow(); //Set status colors based on amount of flow from pump if (pctflow == 100.0)// full flow {
  • 4. pumpstate = pumpstates.FullFlow; curreslvl.BackColor = Color.LightGreen; curflow.BackColor = Color.LightGreen; } else if (pctflow == 0.0)// no flow { pumpstate = pumpstates.Stopped; curreslvl.BackColor = Color.Red; curflow.BackColor = Color.Red; } else //partial flow { pumpstate = pumpstates.PartialFlow; curreslvl.BackColor = Color.Yellow; curflow.BackColor = Color.Yellow; } setrpm(maxrpm, pctflow);// set pumps rpm for this amount of flow curflowrate = maxflowrate * (pctflow / 100.0); curflow.Text = Convert.ToString(curflowrate); // If state of pump is changing, make announcement if (oldpumpstate == pumpstates.FullFlow) { if (pumpstate == pumpstates.PartialFlow) { SystemSounds.Exclamation.Play(); voice.Speak("warning reservoir low, slowing pump",SpFlags); } else if (pumpstate == pumpstates.Stopped) { SystemSounds.Exclamation.Play(); voice.Speak("warning, reservoir critical, stoppingpump", SpFlags); } } else if (oldpumpstate == pumpstates.PartialFlow) { if (pumpstate == pumpstates.FullFlow) { SystemSounds.Exclamation.Play(); voice.Speak("resuming full flow", SpFlags); } else if (pumpstate == pumpstates.Stopped) { SystemSounds.Exclamation.Play(); voice.Speak("warning, reservoir critical, stoppingpump", SpFlags); } } else if (oldpumpstate == pumpstates.Stopped) { if (pumpstate == pumpstates.FullFlow) { SystemSounds.Exclamation.Play(); voice.Speak("resuming full flow", SpFlags); } else if (pumpstate == pumpstates.PartialFlow) { SystemSounds.Exclamation.Play(); voice.Speak("restarting pump, partial flow", SpFlags); } }
  • 5. if (recordon)// record res level and flow rate { logfile.Write(elapsedtime); logfile.Write(","); logfile.Write(curreslvl.Text); logfile.Write(","); logfile.WriteLine(curflow.Text); } } else // pump off { curreslvl.BackColor = Color.White; curflow.BackColor = Color.White; } } // Parse response from load cell meter private double parseweightrsp(char[] rsp) { char[] buf = new char[6]; double weight; int i; String swght; for (i = 0; i < 5; i++) { buf[i] = rsp[i + 3]; } buf[5] = 0; swght = new String(buf); weight = Double.Parse(swght); return weight; } //determine proper pump flow rate based on max flow rate, current,minimum and low // reservoir levels private double manageflow() { double pctflow = 0.0; if (curreslevel > lowreslevel)// current above low { pctflow = 100.0; } else if ((curreslevel <= lowreslevel) && (curreslevel >minreslevel)) {// current between low and minimum switch (pumpstate) { case pumpstates.FullFlow://pump slowing case pumpstates.PartialFlow: pctflow = minpercentflow + (int)((100.0 -minpercentflow) * ((curreslevel - minreslevel) / (lowreslevel -minreslevel))); break; case pumpstates.Stopped:// resuming from stopped if (curreslevel > lowreslevel) {
  • 6. pctflow = 100.0; } else if (curreslevel >= minreslevel + 75) { pctflow = minpercentflow + (int)((100.0 -minpercentflow) * ((curreslevel - minreslevel) / (lowreslevel -minreslevel))); } else { pctflow = 0.0; } break; } } else // current level at or below minimum level { pctflow = 0.0; } return pctflow; } // change in minimum res level event private void minres_click(object sender, EventArgs e) { minreslevel = (double)minreslvlctl.Value; } //change in low res level event private void lowres_click(object sender, EventArgs e) { lowreslevel = (double)lowreslvlctl.Value; } //change in maximum flow event private void maxflow_click(object sender, EventArgs e) { maxflowrate = (double)flowctl.Value; maxrpm = (int)((maxflowrate * 1000) / strokevolume); lvlchangerate.Maximum = (int)(maxflowrate * 1000); } //Stop recording evengt private void rcrdstop_click(object sender, EventArgs e) { logfile.Close(); recordon = false; recordstartbtn.Enabled = true; recordstopbtn.Enabled = false; } //Start recording event private void rcrdstart_click(object sender, EventArgs e) { SaveFileDialog saveFileDialog1 = new SaveFileDialog(); saveFileDialog1.Title = "Save log data"; saveFileDialog1.Filter = "Text files (*.txt)|*.txt"; saveFileDialog1.ShowDialog(); if (saveFileDialog1.FileName != "") { logdata = saveFileDialog1.OpenFile();
  • 7. logfile = new StreamWriter(logdata); } recordon = true; elapsedtime = 0.0; recordstopbtn.Enabled = true; recordstartbtn.Enabled = false; logfile.WriteLine("Max flow rate,Min percent flow,Min res level,lowres level"); logfile.Write(flowctl.Value); logfile.Write(","); logfile.Write(pctflowctl.Value); logfile.Write(","); logfile.Write(minreslvlctl.Value); logfile.Write(","); logfile.WriteLine(lowreslvlctl.Value); logfile.WriteLine("Elapsed Time, Volume, Flowrate"); } //Set fluid to water event private void waterbtn_click(object sender, EventArgs e) { density = waterdensity; } //Set fluid to blood event private void bloodbtn_click(object sender, EventArgs e) { density = blooddensity; } // set minimum amount of flow relative to max flow before // stop pump private void minpctflow_click(object sender, EventArgs e) { minpercentflow = (int)pctflowctl.Value; } //set pump rpm based on max rpm and percent flow private int setrpm(int maxrpm, double pctflow) { int rc = 0; float currpm; if ((maxrpm >= 0) && (maxrpm <= 175)) { if (pctflow > 0.0) { currpm = (float)(maxrpm * pctflow / 100.0); // rc = omega.pioda.PIODA_CalVoltage(0, 0, channel0_base +0); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 0 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 1, channel1_base +(channel1_vrpm * currpm)); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 1 failed"); }
  • 8. // rc = omega.pioda.PIODA_CalVoltage(0, 2, channel2_base +(channel2_vrpm * currpm)); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 2 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 3, channel3_base +(channel3_vrpm * currpm)); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 3 failed"); } } else // Stop pump { // rc = omega.pioda.PIODA_CalVoltage(0, 0, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 0 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 1, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 1 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 2, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 2 failed"); } // rc = omega.pioda.PIODA_CalVoltage(0, 3, 0.0F); if (rc != omega.pioda.PIODA_NoError) { throw new System.ApplicationException("set voltagechannel 3 failed"); } } return 0; } else { return -1; } } enum pumpstates { Stopped, PartialFlow, FullFlow }; pumpstates pumpstate, oldpumpstate; const float channel0_base = 0.0739F; //Yellow const float channel1_base = 0.0739F; //Gray const float channel2_base = 0.1148F; // Blue const float channel3_base = 0.0792F; //Brown const float channel0_vrpm = 0.0097F; //Yellow const float channel1_vrpm = 0.0097F; //Gray const float channel2_vrpm = 0.0557F; // Blue const float channel3_vrpm = 0.0239F; //Brown const float strokevolume = 46.0F; const float waterdensity = 0.99823F; // tap water 20 C const float blooddensity = 1.06F; float density = 1.0F;
  • 9. double weight; char[] weightreq = new char[6]; //"*X01"; double minreslevel; double lowreslevel; Double curreslevel; double previousreslevel; double maxflowrate; int maxrpm; Boolean pumpon; double curflowrate; StreamWriter logfile; Stream logdata; double elapsedtime; Boolean recordon; NumberFormatInfo nfi; double monitortime; Queue reslevels; Bitmap greenuparrow, reddownarrow; SpVoice voice; SpeechVoiceSpeakFlags SpFlags = SpeechVoiceSpeakFlags.SVSFlagsAsync; int minpercentflow; }}namespace omega{ class pioda { // return co public const int PIODA_NoError = 0; // ID public const int PIO_DA = 0x800400; // Driver functions [DllImport("PIODA.DLL")] static public extern ushort PIODA_DriverInit(); [DllImport("PIODA.DLL")] static public extern void PIODA_DriverClose(); [DllImport("PIODA.DLL")] static public unsafe extern ushort PIODA_SearchCard (ushort* wBoards, int dwPIOCardID); // DA functions [DllImport("PIODA.DLL")] static public extern ushort PIODA_Voltage (ushort wBoardNo, ushort wChannel, float fValue); [DllImport("PIODA.DLL")] static public extern ushort PIODA_Current (ushort wBoardNo, ushort wChannel, float fValue); [DllImport("PIODA.DLL")] static public extern ushort PIODA_CalVoltage (ushort wBoardNo, ushort wChannel, float fValue); [DllImport("PIODA.DLL")] static public extern ushort PIODA_CalCurrent (ushort wBoardNo, ushort wChannel, float fValue); }}