CEB Press Control Code v19.01: Difference between revisions
Line 21: | Line 21: | ||
//Reset is the shutdown/initialization procedure. It's selected by non-selection. | //Reset is the shutdown/initialization procedure. It's selected by non-selection. | ||
#define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce | |||
#define PRESSURE_SENSOR_DEBOUNCE | |||
#define TURNOFF_DELAY 50 //Addresses 40 ms turnoff time of solenoid. Loses 1 second every minute. | #define TURNOFF_DELAY 50 //Addresses 40 ms turnoff time of solenoid. Loses 1 second every minute. | ||
#define PRESS_DELAY 500 | #define PRESS_DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms) | ||
#define TEST_DELAY | #define TEST_DELAY 30 //'''Note that if this was set to 0, the downward main cylinder motion step was skipped. Why?''' | ||
//30 ms works, 20 ms doesn't. | |||
//user defined function declarations tell compiler what type parameters to expect for function definitions | //user defined function declarations tell compiler what type parameters to expect for function definitions | ||
bool lowPressure(); //function to read pressure sensor | bool lowPressure(); //function to read pressure sensor | ||
Line 38: | Line 37: | ||
unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. | unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. | ||
unsigned long previousMillis = 0; //time measurement for expansion | unsigned long previousMillis = 0; //time measurement for expansion | ||
unsigned long HalfWay = 0.58; //Multiplier for closure of drawer. Shoudld be about 0.5. | |||
void setup() { | void setup() { | ||
Line 66: | Line 67: | ||
//Step 0 Reset/Initialize - Brick pressing sequence - http://bit.ly/2Hnuk6F | //Step 0 Reset/Initialize - Brick pressing sequence - http://bit.ly/2Hnuk6F | ||
Serial.println("Testing. Started right motion."); | Serial.println("Testing. Started right motion."); | ||
Serial.println("Solenoid turnoff delay (ms):"); | |||
Serial.println(TURNOFF_DELAY); | |||
Serial.println("Test delay (ms):"); | |||
Serial.println(TEST_DELAY); | |||
Serial.println("Pressure sensor debounce (ms):"); | |||
Serial.println(PRESSURE_SENSOR_DEBOUNCE); | |||
while (lowPressure() == true) { //Move drawer cylinder right | while (lowPressure() == true) { //Move drawer cylinder right | ||
digitalWrite(SOLENOID_RIGHT, HIGH); | digitalWrite(SOLENOID_RIGHT, HIGH); | ||
Line 112: | Line 119: | ||
if (resetSelected() == true) { | if (resetSelected() == true) { | ||
digitalWrite(SOLENOID_RIGHT, HIGH); | digitalWrite(SOLENOID_RIGHT, HIGH); | ||
delay(drawerExtTime * 0.75 * | delay(drawerExtTime * 0.75 * HalfWay); //0.58 is the half-way point of drawer cylinder; 0.75 is the Drawer Multiplier | ||
digitalWrite(SOLENOID_RIGHT, LOW); | digitalWrite(SOLENOID_RIGHT, LOW); //Can modify the HalfWay to fine tune the drawer closure location | ||
} | } | ||
Serial.println("Compression chamber closed. Compressing block..."); | Serial.println("Compression chamber closed. Compressing block..."); | ||
//Step 3 Compression by main cylinder with delay | //Step 3 Compression by main cylinder with delay | ||
Line 143: | Line 150: | ||
} | } | ||
//Cycle through sequence from 1 (recalibration) | //Cycle through sequence from 1 (recalibration) | ||
} //end of loop | } //end of loop |
Revision as of 02:37, 2 February 2019
Code
https://github.com/OpenSourceEcology/OSE_CEB_Press_v19.01
Notes
Real Testing, Full Bricks
Hint: Code tested, it works. This code can also be followed manually. There are status updates that can be invoked by looking at serial monitor:
.
In the manual testing, one can trigger the high pressure manually and look at serial monitor to determine what state the machine is in. This is useful for testing to understand real life motion with the pressure sensor connected. The 1.7 second motion time of the drawer shown, combined with Brick Pressing Calculations, shows 6 block per minute in this test case using a 27 hp Briggs&Stratton but not apparently at full power.
- define SOLENOID_UP 7 //Extension. See pin mapping above.
- define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
- define SOLENOID_LEFT 5 //Extension.
- define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
//THE FOLLOWING PINS WERE SELECTED AS THE MID 6 PINS OF THE UPPER RIGHT 8 PIN HEADER ON RELAY SHIELD
- define PRESSURE_SENSOR 13 //Needs pins adjacent to get 6-pin dupont housing for both selector and sensor
- define SELECTOR_FULL 12 //Primary cylinder thickness setting is based on secondary cylinder motion.
- define SELECTOR_THREEQUARTER 11 //Secondary cylinder timing is measured only.
- define SELECTOR_HALF 10 // QUARTER to FULL refers to brick thickness.
- define SELECTOR_QUARTER 9 //Reset is the absence of any brick thickness selection.
//Reset is the shutdown/initialization procedure. It's selected by non-selection.
- define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
- define TURNOFF_DELAY 50 //Addresses 40 ms turnoff time of solenoid. Loses 1 second every minute.
- define PRESS_DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
- define TEST_DELAY 30 //Note that if this was set to 0, the downward main cylinder motion step was skipped. Why?
//30 ms works, 20 ms doesn't.
//user defined function declarations tell compiler what type parameters to expect for function definitions bool lowPressure(); //function to read pressure sensor bool resetSelected(); //checks for selection of position 0 for reset state bool quarterSelected(); // 1/4 brick mode bool halfSelected(); // 1/2 brick mode bool threequarterSelected(); // 3/4 mode bool fullSelected(); // checks for selection switch position for FULL size brick mode //Global variables unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. unsigned long previousMillis = 0; //time measurement for expansion unsigned long HalfWay = 0.58; //Multiplier for closure of drawer. Shoudld be about 0.5.
void setup() {
//initialize pin I/O Inputs and turn everything off to avoid startup glitches //always consider internal pullup resistor states when making wiring changes to prevent damage to the microcontroller pins pinMode(SELECTOR_QUARTER, INPUT_PULLUP); pinMode(SELECTOR_HALF, INPUT_PULLUP); pinMode(SELECTOR_THREEQUARTER, INPUT_PULLUP); pinMode(SELECTOR_FULL, INPUT_PULLUP); pinMode(SOLENOID_RIGHT, OUTPUT); digitalWrite(SOLENOID_RIGHT, LOW); pinMode(SOLENOID_LEFT, OUTPUT); digitalWrite(SOLENOID_LEFT, LOW); pinMode(SOLENOID_DOWN, OUTPUT); digitalWrite(SOLENOID_DOWN, LOW); pinMode(SOLENOID_UP, OUTPUT); digitalWrite(SOLENOID_UP, LOW); pinMode(PRESSURE_SENSOR, INPUT); digitalWrite(PRESSURE_SENSOR, INPUT_PULLUP); Serial.begin(9600);
}
void loop() {
//***************************************************************************************************************** //Reset should be done at end of pressing. If state of machine is correct, //no need to select reset at beginning. Turn the machine on and select 1-4. //Step 0 Reset/Initialize - Brick pressing sequence - http://bit.ly/2Hnuk6F Serial.println("Testing. Started right motion."); Serial.println("Solenoid turnoff delay (ms):"); Serial.println(TURNOFF_DELAY); Serial.println("Test delay (ms):"); Serial.println(TEST_DELAY); Serial.println("Pressure sensor debounce (ms):"); Serial.println(PRESSURE_SENSOR_DEBOUNCE); while (lowPressure() == true) { //Move drawer cylinder right digitalWrite(SOLENOID_RIGHT, HIGH); } digitalWrite(SOLENOID_RIGHT, LOW); delay(TEST_DELAY); //*************************************************************** Serial.println("Reset - moved right. Moving up..."); while (lowPressure() == true) { //Move main cylinder up digitalWrite(SOLENOID_UP, HIGH); } digitalWrite(SOLENOID_UP, LOW); Serial.println("Reset complete. Waiting for main loop..."); delay(50); //
//*********************************************************************************************************** //Step 1 Calibration + Soil Loading/Brick Ejection if (resetSelected() == true) { //Proceeds only if selector is not on 0 (reset) position previousMillis = millis(); //lowPressure() call adds a slight debounce delay to the millis diffirence Serial.println("Calibration - started measurement by moving drawer left..."); while (lowPressure() == true) { //Here we eject brick if this is a repeat cycle. digitalWrite(SOLENOID_LEFT, HIGH);
} digitalWrite(SOLENOID_LEFT, LOW); drawerExtTime = millis() - previousMillis; delay(TEST_DELAY); //*************************************************************** delay(TURNOFF_DELAY); //*************************************************************** Serial.print("Calibration - time measured to be "); Serial.print(drawerExtTime); Serial.print(" ms. Moving main cylinder down..."); }
while (lowPressure() == true) { digitalWrite(SOLENOID_DOWN, HIGH); } digitalWrite(SOLENOID_DOWN, LOW); delay(TURNOFF_DELAY); //*************************************************************** delay(TEST_DELAY); //*************************************************************** Serial.println("Soil loading - main cylinder moved down."); Serial.print("Closing chamber for "); Serial.print(drawerExtTime * 0.75 * 0.58); Serial.println(" ms."); //Step 2 Compression Chamber Closure if (resetSelected() == true) { digitalWrite(SOLENOID_RIGHT, HIGH); delay(drawerExtTime * 0.75 * HalfWay); //0.58 is the half-way point of drawer cylinder; 0.75 is the Drawer Multiplier digitalWrite(SOLENOID_RIGHT, LOW); //Can modify the HalfWay to fine tune the drawer closure location } Serial.println("Compression chamber closed. Compressing block..."); //Step 3 Compression by main cylinder with delay if (resetSelected() == true) { while (lowPressure() == true) { digitalWrite(SOLENOID_UP, HIGH); } delay(PRESS_DELAY); digitalWrite(SOLENOID_UP, LOW); Serial.println("Block compressed. Opening chamber by moving drawer right..."); } //Step 4 Ejection if (resetSelected() == true) { while (lowPressure() == true) { digitalWrite(SOLENOID_RIGHT, HIGH); } digitalWrite(SOLENOID_RIGHT, LOW); delay(TURNOFF_DELAY); //*************************************************************** delay(TEST_DELAY); //*************************************************************** Serial.println("Chamber opened - drawer is at the right."); while (lowPressure() == true) { digitalWrite(SOLENOID_UP, HIGH); } digitalWrite(SOLENOID_UP, LOW); delay(TURNOFF_DELAY); //*************************************************************** delay(TEST_DELAY); //*************************************************************** Serial.println("Block pushed up to daylight."); } //Cycle through sequence from 1 (recalibration)
} //end of loop //user defined function definitions are code that can be called from almost anywhere (within scope). //reads pressure sensor state HIGH is true and LOW is false (pullup) bool lowPressure() {
if (digitalRead(PRESSURE_SENSOR) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(PRESSURE_SENSOR) == HIGH) { return true; } else { return false; } } else { return false; }
}
//reads selector - HIGH is false, LOW is true- SELECTOR_RESET, SELECTOR_QUARTER, SELECTOR_HALF, SELECTOR_3QUARTERS, SELECTOR_FULL, bool resetSelected() {
if (fullSelected() == false && threequarterSelected() == false && halfSelected() == false && quarterSelected() == false && quarterSelected() == false) { return true; } else { return false; }
}
bool quarterSelected() {
if (digitalRead(SELECTOR_QUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_QUARTER) == HIGH) { return false; } else { return true; } } else { return true; }
}
bool halfSelected() {
if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }
}
bool threequarterSelected() {
if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { return false; } else { return true; } } else { return true; }
}
bool fullSelected() {
if (digitalRead(SELECTOR_FULL) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_FULL) == HIGH) { return false; } else { return true; } } else { return true; }
}
Both Cylinder Bounce Testing
Hint: Delay >40 ms is necessary to address the 40 ms turnoff time of the hydruaulic solenoid. 1 second lost due to this delay for every 5 block is acceptable.
//defines to make it easier for non-coders to make adjustments for troubleshooting and custom changes
- define SOLENOID_UP 7 //Extension. See pin mapping above.
- define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
- define SOLENOID_LEFT 5 //Extension.
- define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
- define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
//Activated when nothing is selected.
- define SELECTOR_QUARTER 12 //Reset is the shutdown/initialization procedure. All procedures are selected by
- define SELECTOR_HALF 11 //the WHILE function. QUARTER to FULL refers to brick thickness.
- define SELECTOR_THREEQUARTER 10 //Secondary cylinder timing is measured only.
- define SELECTOR_FULL 9 //Primary cylinder thickness setting is based on secondary cylinder motion.
- define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
- define TURNOFF_DELAY 50 //Addresses 40 ms turnoff time of solenoid. Loses 1 second every minute.
// 1/2 sec extra to compress brick via main Cyl (default 500ms) //custom function declarations
bool lowPressure(); //function to read pressure sensor bool resetSelected(); // //bool quarterSelected(); // bool halfSelected(); // bool threequarterSelected(); // bool fullSelected(); //
//Global variables
unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. unsigned long previousMillis = 0; //time measurement for expansion
void setup() {
Serial.begin(9600); //initialize pin I/O Inputs and turn everything off to avoid startup glitches
pinMode(PRESSURE_SENSOR, INPUT_PULLUP); pinMode(SELECTOR_HALF, INPUT_PULLUP); pinMode(SELECTOR_THREEQUARTER, INPUT_PULLUP); pinMode(SELECTOR_FULL, INPUT_PULLUP); pinMode(SOLENOID_RIGHT, OUTPUT); digitalWrite(SOLENOID_RIGHT, LOW); pinMode(SOLENOID_LEFT, OUTPUT); digitalWrite(SOLENOID_LEFT, LOW); pinMode(SOLENOID_DOWN, OUTPUT); digitalWrite(SOLENOID_DOWN, LOW); pinMode(SOLENOID_UP, OUTPUT); digitalWrite(SOLENOID_UP, LOW); Serial.begin(9600); // In case we need to use the serial monitor
}
void loop() { //MAIN + DRAWER CYLINDER BOUNCE TEST
//Debounce in loop and delay after one step by > delay to avoid timing issues
//-----------------------------------------------------UP- while (lowPressure() == true) {
digitalWrite(SOLENOID_UP, HIGH); } digitalWrite(SOLENOID_UP, LOW); //No delay after this like in manual code.
delay(TURNOFF_DELAY); // delay must be greater than the debounce in order for this to work;
//set debounce to 5 and delay to 6 //If this works, then test this with debounce in Bool
//-------------------------------------------------------DOWN while (lowPressure() == true) {
digitalWrite(SOLENOID_DOWN, HIGH); } digitalWrite(SOLENOID_DOWN, LOW);
delay(TURNOFF_DELAY); //----------------------------------------------------------------- LEFT while (lowPressure() == true) {
digitalWrite(SOLENOID_LEFT, HIGH); }
digitalWrite(SOLENOID_LEFT, LOW);
delay(TURNOFF_DELAY); //----------------------------------------------------------------- RIGHT while (lowPressure() == true) {
digitalWrite(SOLENOID_RIGHT, HIGH); } digitalWrite(SOLENOID_RIGHT, LOW);
delay(TURNOFF_DELAY);
}
//End of Loop bool lowPressure() { //custom function definitions
if (digitalRead(PRESSURE_SENSOR) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(PRESSURE_SENSOR) == HIGH) { return true; } else { return false; } } else { return false; }}
//reads selector - HIGH is false, LOW is true- SELECTOR_RESET, SELECTOR_QUARTER, SELECTOR_HALF, SELECTOR_3QUARTERS, SELECTOR_FULL, bool resetSelected() { if (quarterSelected() == false && threequarterSelected() == false && halfSelected() == false && fullSelected() == false) { return true; } else { return false; }}
bool quarterSelected() {
if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool halfSelected() { if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool threequarterSelected() { if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { return false; } else { return true; } } else { return true; }}
bool fullSelected() { if (digitalRead(SELECTOR_FULL) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_FULL) == HIGH) { return false; } else { return true; } } else { return true; }}
Manual Control Code
- Selection of 9, 10, 11, 12 for UDLR.
/* Open Source Ecology CEB Press v19.01 with Arduino Uno or Mega as controller of choice.
CC-BY-SA, GPLv3, and OSE License for Distributive Economics Use Mega to keep consistency with OSE D3D 3D Printer to minimize GVCS part count. Switches FET's HIGH/LOW to control two hydraulic solenoids, measures piston motion time relative to pressure sensor trigger, and repeats cycle while auto calibrating timing from previous cycles and startup positions.
Extension time is measured. Orientation of machine is such that cylinder retracts to the right. See sequence at http://bit.ly/2Hnuk6F
Faults should be self-resolving based on pressing sequence: pressure trigger reverses direction at fault point and no block results. There is one likely place for faults to occur: soil load into chamber.
Uses HiLetgo Relay Shield 5V 4 Channel for Arduino:
https://www.amazon.com/HiLetgo-Relay-Shield-Channel-Arduino/dp/B07F7Y55Z7/ref=sr_1_2?ie=UTF8&qid=1547696929&sr=8-2&keywords=hiletgo+relay+shield
Note pins must be trimmed flat under Relay 1 connector and must be insulated to prevent shorts.
Relay 1 is controlled by digital pin 7 Relay 2 is controlled by digital pin 6 Relay 3 is controlled by digital pin 5 Relay 4 is controlled by digital pin 4
A high written to a pin turns the relay ON A low written to a pin turns the relay OFF
Contributions by: Abe Anderson http://opensourceecology.org/wiki/AbeAnd_Log Marcin Jakubowski http://opensourceecology.org/wiki/Marcin_Log
Unfamiliar with code structures? See https://www.arduino.cc/en/Reference/HomePage */
//defines to make it easier for non-coders to make adjustments for troubleshooting and custom changes
- define SOLENOID_UP 7 //Extension. See pin mapping above.
- define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
- define SOLENOID_LEFT 5 //Extension.
- define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
- define PRESSURE_SENSOR 13 //Needs pins adjacent to get 8-pin dupont housing for both selector and sensor
- define SELECTOR_QUARTER 12 //Second 8-pin Dupont housing for the solenoids
//Reset is the shutdown/initialization procedure. All procedures are selected by
- define SELECTOR_HALF 11 //the WHILE function. QUARTER to FULL refers to brick thickness.
- define SELECTOR_THREEQUARTER 10 //Secondary cylinder timing is measured only.
- define SELECTOR_FULL 9 //Primary cylinder thickness setting is based on secondary cylinder motion.
- define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
- define DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
//custom function declarations
bool lowPressure(); //function to read pressure sensor bool resetSelected(); // bool quarterSelected(); // bool halfSelected(); // bool threequarterSelected(); // bool fullSelected(); //
//Global variables
unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. unsigned long previousMillis = 0; //time measurement for expansion
void setup() {
//initialize pin I/O Inputs and turn everything off to avoid startup glitches
pinMode(PRESSURE_SENSOR, INPUT_PULLUP); pinMode(SELECTOR_QUARTER, INPUT_PULLUP); pinMode(SELECTOR_HALF, INPUT_PULLUP); pinMode(SELECTOR_THREEQUARTER, INPUT_PULLUP); pinMode(SELECTOR_FULL, INPUT_PULLUP); pinMode(SOLENOID_RIGHT, OUTPUT); digitalWrite(SOLENOID_RIGHT, LOW); pinMode(SOLENOID_LEFT, OUTPUT); digitalWrite(SOLENOID_LEFT, LOW); pinMode(SOLENOID_DOWN, OUTPUT); digitalWrite(SOLENOID_DOWN, LOW); pinMode(SOLENOID_UP, OUTPUT); digitalWrite(SOLENOID_UP, LOW);
}
void loop() {
//Step 0 Reset/Initialize - Brick pressing sequence - http://bit.ly/2Hnuk6F
while (fullSelected() == true) { // happens when 9 is selected
digitalWrite(SOLENOID_UP, HIGH);
}
digitalWrite(SOLENOID_UP, LOW);
while (threequarterSelected() == true) { //10 selected
digitalWrite(SOLENOID_DOWN, HIGH); } digitalWrite(SOLENOID_DOWN, LOW);
while (halfSelected() == true) { // happens when 11 is selected
digitalWrite(SOLENOID_LEFT, HIGH);
}
digitalWrite(SOLENOID_LEFT, LOW);
while (quarterSelected() == true) { //12 selected
digitalWrite(SOLENOID_RIGHT, HIGH); } digitalWrite(SOLENOID_RIGHT, LOW);
} //end of loop
//custom function definitions //reads pressure sensor state HIGH is false and LOW is true
bool lowPressure() {
if (digitalRead(PRESSURE_SENSOR) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(PRESSURE_SENSOR) == HIGH) { return true; } else { return false; } } else { return false; }}
//reads selector - HIGH is false, LOW is true- SELECTOR_RESET, SELECTOR_QUARTER, SELECTOR_HALF, SELECTOR_3QUARTERS, SELECTOR_FULL, bool resetSelected() { if (threequarterSelected() == false && halfSelected() == false && fullSelected() == false) { return true; } else { return false; }}
bool quarterSelected() { if (digitalRead(SELECTOR_QUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_QUARTER) == HIGH) { return false; } else { return true; } } else { return true; }}
bool halfSelected() { if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool threequarterSelected() { if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { return false; } else { return true; } } else { return true; }}
bool fullSelected() { if (digitalRead(SELECTOR_FULL) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_FULL) == HIGH) { return false; } else { return true; } } else { return true; }}
Drawer Cylinder Bounce Test
Hint: Note: this goes randomly between up and down - looks like debounce is not working but it's really bad code. Same for main cylinder bounce. The missing piece here is a delay. It turns out that a delay with delay time > debounce delay must be used between switching of solenoid for switching to work properly. The reason for this is that as soon as the debounced measurement happens, the pressure sensor will be high for the duration of solenoid switching time. That time is 20-60 ms for on, and 20-40 ms for off [1]. Thus a delay >40 ms should be used after a cylinder is turned off to begin motion in the other direction. Delay(50) should work at every turnoff to address the turnoff time. Otherwise, the pressure is still high when beginning the next motion, which throws the logic off
- define SOLENOID_UP 7 //Extension. See pin mapping above.
- define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
- define SOLENOID_LEFT 5 //Extension.
- define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
- define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
- define SELECTOR_RESET 12 //Activated when nothing is selected.
- define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
- define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
- define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
- define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
- define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
- define DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
//custom function declarations
bool lowPressure(); //function to read pressure sensor bool resetSelected(); // //bool quarterSelected(); // bool halfSelected(); // bool threequarterSelected(); // bool fullSelected(); //
//Global variables
unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. unsigned long previousMillis = 0; //time measurement for expansion
void setup() {
//initialize pin I/O Inputs and turn everything off to avoid startup glitches
pinMode(PRESSURE_SENSOR, INPUT_PULLUP); pinMode(SELECTOR_HALF, INPUT_PULLUP); pinMode(SELECTOR_THREEQUARTER, INPUT_PULLUP); pinMode(SELECTOR_FULL, INPUT_PULLUP); pinMode(SOLENOID_RIGHT, OUTPUT); digitalWrite(SOLENOID_RIGHT, LOW); pinMode(SOLENOID_LEFT, OUTPUT); digitalWrite(SOLENOID_LEFT, LOW); pinMode(SOLENOID_DOWN, OUTPUT); digitalWrite(SOLENOID_DOWN, LOW); pinMode(SOLENOID_UP, OUTPUT); digitalWrite(SOLENOID_UP, LOW); Serial.begin(9600); // In case we need to use the serial monitor
}
void loop() { //DRAWER CYLINDER BOUNCE CODE
while (lowPressure() == true) {
digitalWrite(SOLENOID_RIGHT, HIGH);
}
digitalWrite(SOLENOID_RIGHT, LOW); //No delay after this like in manual code.
while (lowPressure() == true) {
digitalWrite(SOLENOID_LEFT, HIGH); //Reversal is immediate
}
digitalWrite(SOLENOID_LEFT, LOW);
}
//End of Loop bool lowPressure() { //custom function definitions
if (digitalRead(PRESSURE_SENSOR) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(PRESSURE_SENSOR) == HIGH) { return true; } else { return false; } } else { return false; }}
//reads selector - HIGH is false, LOW is true- SELECTOR_RESET, SELECTOR_QUARTER, SELECTOR_HALF, SELECTOR_3QUARTERS, SELECTOR_FULL, bool resetSelected() { if (quarterSelected() == false && threequarterSelected() == false && halfSelected() == false && fullSelected() == false) { return true; } else { return false; }}
bool quarterSelected() {
if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool halfSelected() { if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool threequarterSelected() { if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { return false; } else { return true; } } else { return true; }}
bool fullSelected() { if (digitalRead(SELECTOR_FULL) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_FULL) == HIGH) { return false; } else { return true; } } else { return true; }}
Main Cylinder Bounce Testing
- Testing bounce of main cylinder on real machine.
- Code works using manual switching, where the state goes randomly between up and down as a result of manual switching. This is because it is not possible to do an instantaneous switch by hand; microprocessor looping is faster.
//defines to make it easier for non-coders to make adjustments for troubleshooting and custom changes
- define SOLENOID_UP 7 //Extension. See pin mapping above.
- define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
- define SOLENOID_LEFT 5 //Extension.
- define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
- define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
- define SELECTOR_RESET 12 //Activated when nothing is selected.
- define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
- define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
- define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
- define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
- define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
- define DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
//custom function declarations
bool lowPressure(); //function to read pressure sensor bool resetSelected(); // //bool quarterSelected(); // bool halfSelected(); // bool threequarterSelected(); // bool fullSelected(); //
//Global variables
unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. unsigned long previousMillis = 0; //time measurement for expansion
void setup() {
//initialize pin I/O Inputs and turn everything off to avoid startup glitches
pinMode(PRESSURE_SENSOR, INPUT_PULLUP); pinMode(SELECTOR_HALF, INPUT_PULLUP); pinMode(SELECTOR_THREEQUARTER, INPUT_PULLUP); pinMode(SELECTOR_FULL, INPUT_PULLUP); pinMode(SOLENOID_RIGHT, OUTPUT); digitalWrite(SOLENOID_RIGHT, LOW); pinMode(SOLENOID_LEFT, OUTPUT); digitalWrite(SOLENOID_LEFT, LOW); pinMode(SOLENOID_DOWN, OUTPUT); digitalWrite(SOLENOID_DOWN, LOW); pinMode(SOLENOID_UP, OUTPUT); digitalWrite(SOLENOID_UP, LOW); Serial.begin(9600); // In case we need to use the serial monitor
}
void loop() {
while (lowPressure() == true) {
digitalWrite(SOLENOID_DOWN, HIGH);
}
digitalWrite(SOLENOID_DOWN, LOW); //No delay after this like in manual code.
while (lowPressure() == true) {
digitalWrite(SOLENOID_UP, HIGH); //Reversal is immediate
}
digitalWrite(SOLENOID_UP, LOW);
}
//End of Loop bool lowPressure() { //custom function definitions
if (digitalRead(PRESSURE_SENSOR) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(PRESSURE_SENSOR) == HIGH) { return true; } else { return false; } } else { return false; }}
//reads selector - HIGH is false, LOW is true- SELECTOR_RESET, SELECTOR_QUARTER, SELECTOR_HALF, SELECTOR_3QUARTERS, SELECTOR_FULL, bool resetSelected() { if (quarterSelected() == false && threequarterSelected() == false && halfSelected() == false && fullSelected() == false) { return true; } else { return false; }}
bool quarterSelected() {
if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool halfSelected() { if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool threequarterSelected() { if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { return false; } else { return true; } } else { return true; }}
bool fullSelected() { if (digitalRead(SELECTOR_FULL) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_FULL) == HIGH) { return false; } else { return true; } } else { return true; }}
Nonselection Procedure
- We are using a four position switch for 1/4, 1/2, 3/4, and full bricks
- Switch has positions 0-4 - or 5 total
- The switch happens to have an off position (0) which does not make any connections
- We can use the non-selection condition to do a fifth pseudo-selection - the reset procedure
- Code for resetSelected (nonselection of all choices) is: if (quarterSelected() == false && halfSelected == false && threequarterSelected == false && fullSelected == false ) {}
- Testing this:
//defines to make it easier for non-coders to make adjustments for troubleshooting and custom changes
- define SOLENOID_UP 4 //Extension. See pin mapping above.
- define SOLENOID_DOWN 5 //swap these pin numbers for wire inversion
- define SOLENOID_LEFT 6 //Extension.
- define SOLENOID_RIGHT 7 //swap these pin numbers for wire inversion
- define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
- define SELECTOR_RESET 12 //Activated when nothing is selected.
- define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
- define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
- define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
- define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
- define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
- define DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
//custom function declarations
bool lowPressure(); //function to read pressure sensor bool resetSelected(); // //bool quarterSelected(); // bool halfSelected(); // bool threequarterSelected(); // bool fullSelected(); //
//Global variables
unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. unsigned long previousMillis = 0; //time measurement for expansion
void setup() {
//initialize pin I/O Inputs and turn everything off to avoid startup glitches
pinMode(PRESSURE_SENSOR, INPUT_PULLUP); pinMode(SELECTOR_HALF, INPUT_PULLUP); pinMode(SELECTOR_THREEQUARTER, INPUT_PULLUP); pinMode(SELECTOR_FULL, INPUT_PULLUP); pinMode(SOLENOID_RIGHT, OUTPUT); digitalWrite(SOLENOID_RIGHT, LOW); pinMode(SOLENOID_LEFT, OUTPUT); digitalWrite(SOLENOID_LEFT, LOW); pinMode(SOLENOID_DOWN, OUTPUT); digitalWrite(SOLENOID_DOWN, LOW); pinMode(SOLENOID_UP, OUTPUT); digitalWrite(SOLENOID_UP, LOW); Serial.begin(9600);
}
void loop() {
Serial.println(resetSelected());
while (resetSelected() == true) { //goes only up to trigger of pressure, no matter how long pressure trigger is
digitalWrite(SOLENOID_UP, HIGH);
}
digitalWrite(SOLENOID_UP, LOW); // delay(2000); //gives time to release trigger (momentary switch should be used to make this easier) //reads pressure sensor state HIGH is false and LOW is true
}
//End of Loop bool lowPressure() { //custom function definitions
if (digitalRead(PRESSURE_SENSOR) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(PRESSURE_SENSOR) == HIGH) { return true; } else { return false; } } else { return false; }}
//reads selector - HIGH is false, LOW is true- SELECTOR_RESET, SELECTOR_QUARTER, SELECTOR_HALF, SELECTOR_3QUARTERS, SELECTOR_FULL, bool resetSelected() { if (quarterSelected() == false && threequarterSelected() == false && halfSelected() == false && fullSelected() == false) { return true; } else { return false; }}
bool quarterSelected() {
if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool halfSelected() { if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool threequarterSelected() { if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { return false; } else { return true; } } else { return true; }}
bool fullSelected() { if (digitalRead(SELECTOR_FULL) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_FULL) == HIGH) { return false; } else { return true; } } else { return true; }}
Action Based on Selection of 2 Options
- Same as above, but trigger an action by while (quarterSelected() == true && halfSelected == true) {}
- This works.
while (fullSelected() == true && threequarterSelected() == true) {
digitalWrite(SOLENOID_UP, HIGH);
}
digitalWrite(SOLENOID_UP, LOW); //
}
Cylinder Bounce Code Simulation
To test solenoids sensing pressure and reversing solenoids upon pressure trigger, ma nually simulated logic is the following. This simulates a cylinder bouncing between full retraction and full extension, which are both high pressure trigger points.
- Turn solenoid UP on - while pressure low
- Turn solenoid UP off - as soon as pressure triggers, and move solenoid Down.
- Trigger is done manually simply by switching pin 13 on (touching jumper from ground to 13)
- The opposite action occurs until the pressure is triggered again. Length of pressure trigger doesn't matter.
- If the pressure trigger is longer that 2 seconds, then we don't know where in the program loop we are and either UP or DOWN will occur
- In real life, the solenoid should be off momentarily, and next step should follow immediately
Code:
//defines to make it easier for non-coders to make adjustments for troubleshooting and custom changes
//defines to make it easier for non-coders to make adjustments for troubleshooting and custom changes
- define SOLENOID_UP 4 //Extension. See pin mapping above.
- define SOLENOID_DOWN 5 //swap these pin numbers for wire inversion
- define SOLENOID_LEFT 6 //Extension.
- define SOLENOID_RIGHT 7 //swap these pin numbers for wire inversion
- define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
- define SELECTOR_RESET 12 //Activated when nothing is selected.
- define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
- define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
- define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
- define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
- define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
- define DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
//custom function declarations
bool lowPressure(); //function to read pressure sensor bool resetSelected(); // //bool quarterSelected(); // bool halfSelected(); // bool threequarterSelected(); // bool fullSelected(); //
//Global variables
unsigned long drawerExtTime = 0; //Time measurement for calibrating motion. unsigned long previousMillis = 0; //time measurement for expansion
void setup() {
//initialize pin I/O Inputs and turn everything off to avoid startup glitches
pinMode(PRESSURE_SENSOR, INPUT_PULLUP); pinMode(SELECTOR_HALF, INPUT_PULLUP); pinMode(SELECTOR_THREEQUARTER, INPUT_PULLUP); pinMode(SELECTOR_FULL, INPUT_PULLUP); pinMode(SOLENOID_RIGHT, OUTPUT); digitalWrite(SOLENOID_RIGHT, LOW); pinMode(SOLENOID_LEFT, OUTPUT); digitalWrite(SOLENOID_LEFT, LOW); pinMode(SOLENOID_DOWN, OUTPUT); digitalWrite(SOLENOID_DOWN, LOW); pinMode(SOLENOID_UP, OUTPUT); digitalWrite(SOLENOID_UP, LOW);
}
void loop() {
while (lowPressure() == true) { //goes only up to trigger of pressure, no matter how long pressure trigger is
digitalWrite(SOLENOID_UP, HIGH);
}
digitalWrite(SOLENOID_UP, LOW); // delay(2000); //gives time to release trigger (momentary switch should be used to make this easier)
while (lowPressure() == true) { //moves in reverse direction until next trigger
digitalWrite(SOLENOID_DOWN, HIGH);
}
digitalWrite(SOLENOID_DOWN, LOW); //moves on to next step, next step should continue until next trigger delay(2000);
} //reads pressure sensor state HIGH is false and LOW is true
//End of Loop
bool lowPressure() { //custom function definitions
if (digitalRead(PRESSURE_SENSOR) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(PRESSURE_SENSOR) == HIGH) { return true; } else { return false; } } else { return false; }}
//reads selector - HIGH is false, LOW is true- SELECTOR_RESET, SELECTOR_QUARTER, SELECTOR_HALF, SELECTOR_3QUARTERS, SELECTOR_FULL, bool resetSelected() { if (threequarterSelected() == false && halfSelected() == false && fullSelected() == false) { return true; } else { return false; }}
bool halfSelected() { if (digitalRead(SELECTOR_HALF) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_HALF) == HIGH) { return false; } else { return true; } } else { return true; }}
bool threequarterSelected() { if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_THREEQUARTER) == HIGH) { return false; } else { return true; } } else { return true; }}
bool fullSelected() { if (digitalRead(SELECTOR_FULL) == HIGH) { delay(PRESSURE_SENSOR_DEBOUNCE); if (digitalRead(SELECTOR_FULL) == HIGH) { return false; } else { return true; } } else { return true; }}
Debouncing
References, libraries and methods for debouncing different types of switching noise.
- https://www.arduino.cc/en/tutorial/debounce
- https://forum.arduino.cc/index.php?topic=266132.60
- https://hackaday.com/2010/11/09/debounce-code-one-post-to-rule-them-all/
- https://hackaday.com/2015/12/09/embed-with-elliot-debounce-your-noisy-buttons-part-i/
- https://hackaday.com/2015/12/10/embed-with-elliot-debounce-your-noisy-buttons-part-ii/