CEB Press Control Code v19.01

From Open Source Ecology
Jump to: navigation, search

Code

https://github.com/OpenSourceEcology/OSE_CEB_Press_v19.01

Notes

10" Cylinder Code

HintLightbulb.png Hint: Tested and works. Set up for selection of 10" (full stroke), 8", 6", and 4" stoke of main cylindent. Equivalent to 5, 4, 3, and 2" bricks.

Here is what serial monitor should look like:

SerialmonitorCEB.png

  1. define SOLENOID_UP 7 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 5 //Extension.
  4. 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

  1. define PRESSURE_SENSOR 13 //Needs pins adjacent to get 6-pin dupont housing for both selector and sensor
  2. define SELECTOR_FULL 12 //Primary cylinder thickness setting is based on secondary cylinder motion.
  3. define SELECTOR_THREEQUARTER 11 //Secondary cylinder timing is measured only.
  4. define SELECTOR_HALF 10 // QUARTER to FULL refers to brick thickness.
  5. 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.

  1. define PRESSURE_SENSOR_DEBOUNCE 30 //milliseconds to delay for pressure sensor debounce
  2. define TURNOFF_DELAY 50 //Addresses 40 ms turnoff time of solenoid. Loses 1 second every minute.
  3. define PRESS_DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
  4. 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() {

 //*****************************************************************************************************************
                                  //Step 0 - Reset - Only in ResetSelected Selection. Brick pressing sequence - http://bit.ly/2Hnuk6F
                                  //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.
                                  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 (resetSelected() == true) {
                                  Serial.println("Reset is Selected. Resetting by moving drawer right...");    
 while (lowPressure() == true) {  
   digitalWrite(SOLENOID_RIGHT, HIGH); //Move drawer cylinder right
 }
   digitalWrite(SOLENOID_RIGHT, LOW);
   delay(TEST_DELAY);             //***************************************************************
   delay(TURNOFF_DELAY);          //***************************************************************
                                  Serial.println("Reset is Selected.  Moving up...");
 while (lowPressure() == true) {            
   digitalWrite(SOLENOID_UP, HIGH);    //Move main cylinder up.
 }
   digitalWrite(SOLENOID_UP, LOW);
                                  Serial.println("Reset complete. Waiting for main loop...");
 delay(5000);                     //Delays a comfortable time, enough for person to select brick thickness                  
 }

//***************************************************************************************************************

                                  //STEP 1A - CALIBRATION ************************** 
 if (resetSelected() == false) {  //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);
                                  Serial.println("Calibration - finished moving drawer left.");
   delay(TEST_DELAY);             //***************************************************************
   delay(TURNOFF_DELAY);          //***************************************************************    
   drawerExtTime = millis() - previousMillis;
                                  Serial.print("Calibration - measured time of drawer motion is ");
                                  Serial.print(drawerExtTime);
                                  Serial.println(" ms. Moving main cylinder down...");
 }

//**************************************************************************************************

                                  //STEP 1B - SOIL LOADING ****************************************
                                  //Goes through different selections as in http://bit.ly/2RYpQYa
 if (fullSelected() == true) {    Serial.println("Tall 5 inch brick thickness is selected.");
   while (lowPressure() == true) {
     digitalWrite(SOLENOID_DOWN, HIGH);
     }
 digitalWrite(SOLENOID_DOWN, LOW);
                                 
 }
 if (threequarterSelected() == true) { Serial.println("Regular (4") brick thickness is selected . ");
   digitalWrite(SOLENOID_DOWN, HIGH);
   delay(drawerExtTime*1.7);      //Thickness multiplier based on cylinder diameters
   digitalWrite(SOLENOID_DOWN, LOW);
                                 
 }
 
 if (halfSelected() == true) {         Serial.println("3/4" brick thickness is selected. "); 
   digitalWrite(SOLENOID_DOWN, HIGH);
   delay(drawerExtTime*1.3);      //Thickness multiplier based on cylinder diameters
   digitalWrite(SOLENOID_DOWN, LOW);
                                  

   }
 if (quarterSelected() == true) {       Serial.println("1/2 brick thickness is selected. ");       
   digitalWrite(SOLENOID_DOWN, HIGH);       
   delay(drawerExtTime*0.9);      //Thickness multiplier based on cylinder diameters
   digitalWrite(SOLENOID_DOWN, LOW);
                                  

 }
   delay(TURNOFF_DELAY);           //***************************************************************
   delay(TEST_DELAY);              //***************************************************************
                                    Serial.println("Soil loaded - main cylinder moved down.");
                                    Serial.print("Drawer Extension Time is ");
                                    Serial.println(drawerExtTime);
                                    Serial.print("Closing chamber for ");
                                    Serial.print(drawerExtTime * 0.75 * 0.58);
                                    Serial.println(" ms.");

//*****************************************************************************************************************************

                                //STEP 2 - COMPRESSION CHAMBER CLOSURE********************************************************
 if (resetSelected() == false) {
   digitalWrite(SOLENOID_RIGHT, HIGH);
   delay(drawerExtTime * 0.75 * 0.58);       //HalfWay is the half-way multiplier 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() == false) {
   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() == false) {
    digitalWrite(SOLENOID_DOWN, HIGH);
    delay(50);
    digitalWrite(SOLENOID_DOWN, LOW);
   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) {
   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;
 }

}

Real Pressing, with Selection of Brick Thicknesses - final testing

HintLightbulb.png Hint: This was tested manually keeping TEST_DELAY at 700. Real run - TEST_DELAY should be 30.

  1. define SOLENOID_UP 7 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 5 //Extension.
  4. 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

  1. define PRESSURE_SENSOR 13 //Needs pins adjacent to get 6-pin dupont housing for both selector and sensor
  2. define SELECTOR_FULL 12 //Primary cylinder thickness setting is based on secondary cylinder motion.
  3. define SELECTOR_THREEQUARTER 11 //Secondary cylinder timing is measured only.
  4. define SELECTOR_HALF 10 // QUARTER to FULL refers to brick thickness.
  5. 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.

  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. define TURNOFF_DELAY 50 //Addresses 40 ms turnoff time of solenoid. Loses 1 second every minute.
  3. define PRESS_DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
  4. define TEST_DELAY 700 //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() {

 //*****************************************************************************************************************
                                  //Step 0 - Reset - Only in ResetSelected Selection. Brick pressing sequence - http://bit.ly/2Hnuk6F
                                  //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.
                                  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 (resetSelected() == true) {
                                  Serial.println("Reset is Selected. Resetting by moving drawer right...");    
 while (lowPressure() == true) {  
   digitalWrite(SOLENOID_RIGHT, HIGH); //Move drawer cylinder right
 }
   digitalWrite(SOLENOID_RIGHT, LOW);
   delay(TEST_DELAY);             //***************************************************************
   delay(TURNOFF_DELAY);          //***************************************************************
                                  Serial.println("Reset is Selected.  Moving up...");
 while (lowPressure() == true) {            
   digitalWrite(SOLENOID_UP, HIGH);    //Move main cylinder up.
 }
   digitalWrite(SOLENOID_UP, LOW);
                                  Serial.println("Reset complete. Waiting for main loop...");
 delay(5000);                     //Delays a comfortable time, enough for person to select brick thickness                  
 }

//***************************************************************************************************************

                                  //STEP 1A - CALIBRATION ************************** 
 if (resetSelected() == false) {  //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);
                                  Serial.println("Calibration - finished moving drawer left.");
   delay(TEST_DELAY);             //***************************************************************
   delay(TURNOFF_DELAY);          //***************************************************************    
   drawerExtTime = millis() - previousMillis;
                                  Serial.print("Calibration - measured time of drawer motion is ");
                                  Serial.print(drawerExtTime);
                                  Serial.println(" ms. Moving main cylinder down...");
 }

//**************************************************************************************************

                                  //STEP 1B - SOIL LOADING ****************************************
                                  //Goes through different selections as in http://bit.ly/2RYpQYa
 if (fullSelected() == true) {    Serial.println("Full brick thickness is selected.");
   while (lowPressure() == true) {
     digitalWrite(SOLENOID_DOWN, HIGH);
     }
 digitalWrite(SOLENOID_DOWN, LOW);
                                 
 }
 if (threequarterSelected() == true) { Serial.println("3/4 brick thickness is selected. ");
   digitalWrite(SOLENOID_DOWN, HIGH);
   delay(drawerExtTime*1.3);      //Thickness multiplier of 1.3 based on cylinder diameters
   digitalWrite(SOLENOID_DOWN, LOW);
                                 
 }
 
 if (halfSelected() == true) {         Serial.println("Half brick thickness is selected. "); 
   digitalWrite(SOLENOID_DOWN, HIGH);
   delay(drawerExtTime*0.9);      //Thickness multiplier of 0.9 based on cylinder diameters
   digitalWrite(SOLENOID_DOWN, LOW);
                                  

   }
 if (quarterSelected() == true) {       Serial.println("1/4 brick thickness is selected. ");       
   digitalWrite(SOLENOID_DOWN, HIGH);       
   delay(drawerExtTime*0.5);      //Thickness multiplier of 0.5 based on cylinder diameters
   digitalWrite(SOLENOID_DOWN, LOW);
                                  

 }
   delay(TURNOFF_DELAY);           //***************************************************************
   delay(TEST_DELAY);              //***************************************************************
                                    Serial.println("Soil loaded - main cylinder moved down.");
                                    Serial.print("Drawer Extension Time is ");
                                    Serial.println(drawerExtTime);
                                    Serial.print("Closing chamber for ");
                                    Serial.print(drawerExtTime * 0.75 * 0.58);
                                    Serial.println(" ms.");

//*****************************************************************************************************************************

                                //STEP 2 - COMPRESSION CHAMBER CLOSURE********************************************************
 if (resetSelected() == false) {
   digitalWrite(SOLENOID_RIGHT, HIGH);
   delay(drawerExtTime * 0.75 * 0.58);       //HalfWay is the half-way multiplier 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() == false) {
   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() == false) {
   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) {
   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;
 }

}

