![]() System Board | ![]() Data Terminal | ![]() 4" Updraft Valve | ![]() 4" Slider Valve |
This system uses the Arduino Data Terminal for displaying mode, tool being used, dust bin free space, and controlling the system. The 4" and 6" updraft valves make this system easy. Of the eight tools, only 6 use current sensors, the other 2 are run using manual mode.
The program Controls
Default | Automatic Operation: The system polls I-sensors for each tool and if one increases (motor turned on) it opens the associated valve, and turns on the DC's blower. The system continues monitoring the current of the tool and if it's current returns to normal (motor off), the DC is shutdown and the tool's valve is closed. | |
'1'-'8' | Manual operation: By entering a single digit 1-8, one of the tools is manually selected, the valve closed, and the DC started. If one of the tools is running in manual mode, and you enter another single digit 1-8 the DC shuts down, the valve is closed, the valve for the new machine is opened and the DC started again. | |
'0' (zero) | Cancel any current operation, shuts down DC, close all valves. | |
'A' | Cycle All Vavles Cycle all valves (1-8) to clear any debris. | |
'B' | Open A SECOND Valve (Manual Mode) Request a tool number, then stop DC, open that tool's valve, restart the DC. | |
'*' (splat) | Display Sensor Reading Requests a sensor number (1-8), when it is entered the sensor is selected and it's analog reading is displayed. Allows you to trurn on or off a machine and see it's Isnsr readings. | |
'#' (crunch) | Set Servo Values Requests a valve number (1-8) then the valve is opened and the servo's digital value is displayed. Entering a '2' increases the digital setting, an '8' decreases the setting. Entering a '6' closes the valve and displays the servo's valve closed setting, again '2' and '8' increase and decrease the setting. Entering a '4' opens the valve and displays its servo setting. Sensors are polled when not in manual mode or one of the test modes, if one reads an analog reading equal or greater than RDGTHLD, the tools is activated, valve opened, and DC turned on. An analog read may return 1023 digital, with 5 volts max and a digital value of 0 - 1023 that means 5 / 1023 = .00488 mv / increment. RDGTHLD = 200, or 200 * .00488 = .976 volts at the sensor. |
If I decide I need more commands, I'll add a 'Test' mode (maybe letter 'B') which will have a menu of all test requests: cycle all valves, set servo open/close, display Isnsr readings, etc. The test mode is terminated by '0' (cancel) and while in 'Test' mode disable auto Isnsr scanning.
One thing to note about programming, I've not done a lot of Arduino programming but I have done a lot of 'C' code programming (I learned at Bell Labs many moons ago) so the sketches may not look quite like normal Arduino programming.
I'm not a big fan of the Arduino IDE editor, so I usually use my old friend, the ubiquitous vi, bounce the IDE, compile, and download.
Please note: CODING STYLE (Read this, it'll make the code easier to understand)
RS-232 Communication:
I am using RS-232 to communicate to the Data Terminal, Dust Detector, and Valve 8.
The Data Terminal will be on the hardware Serial, the other two will uses the Software Serial library.
Software Serial has a requirement that you can only listen to one serial port at a time and you must explicitly state which to listen to at any given time.
In order to make this work I am using a query/response scenario, the control system wil send a request then wait for a response from that remote.
That way I know which remote to listen to for response.
These query/response actions will each have a timeout associated, so a remote having a problem won't hang up the entire control system.
After getting the basic system up and running, I converted the original dust detector to work with it (DustDetector2). The DustAuto System requests a dust depth from dust detector2 each second. | |
Originally, | |
DustDetector2 probes the dust in the bin, then transmitts (RS232 Ascii) the depth, in inches, to the DustAuto System. The Dust Collector System updates it's display of the current dust depth on the data terminal. Upon receiving the dust depth, DustAuto averages the last 5 readings before displaying or making a decision. If there have been 3 consecutive readings with the dust in the bin less than 8" from the top (where the sensor is) the system goes into "Dust Halt" mode and shuts down the dust collector blower motor. | |
Now | |
The dust detector now uses an IR (Infra Red) device to dermine if the dust in it's bin is too high, base on a pot in the IR detector..
When queried by DustAuto the detector reports OK or FULL.
A cancel will restore the system to IDLE state and resume probing Isensors.
Averaging and requiring multiple sequential bad readings before halting, is due to the DustDetector looking down into a virtual tornado (chaos) in the dust bin while the system is running. | |
If DustAuto doesn't receive a dust report within 30Ms, it shuts down ("Dust Halt"). |
/*********************************************************************** DUST COLLECTION AUTOMATION: PARTS TAKEN FROM BOB CLAGETT ON I LIKE TO MAKE STUFF (ILIKETOMAKESTUFF.COM) I/O DEVICE: LCDKEYPAD (DATA TERM) HDW: PCA9685 I2C PWM Servo driver, MG996R Servos, 74HC4051 Analog Mux, CURRENT SENSOR: ACS712-30A (66Ms/A), AND A SOLID STATE RELAY TOOLS NUMBERED 1 - 8, NO ZERO ***********************************************************************/ #include <Wire.h> #include <Adafruit_PWMServoDriver.h> #include <SoftwareSerial.h> /************************** DEFINES ************************************/ #define AUTODLY 20000 // AUTO MODE LOCK TIME #define DCRUN 11 // DUST COLLECTOR GO PIN #define DSPDLY 1000 // DELAY BETWEEN VOLT READING DISPLAYS #define DUSTAVGCNT 5 // MUST HAVE DUSTAVGCNT RDNGS TO AVERAGE #define DUSTBADS 3 // MUST HAVE DUSTBADS DUSTMINS TO HALT #define DUSTCHK 1000 // TIME BETWEEN DUST REQUESTS #define DUSTWAT 100 // TIME WAIT FOR DUST DTCTR #define DUSTMIN 8 // DUST BIN MUST HAVE MORE THAN 8" SPACE #define ESC 92 // BACKSLASH, IDE, Serial DOESN'T SEND CNTRL CHRS #define INSTRMAX 32 // INSTRING SIZE #define MITERSAW 6 // MITERSAW NBR #define MUXS0 7 // LSB // ANALOG MUX SELECT 0 #define MUXS1 6 // ANALOG MUX SELECT 1 #define MUXS2 5 // MSB // ANALOG MUX SELECT 2 #define NBRTOOLS 8 // NUMBER OF TOOLS #define NBRVALVES 8 // NUMBER OF VALVES #define PWM_ADDR 0X40 // SERVO CONTOROL ADDRESS #define V8WAT 5000 // PLANER VALVE WAIT TIME 5 SEC #define RDGTHLD 200 // DIGITAL READING THRESHOLD @ 4.887 MV/INCR #define DDRX 3 // SOFTWARE SERIAL RX #define DDTX 4 // SOFTWARE SERIAL TX #define V8RX 8 // VALVE-8 SERIAL RX #define V8TX 9 // VALVE-8 SERIAL TX #define SNSRDLY 20 // SAMPLE TIME 20MS #define SRVODLY 525 // MG996R MVS 60deg in .17 SEC, SERVO ACT DELAY #define SPINUP 1000 // DC SPIN UP TIME MS #define SPINDOWN 3000 // DUST COLLECTOR SPIN DOWN TIME #define SRVOBUMP 5 // VALVE SERVO INCR OR DECR #define NL 10 #define OPN 0 // VALVE CCW #define CLOS 1 // VALVE CW #define ZIN A7 // SENSOR IN enum Modes { IDLE, MANUAL, DSPRDG, AUTO, SETSRVO, MULTVLV, DUSTBINHALT }; typedef unsigned long ulong; #define ssL(str,ndx) for( byte x = 0; x < ndx +1; x++ ) str[x] = str[x +1]; /************************** VARIABLES ************************************/ Adafruit_PWMServoDriver Servo = Adafruit_PWMServoDriver(); SoftwareSerial Dust( DDRX, DDTX ); // DUST DETECTOR SERIAL RX, TX SoftwareSerial V8( V8RX, V8TX ); // PlanerValve (V8) SERIAL RX, TX bool DcOnFlg = false, Rs232 = false, DstOnScrn = false; bool V8Req = false; char *ToolNam[NBRTOOLS+1] = { "0","Sander","BandSaw","Free-1","TableSaw" ,"Free-2","MiterSaw","Router","Planer" }; // TOOL NAMES ARRAY short BasVal[NBRTOOLS +1], RdgTool = 0, VlvOc = CLOS; int DustSpc, DustCnt =0, DustAcc =0, DustBads =0; // DUST RELATED VARS int VlvVals[NBRVALVES +1][2] = {{0,0}, // OPN,CLOS VALVE, NO VALVE ZERO {160,480}, {150,445}, {160,450}, {180,425}, {160,450},{125,435},{150,440} // SANDER BANDSAW FREE-1 tableSAW FREE-2 MITERSAW ROUTER ,{190,465}, }; // MITERSAW ulong NxtDsp =0, AutoTime =0, DustTim = 0; char CurPos[8] = { ESC,'[','0',';','0','0','f',0}; // POSIT CURSOR, ROW,COL char ClrScrn[6] = { ESC,'[','2','j',0}; // CLEAR SCREEN char Hdr[] = {" Dust Collector\n"}, DstChrs[18]; char InStr[INSTRMAX], *VlvPos[2] = {"Open","Close"}; byte InNdx =0, Mode = IDLE, ActvTool = 0, ActVlv = 0, SsNdx =0; /************************** PROTOTYPES ************************************/ void cancel( byte noPnt ); // CANCEL ALL OPERATIONS bool chkAmpChg( int tool ); // CHECK FOR CURRENT CHANGE void chkDustBin(); // PROCESS DUST BIN DEPTHS void chkTools(); // CHECK FOR ACTIVE TOOL void clrScrn(); // CLEAR DATA TERMINAL SCRN void cycVlvs(); // CYCLE ALL VALVES void dcOn(),dcOff(); // DUST COLLECTOR ON OFF void dspDust( int dust ); // DISPLAY DUST STATUS void dspIRdg( char chr ), dspIRdgSu(); // DISPLAY ISNSR READINGS void doChrs(); // PROCESS KBD CHARS void dustHalt( byte row, byte col, char* msg); // DUST HALT char getChr(); // GET A CHAR FROM INSTR int getDust(); // SOFTWARE SERIAL INTERRUPT SERVICE ROUTINE void multVlv( char chr ), multVlvSu(); // OPEN MULTIPLE VALVES short opnVlv( uint8_t num), clsVlv( uint8_t num, byte prnt); // OPN/CLOS VLV void posCur( byte row, byte col ); // SET CURSOR POSTION short reqV8( char cmd ); // SEND REQUEST TO PLANER VALVE int rdSnsr( short snsr); // READ A SENSOR void runTool( char chr ); // START A TOOL void serialEvent(); // RS232 INTERRUPT ROUTINE void setSrvo( char chr), setSrvoSu(); // SET SERVO VALUES short v8Fail(); /*F****************************************************************** * **********************************************************************/ void setup() { int ndx; Serial.begin( 9600 ); // START SERIAL I/O FROM DATA TERMINAL Serial.print( Hdr ); // PRINT HEADER ON DATA TERM Dust.begin( 9600 ); // START SFTW SERIAL I/O FROM DUST BIN V8.begin( 9600 ); // START SFTW SERIAL I/O FROM DUST BIN pinMode( DCRUN, OUTPUT); // I/O PIN OUTPUT FOR RUNNING DUST COLLECTOR Servo.begin(); Servo.setPWMFreq( 50 ); // SET PWM FREQ = 50HZ delay( 1000 ); pinMode( MUXS2, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX pinMode( MUXS1, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX pinMode( MUXS0, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX for( ndx =1; ndx <= NBRTOOLS; ndx++) BasVal[ndx] = rdSnsr( ndx ); // SAVE BASE SNSR RDGS, FOR VOLT CMPRSN for( ndx =1; ndx <= NBRVALVES; ndx++) clsVlv( ndx, 0 ); // CLOSE ALL VALVES } /*F****************************************************************** * **********************************************************************/ void loop() { if( Rs232 == true ) doChrs(); // CHAR ARRIVED ON THE SERIAL I/O FROM DATA TERM if( millis() > DustTim ) chkDustBin(); // CHECK DUST BIN DEPTH if( Mode == DUSTBINHALT ) return; // DUST BIN FULL, ONLY CANCEL WILL RESTART chkTools(); // SEE IF ANY TOOL'S MOTOR IS RUNNING if( (Mode == DSPRDG) ) dspIRdg( 9 ); // PASS CHAR TO DISPLAY ISNSR VOLTAGE if( (Mode == SETSRVO) ) setSrvo( 9 ); // PASS CHAR TO ADJUST SERVO } /*F****************************************************************** * DUSTBIN DEPTH MESSAGE PROCESSING, AFTER DUSTAVGCNT **********************************************************************/ void chkDustBin() { int dust; if((Mode == DSPRDG) || (Mode == SETSRVO)) return; if( (dust = getDust()) < 0 ) return( dustHalt( 3, 0, " No Dust ")); if( (DustAcc > 0) && (DustCnt >= DUSTAVGCNT) ) { // AVERAGE DUST DEPTH REPORTS FROM DETECTOR DustSpc = DustAcc / DustCnt; // UPDATE DUST SPACE dspDust( DustSpc ); DustCnt = DustAcc = 0; // RESET ACCUMULATOR AND COUNT if( (DustSpc <= DUSTMIN) && (DustSpc > 0) && (DcOnFlg == true) ) { if( (Mode == DUSTBINHALT) || (++DustBads < DUSTBADS) ) return; // ALREADY HALT MODE, OR NOT ENOUGH BAD DEPTHS dustHalt( 0, 3, "Dust Bin Halt"); // DC RUNING & DUST BIN FULL } else DustBads = 0; // ONE GOOD DUST READING RESETS DUSTBADS } } /*F****************************************************************** * CHECK FOR TOOL MOTOR RUNNING **********************************************************************/ void chkTools() { int ndx, tool =0; ulong now; if( (Mode != AUTO) && (Mode != IDLE) ) return; // DO NOT CHECK FOR I FLOW UNLESS IN AUTO OR IDLE now = millis(); for( ndx =1; ndx <= NBRTOOLS; ndx++) { // SCAN THROUGH TOOLS & CHECK FOR INCREASED CUR FLOW if( chkAmpChg( ndx )) { // TOOL ON tool = ndx; Mode = AUTO; if( tool == MITERSAW ) AutoTime = millis() + AUTODLY; // MITERSAW RUNNING break; // FOUND ONE } } if( (ActvTool == MITERSAW) && (now < AutoTime) ) return; // TOOL STARTED, WAIT AUTODLY B4 CHANGING if( ActvTool == tool ) return; // SAME TOOL STILL RUNNING if( ActvTool && !tool ) cancel( 0 ); // NO ACTIVE TOOL AND DC IS ON else if( (tool != 0) && (tool != ActvTool) ) runTool( tool ); // START TOOL } /*F****************************************************************** * PROCESS KBD CHRS * 0 CANCEL ALL * 1-8 OPEN VALVE N, TURN DC ON * A CYCLE ALL VALVES * #n TEST ISNSRS * *n SET SERVOS **********************************************************************/ void doChrs() { char chr; while( (chr = getChr()) != 0 ) // READ A CHAR FROM InStr, IF AVAIL { Rs232 = false; // CLEAR SERIAL I/O FLAG if( (Mode == DSPRDG) && (chr != '0')) return( dspIRdg( chr ) ); // PASS CHR TO DSPLY ISENSOR VOLTS if( (Mode == SETSRVO) && (chr != '0')) return( setSrvo( chr )); // PASS CHR TO SERVO SETUP if( (Mode == MULTVLV) && (chr != '0')) return( multVlv( chr )); // PASS CHR TO MULTI VALVE SETUP switch( chr ) { case '0': // CANCEL CURRENT OPERATION cancel( 0 ); break; case 'A': // CYCLE ALL VALVES cycVlvs(); break; case 'B': multVlvSu(); // OPEN MULTIPLE VALVES break; case '1' ... '8': // MANUAL MODE, OPEN VALVE & RUN DC Mode = MANUAL; runTool( chr ); break; case '*': // SPLAT, DISPLAY ISENSOR VOLTAGE READING dspIRdgSu(); break; case '#': // CRUNCH, SETUP SERVOS setSrvoSu(); break; case NL: // GOT NEWLINE break; // DISCARD NEWLINE default: Mode = IDLE; break; } } } /*F****************************************************************** * SETUP FOR DISPLAY ISNSR VOLTAGE READINGS, CALLED FROM doChrs() **********************************************************************/ void dspIRdgSu() { if( DcOnFlg ) dcOff(); // DC IS RUNNING, STOP IT Mode = DSPRDG; // SET DISPLAY READING MODE AutoTime =0; ActVlv = 0; VlvOc = CLOS; clrScrn(); posCur( 0, 2 ); Serial.print("Read Sensor"); posCur( 1, 0 ); Serial.print("Enter Tool Number"); } /*F****************************************************************** * SETUP SERVO SETUP **********************************************************************/ void setSrvoSu() { if( DcOnFlg ) dcOff(); Mode = SETSRVO; clrScrn(); delay( 200 ); posCur( 0, 0 ); Serial.print(" SERVO SETUP"); posCur( 1, 0 ); Serial.print("Enter Servo Number"); } /*F****************************************************************** * RUN A MACHINE **********************************************************************/ void runTool( char chr ) { byte tool; clrScrn(); tool = (chr & 15); // STRIP OFF UPPER BITS OF CHR 0X3n posCur( 0, 6 ); Serial.println( (String)ToolNam[tool] ); // ROW: 0, PRINT TOOL NAME if( (ActvTool > 0) && (ActvTool != tool)) { // NEW ACTIVE TOOL if( DcOnFlg ) dcOff(); clsVlv( ActvTool, 1 ); } ActvTool = tool; opnVlv( ActvTool ); dcOn(); } /*F****************************************************************** * CANCEL CURRENT OPERATION **********************************************************************/ void cancel( byte noPnt ) { short ndx; if( !noPnt ) { clrScrn(); Serial.println(" Cancel Operation"); } if( DcOnFlg ) dcOff(); // DC IS ON, STOP IT for( ndx = 1; ndx <= NBRVALVES; ndx++ ) clsVlv( ndx, 1 ); // CLOSE ALL VALVES Mode = IDLE; AutoTime =0; // CANCEL ANY TOOL RUNNING IN AUTO MODE RdgTool = ActvTool = 0; if( noPnt ) return; clrScrn(); Serial.print((String)Hdr ); } /*F****************************************************************** * DISPLAY ISNSR VOLTAGE READINGS, CALLED FROM loop(), or doChrs() **********************************************************************/ void dspIRdg( char chr ) { short tool, val; int32_t now; if( (chr >= '1' ) && (chr <= '8' )) { // SET NEW TOOL RdgTool = (chr & 0X0F); // STRIP OFF 0X3n posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)ToolNam[RdgTool] + " = " ); NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } now = millis(); // GET CURRENT TIME if((now > NxtDsp) && (RdgTool != 0)) { // TIME TO DISPLAY A CURRENT READING NxtDsp = (now + DSPDLY); // SAVE TIME OF CURRENT DISPLAY val = rdSnsr( RdgTool ); posCur( 1, 10 ); // ROW 1, COL 10 Serial.println( val ); // 4.88MV / INCR } } /*F****************************************************************** * CYCLE ALL VALVES TO REMOVE ANY LARGE SPLINTERS ETC. **********************************************************************/ void cycVlvs() { char tool, chr, buf[24]; clrScrn(); Serial.println(" Cycling Valves "); if( DcOnFlg ) dcOff(); for( tool = 1; tool <= NBRVALVES; tool++ ) { // FLAP ALL VALVES posCur( 1, 0 ); // ROW 2, COL 0 Serial.println((String)ToolNam[tool] ); opnVlv( tool ); delay( SRVODLY ); // WAIT FOR THE SERVO TO ACT clsVlv( tool, 1 ); delay( SRVODLY ); // WAIT FOR THE SERVO TO ACT } ActvTool = 0; clrScrn(); Serial.print( Hdr ); } /*F****************************************************************** * SERVO SETUP **********************************************************************/ void setSrvo( char chr ) { short tool, val, rtn; int32_t now; if( !ActVlv && (chr == 9)) return; // CALLED FROM LOOP, NO ACTIVE VALVE if( !ActVlv && ((chr >= '1') && (chr <='8'))) { // NEW SERVO NMBR ActVlv = chr & 15; // SET NEW ACTIVE VALVE NBR posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)ToolNam[ActVlv] + "-" ); // LIKE "TableSaw-" NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } else if( (chr >= '1') && (chr <= '8') ) { switch( chr ) { case '2': // VAL UP VlvVals[ActVlv][VlvOc] += SRVOBUMP; break; case '4': // OPEN VALVE VlvOc = OPN; // VlvOc: VALVE SHOULD BE OPEN OR CLOSED break; case '6': // CLOSE VALVE VlvOc = CLOS; // VlvOc: VALVE SHOULD BE OPEN OR CLOSED break; case '8': // VAL DN VlvVals[ActVlv][VlvOc] -= SRVOBUMP; break; default: break; } if( (ActVlv == 8) && (VlvOc == OPN) && ((rtn =reqV8( 'O' )) <0)) v8Fail(); else if( (ActVlv == 8) && (VlvOc== CLOS) && ((rtn =reqV8( 'C' )) <0)) v8Fail(); else { Servo.setPWM( ActVlv, 0, VlvVals[ActVlv][VlvOc]); // SET SERVO delay( SRVODLY ); // WAIT FOR SERVO TO ACT } NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } now = millis(); // GET CURRENT TIME if((now > NxtDsp) && (ActVlv != 0)) { NxtDsp = (now + DSPDLY); // SAVE TIME OF NEXT DISPLAY posCur( 1, 10 ); // ROW 1, COL 10 val = VlvVals[ActVlv][VlvOc]; Serial.println( (String)VlvPos[VlvOc] + ":" +val ); // "Close: 450" } } /*F****************************************************************** * TURN DUST COLLECTOR ON **********************************************************************/ void dcOn() { if( Mode == DUSTBINHALT ) return; digitalWrite( DCRUN, 1); posCur( 1, 13 ); Serial.println("DC On "); DcOnFlg = true; DustCnt = DustAcc = 0; // RESET DUST ACCUM & CNT delay( SPINUP ); } /*F****************************************************************** * TURN DUST COLLECTOR OFF **********************************************************************/ void dcOff() { posCur( 1, 3 ); Serial.println("Stopping DC "); delay( 2000 ); // WAIT FOR PLENUM/HOSE TO EMPTY digitalWrite( DCRUN, 0); delay( SPINDOWN ); // WAIT FOR DC SPINDOWN posCur( 1, 0 ); // ERASE ROW 1 TO END OF LINE DcOnFlg = false; } /*F****************************************************************** * SAMPLING CURRENT SENSOR 1-7 (LO NIBBLE 0X0001 - 0X0111), SNSR 8 =0 **********************************************************************/ int rdSnsr( short snsr ) // SNSR: 1 - 8 { int rdVal, cnt, pin, msk =1, rtn; ulong end, tmp; // S0:D7(LSB), S1:D6, S2:D5(MSB) pin scans 7 - 5 for( pin = MUXS0, msk = 1; pin > 4; --pin, msk <<=1 ) { // SET SENSOR # INTO MUX SEL0-SEL2 INPUTS, LSB to MSB, SNSR 8 = 0 if( msk & snsr ) digitalWrite( pin, HIGH ); // WT HI PINS MUXS0,MUXS1,MUXS2 else digitalWrite( pin, LOW ); // WT LOW PINS MUXS0,MUXS1,MUXS2 } delay( 2 ); // WAIT 2MS FOR SEL TO INP TIME end = millis() + SNSRDLY; // SAVE CURRENT TIME + SAMPLE TIME for( cnt = tmp =0; millis() < end; cnt++ ) { // NOISY SIGNAL, AVERAGE FOR SAMPLE TIME rdVal = analogRead( ZIN ); // 0-1023 DIGITAL RDG tmp += rdVal; } // 175 - 180 samples IN 20 MS rtn = tmp / cnt; return( rtn ); } /*F****************************************************************** * CHECK FOR AMPERAGE CHANGE ON A TOOL **********************************************************************/ bool chkAmpChg( int tool) { int rdg; rdg = rdSnsr( tool ); // READINGS RUN FROM OFF: 52-81, ON: 364-461 if( rdg > RDGTHLD ) // NEW SENSOR IGNORE BASE (BasVal[tool] + RDGTHLD)) return( true ); // RETURN TOOL ON else return( false ); // RETURN TOOL OFF } /*F****************************************************************** * GET CHAR FROM INSTR **********************************************************************/ char getChr() { char chr; if( InNdx == 0 ) return( 0 ); chr = InStr[--InNdx]; ssL( InStr, InNdx ); // SHIFT INSTR LEFT if( InNdx == 0 ) Rs232 = false; // INSTR EMPTY return( chr ); } /*F****************************************************************** * CLOSE A VALVE **********************************************************************/ short clsVlv( uint8_t num, byte prnt ) { short rtn = 1; if( DcOnFlg ) dcOff(); VlvOc = CLOS; // SET CURRENT VALVE POSTION = CLOSED if( prnt ) { posCur( 1, 0 ); Serial.println((String)"Vlv "+num+" Clos" ); } if( num == 8 ) rtn = reqV8( 'C' ); // REQUEST VALVE 8 CLOSE else { Servo.setPWM( num, 0, VlvVals[num][CLOS]); // CLOSE VALVE delay( SRVODLY ); // WAIT FOR SERVO TO ACT } Servo.setPWM( 15, 0, 400 ); // DISTRACT PCA9685 TO SERVO 15 ActVlv = 0; if( prnt ) posCur( 1, 0 ); // CLEAR ROW 1 } /*F****************************************************************** * OPEN A VALVE **********************************************************************/ short opnVlv( uint8_t num ) { int rtn = 1; if( DcOnFlg ) dcOff(); VlvOc = OPN; posCur( 1, 0 ); Serial.println((String)"Vlv "+num+" Opn"); if( num == 8 ) rtn = reqV8( 'O' ); // REQUEST VALVE 8 OPEN else { Servo.setPWM( num, 0, VlvVals[num][OPN]); // OPEN VALVE delay( SRVODLY ); } ActVlv = num; } /*F****************************************************************** * RS-232 INTERRUPT SERVICE ROUTINE, DO NOT TARRY HERE **********************************************************************/ void serialEvent() { // RUNS EACH TIME (AFTER) LOOP RUNS int val; char chr; while( Serial.available()) // INTERRUPT SERVICE ROUTINE, DON'T TARRY HERE { chr = (char)Serial.read(); // GET NEW CHAR if( chr < 32 ) continue; // DISCARD NON_PRINtable CHAR if( InNdx >= INSTRMAX ) { // IN STR NDX TOO LARGE, RESET IT Serial.println("Overrun"); break; } val = chr & 15; InStr[InNdx++] = chr; // ADD NEW CHAR TO InStr[] Rs232 = true; // SET FLAG SO MAIN LOOP CAN DO SOMETHING ABOUT IT } } /*F****************************************************************** * REQUEST DEPTH FROM DUST DETECTOR, WAIT FOR RESPONSE * DATA FROM THIS MAKES SERIOUS DECISIONS ABOUT SHUTING DOWN DC **********************************************************************/ int getDust() { // @ 9600 CHARS ARRIVE EVERY 1Ms int val, dstVal; char chr; ulong end; // Serial.println((String)"getDust: Bgn"); Dust.listen(); Dust.print( "D\n" ); // SEND DUST DEPTH REQUEST TO DUST DET DustSpc = 0; DustTim = millis() + DUSTCHK; // SET TIME OF NEXT DUST DEPTH REQUEST val = dstVal =0; // BELOW: < DustTim IN CASE DUSTDET DOESN'T RESPOND end = millis() + DUSTWAT; // SET TIMER FOR DUST DET RESONSE while( millis() < end ) { // LOOP HERE WHILE DUSTREQ & NOT DUSTTIME if( Dust.available() ) { // KEEP READING TIL FIND NEWLINE chr = Dust.read(); // GET NEW CHAR // Serial.println((String)"GotChr: "+chr); if( chr == '\n' ) { // END OF TRANSMISSION DustAcc += dstVal; // ACCUMULATE DUST DEPTH DustCnt++; // BUMP DUST READING COUNTER break; } if( (chr < '0') || (chr > '9')) continue; // DISCARD NON NUMERIC CHAR val = (chr & 15); // CONVERT ASCII TO BIN: '2' (0X32) & 0X0F = 2 dstVal = (dstVal * 10) + val; // ACCUM DEC DUST DEPTH VALS } } // Serial.println((String)"getDust: End, dstVal: "+dstVal); if( millis() > end ) return( -1 ); return( dstVal ); } /*F****************************************************************** * DUST HALT **********************************************************************/ void dustHalt( byte row, byte col, char *msg) { // DC RUNING & DUST BIN FULL, STOP EVERYTHING Mode = DUSTBINHALT; // ADVERTISE WHY WE'RE SHUTDOWN clrScrn(); posCur( row, col ); // SET CURSOR POSTION Serial.println( (String)msg ); cancel( 1 ); // STOP EVERYTHING } /*F****************************************************************** * OPEN MULTIPLE VALVE SETUP **********************************************************************/ void multVlvSu() { if( DcOnFlg ) dcOff(); Mode = MULTVLV; clrScrn(); delay( 200 ); // posCur( 0, 0 ); // Serial.print("OPEN ANOTHER VALVE"); posCur( 1, 0 ); Serial.print("Enter Valve Number"); dcOff(); } /*F****************************************************************** * OPEN MULTIPLE VALVES **********************************************************************/ void multVlv( char chr ) // OPEN MULTIPLE VALVES { short tool; if( (chr >= '1' ) && (chr <= '8' )) { // SET NEW TOOL Mode = MANUAL; tool = (chr & 0X0F); // STRIP OFF 0X3n posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)"+ "+ToolNam[tool] ); opnVlv( tool ); dcOn(); } else cancel( 0 ); } /*F****************************************************************** * POSITION CURSOR Esc[r;ccf SET CURSOR TO ROW COL **********************************************************************/ void posCur( byte row, byte col ) { char str[8]; strcpy( str, CurPos ); sprintf( &str[2], "%1d;%02df", row, col ); Serial.print( str ); delayMicroseconds( 200 ); } /*F****************************************************************** * CLEAR SCREEN **********************************************************************/ void clrScrn() { Serial.print( ClrScrn ); delay( 200 ); DstOnScrn = false; } /*F****************************************************************** * RUN A MACHINE **********************************************************************/ void dspDust( int dustSpc ) { char buf[32]; if( !DstOnScrn ) { // NEED TO REPRINT "Dust Space" posCur( 3, 0 ); // SET CURSOR POSTION Serial.print( (String)"Dust Space: "); DstOnScrn = true; } posCur( 3, 12 ); sprintf( buf, "%02u\"", dustSpc ); Serial.print( (String)buf ); } /*F****************************************************************** * SEND PLANER VALVE (V8) OPEN/CLOSE REQUEST RETURN: 1 = OK, else -1 **********************************************************************/ short reqV8( char req ) // REQ IS UC LETTER 'O' or 'C' { ulong end; char chr, resp =0; short rtn = 1; V8.listen(); V8.println((String)req ); // SEND PLANER VALVE REQUEST end = millis() + V8WAT; // SET TIMER FOR PLANER VALVE RESONSE while( millis() < end ) { // LOOP HERE WHILE PLANER VALVE MOVES if( V8.available() ) { // KEEP READING TIL FIND NEWLINE chr = V8.read(); // GET RESPONSE: 'O' =OK, 'F' =FAIL if( chr == NL ) return( rtn ); // END OF RESPONSE if( (chr != 'O') && (chr != 'K') ) rtn = -1; } } return( -1 ); // TIMEOUT OR FAILED REQ } /*F****************************************************************** * **********************************************************************/ short v8Fail() { posCur( 2, 0 ); Serial.println((String)"V 8 Failed"); cancel( 0 ); return( -1 ); }