Real Testing, Full Bricks

HintLightbulb.png 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: CEBtesting.png.

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.

  1. define SOLENOID_UP 7 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 5 //Extension.
  4. 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

  1. define PRESSURE_SENSOR 13 //Needs pins adjacent to get 6-pin dupont housing for both selector and sensor
  2. define SELECTOR_FULL 12 //Primary cylinder thickness setting is based on secondary cylinder motion.
  3. define SELECTOR_THREEQUARTER 11 //Secondary cylinder timing is measured only.
  4. define SELECTOR_HALF 10 // QUARTER to FULL refers to brick thickness.
  5. 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.

  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. define TURNOFF_DELAY 50 //Addresses 40 ms turnoff time of solenoid. Loses 1 second every minute.
  3. define PRESS_DELAY 500 // 1/2 sec extra to compress brick via main Cyl (default 500ms)
  4. 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

HintLightbulb.png 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

  1. define SOLENOID_UP 7 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 5 //Extension.
  4. define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
  1. define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
                               //Activated when nothing is selected.
  1. define SELECTOR_QUARTER 12 //Reset is the shutdown/initialization procedure. All procedures are selected by
  2. define SELECTOR_HALF 11 //the WHILE function. QUARTER to FULL refers to brick thickness.
  3. define SELECTOR_THREEQUARTER 10 //Secondary cylinder timing is measured only.
  4. define SELECTOR_FULL 9 //Primary cylinder thickness setting is based on secondary cylinder motion.
  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. 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

  1. define SOLENOID_UP 7 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 5 //Extension.
  4. define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
  1. define PRESSURE_SENSOR 13 //Needs pins adjacent to get 8-pin dupont housing for both selector and sensor
  2. define SELECTOR_QUARTER 12 //Second 8-pin Dupont housing for the solenoids
                             //Reset is the shutdown/initialization procedure. All procedures are selected by
  1. define SELECTOR_HALF 11 //the WHILE function. QUARTER to FULL refers to brick thickness.
  2. define SELECTOR_THREEQUARTER 10 //Secondary cylinder timing is measured only.
  3. define SELECTOR_FULL 9 //Primary cylinder thickness setting is based on secondary cylinder motion.
  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. 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

HintLightbulb.png 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

  1. define SOLENOID_UP 7 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 5 //Extension.
  4. define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
  1. define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
  2. define SELECTOR_RESET 12 //Activated when nothing is selected.
  3. define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
  4. define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
  5. define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
  6. define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. 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


  1. define SOLENOID_UP 7 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 6 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 5 //Extension.
  4. define SOLENOID_RIGHT 4 //swap these pin numbers for wire inversion
  1. define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
  2. define SELECTOR_RESET 12 //Activated when nothing is selected.
  3. define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
  4. define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
  5. define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
  6. define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. 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


  1. define SOLENOID_UP 4 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 5 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 6 //Extension.
  4. define SOLENOID_RIGHT 7 //swap these pin numbers for wire inversion
  1. define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
  2. define SELECTOR_RESET 12 //Activated when nothing is selected.
  3. define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
  4. define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
  5. define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
  6. define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. 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

  1. define SOLENOID_UP 4 //Extension. See pin mapping above.
  2. define SOLENOID_DOWN 5 //swap these pin numbers for wire inversion
  3. define SOLENOID_LEFT 6 //Extension.
  4. define SOLENOID_RIGHT 7 //swap these pin numbers for wire inversion
  1. define PRESSURE_SENSOR 13 //Needs pins adjacent so only 1 dupont connector is used
  2. define SELECTOR_RESET 12 //Activated when nothing is selected.
  3. define SELECTOR_QUARTER 11 //Reset is the shutdown/initialization procedure. All procedures are selected by
  4. define SELECTOR_HALF 10 //the WHILE function. QUARTER to FULL refers to brick thickness.
  5. define SELECTOR_THREEQUARTER 9 //Secondary cylinder timing is measured only.
  6. define SELECTOR_FULL 8 //Primary cylinder thickness setting is based on secondary cylinder motion.
  1. define PRESSURE_SENSOR_DEBOUNCE 20 //milliseconds to delay for pressure sensor debounce
  2. 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.

Links