CEB Press/Manufacturing Instructions/Controller Box/Source Code


 * /v1.0
 * /v1.01
 * /v1.01 Annotated
 * /v5.15.10

2 Sensor Control Code
The code as of 4.22.10 is shown below. This code operates with two position-sensor-magnets, where the concept was to avoid using 3 magnets for simplicity. This code works by calibrating timing between the initial and mid position of a given sensor, such that the completion of the stroke is attained by timing. It turns out in practice that at high machine speed, over 15 gpm, the timing is not robust and errors on the order of up to 1/2" in positioning may occur sporadically. Because of this reason, the code was updated to 3 position-sensor-magnets for each cylinder, such that timing is avoided.

Code - Liberator Beta v2.0
//Notes: In every WHILE loop, shut off solenoids explicitly after //escaping from the loop. Orientation is defined by machine user //facing the control panel. 2 magnets (sensor actuators) are used //for main cylinder, 4 magnets for soil drawer, and 2 magnets are //are used for soil grate shaker. Copyright April 2010, Creative //Commons CC-BY-SA-compatible OSE License, by Marcin Jakubowski, //Ph.D., for OSE. This code and other documentation is available //at the Open+Pario project management site under the CEB Project, //under Documents - Liberator Beta 2.0 Control Code, //http://openpario.net/projects/OSE? int val; int val2; unsigned long startcounter; unsigned long counter; unsigned long startcounter2; unsigned long counter2; //0. Initialization. void setup{ Serial.begin(9600); pinMode(19,INPUT);//Digital 19 is Analog 5. pinMode(18,INPUT);//Digital 18 is Analog 4. pinMode(3,OUTPUT);//Pins 3 and 5 are up and down motion, pinMode(6,OUTPUT);//respectively. pinMode(9,OUTPUT);//Pins 9 and 10 are right and left. pinMode(10,OUTPUT); counter=0; counter2=0; val=analogRead(5);//Read the sensor.\ val2=analogRead(4); Serial.println("Main cylinder state:"); Serial.println(val); Serial.println("Drawer cylinder state:"); Serial.println(val2); //1. Move big cylinder down all way to identify bottom point (+). while (val<500){ digitalWrite(3, LOW);//Move main cylinder down. digitalWrite(6, HIGH);//Control solenoids in pairs to keep track. val=analogRead(5); Serial.println("moving down"); Serial.println(val); // delay(500); }  digitalWrite(3, LOW);//Turn solenoids off. digitalWrite(6, LOW); Serial.println("Waiting for approval..."); // delay(4000); //2. Move drawer left - all way to brick ejection position. val2=analogRead(4); Serial.println("Drawer State reading:"); Serial.println(val2); // Serial.println("Waiting 5 seconds for next step..."); // delay(5000); while(val2 < 500){ digitalWrite(9, LOW);//Move left. digitalWrite(10, HIGH);//Solenoids are controlled in pairs. val2=analogRead(4); Serial.println("Moving left"); Serial.println(val2); //Need to keep reading state of sensor. };//stop upon reaching left (magnet at LEFT induces + state) digitalWrite(9, LOW); digitalWrite(10, LOW); val2=analogRead(4); Serial.println("Finished left. Drawer state:"); Serial.println(val2); //   Serial.println("WAITING FOR APPROVAL..."); // delay(4000); //3. Calibrate main cylinder/eject. val=analogRead(5); startcounter=millis; while(val > 500){ digitalWrite(3, HIGH);//Start upward motion. digitalWrite(6, LOW); Serial.println("Time during motion (ms):"); Serial.println(millis-startcounter); val=analogRead(5); };    digitalWrite(3, LOW);//stop motion digitalWrite(6, LOW); counter=millis-startcounter; Serial.println("Time after leaving loop:"); Serial.println(counter); val=analogRead(5); Serial.println("Finished calibrations. Main cylinder state:"); Serial.println(val); Serial.println("Waiting for approval."); //  delay(40000); //4. Calibrate drawer val=analogRead(4); startcounter2=millis; while(val2 > 500){ digitalWrite(9, HIGH);//Start upward motion. digitalWrite(10, LOW); Serial.println("Time during motion (ms):"); Serial.println(millis-startcounter2); val2=analogRead(4); }; //   digitalWrite(9, LOW);//stop motion //   digitalWrite(10, LOW); counter2=millis-startcounter2; Serial.println("Time after leaving loop:"); Serial.println(counter2); val=analogRead(4); Serial.println("Finished calibration 2. Drawer cylinder state:"); Serial.println(val2); //5. Continue moving for the calibrated duration // digitalWrite(9, HIGH); // digitalWrite(10, LOW); delay(counter2); digitalWrite(9, LOW); digitalWrite(10, LOW); Serial.println("Moved into soil loading position."); } //**************************** END OF INITIALIZATION void loop{ //8. Lower main cylinder. val=analogRead(5); Serial.println("Main cylinder state:"); Serial.println(val); while(val < 500){;//Sensor is low at start. digitalWrite(3, LOW);//Move main cylinder down. digitalWrite(6, HIGH);//Control solenoids in pairs to keep track. val=analogRead(5); Serial.println("moving down"); Serial.println(val); };//stop upon reaching bottom (magnet at bottom induces high state) digitalWrite(3,LOW); digitalWrite(6,LOW); //9. Close compression chamber. Needs timing. digitalWrite(9, LOW);//Move left. digitalWrite(10, HIGH);//Solenoids are controlled in pairs. Serial.println("Moving left"); delay(counter2*.84);//.75 is the exact factor digitalWrite(9, LOW);//Stopping by timing only. digitalWrite(10, LOW); Serial.println("Finished left. Drawer state:"); Serial.println(val2); //10. Begin pressing cycle with main cylinder, and then release // pressure by moving 1/2 sec down. digitalWrite(3, HIGH);// Start cycle, and time motion. digitalWrite(6, LOW);// Start from bottom cylinder position. delay (counter/2);//Go up half way. Time counted in milliseconds. Serial.println("PRESSING...UP TO TIME OF (ms):"); Serial.println(counter/2); digitalWrite(3, LOW);// Stop motion. digitalWrite(6, LOW); val=analogRead(5); Serial.println("Main cylinder State:"); Serial.println(val); //******************************************************  RELEASE CYCLE digitalWrite(3, LOW);//Release, by time. digitalWrite(6, HIGH);// delay (counter/100); Serial.println("Releasing..."); digitalWrite(3, LOW);// Stop motion. digitalWrite(6, LOW); val=analogRead(5); Serial.println("State:"); Serial.println(val); //11. Open compression chamber by moving drawer left. val2=analogRead(4); Serial.println("Drawer State reading:"); Serial.println(val2); // Serial.println("Waiting 5 seconds for next step..."); // delay(5000); while(val2 < 500){ digitalWrite(9, LOW);//Move left. digitalWrite(10, HIGH);//Solenoids are controlled in pairs. val2=analogRead(4); Serial.println("Moving left"); Serial.println(val2); //Need to keep reading state of sensor. };//stop upon reaching left (magnet at LEFT induces + state) digitalWrite(9, LOW); digitalWrite(10, LOW); val2=analogRead(4); Serial.println("Finished left. Drawer state:"); Serial.println(val2); //12. Push brick up. val=analogRead(5); while (val > 500){;//Complete motion up to sensor. digitalWrite(3, HIGH);//Complete up motion. digitalWrite(6, LOW); val=analogRead(5); Serial.println("Pushing brick up..."); Serial.println("Main cylinder State:"); Serial.println(val); }  digitalWrite(3, LOW); digitalWrite(6, LOW); //13. Eject brick from machine by moving drawer to the right. val=analogRead(4); startcounter2=millis; while(val2 > 500){ digitalWrite(9, HIGH);//Start upward motion. digitalWrite(10, LOW); Serial.println("Time during motion (ms):"); Serial.println(millis-startcounter2); val2=analogRead(4); }; //   digitalWrite(9, LOW);//stop motion //   digitalWrite(10, LOW); counter2=millis-startcounter2; Serial.println("Time after leaving loop:"); Serial.println(counter2); val=analogRead(4); Serial.println("Finished calibration 2. Drawer cylinder state:"); Serial.println(val2); //14. Continue moving for the calibrated duration (into loading pos.) // digitalWrite(9, HIGH); // digitalWrite(10, LOW); delay(counter2); digitalWrite(9, LOW); digitalWrite(10, LOW); Serial.println("Moved into soil loading position."); };

Secondary Cylinder
This code is for the secondary (drawer) cylinder. This code may be used for calibration or troubleshooting purposes. This code zeroes the drawer cylinder by moving it to the far left (direction is determined by user facing the machine control panel). This code cycles between the 3 positions. You may use this code for determining positioning replicability at various speeds of the machine.

Correct zeroing occurs in most cases. If the machine was turned off in the far-right-position, this code does not work properly. This is an artifact of the control mechanism, and cannot be avoided easily. The user needs to reset the machine if this happens. To determine if the machine is zeroed properly, observe the position of the drawer during the initial 5 second rest (after zeroing occurred). If the machine did not reset properly, reset it manually via the reset button on the Arduino shield or by cycling the power to the controller.

Beginning of code follows: -

//Notes: In every WHILE loop, shut off solenoids explicitly after //escaping from the loop. Orientation is defined by machine user //facing the control panel. 3 magnets (sensor actuators) are used //for main cylinder, 3 magnets for soil drawer, and 2 magnets are //are used for soil grate shaker. Copyright April 2010, Creative //Commons CC-BY-SA-compatible Open Source Ecology (OSE) License, //by Marcin Jakubowski, Ph.D., for OSE. This code and other //documentation is available at the Open+Pario project management //site under the CEB Project, under Documents - Liberator Beta 2.0 //Control Code, http://openpario.net/projects/OSE int val; int val2; int val3; unsigned long startcounter; unsigned long counter; unsigned long startcounter2; unsigned long counter2; //0. Initialization. void setup{ Serial.begin(9600); pinMode(19,INPUT);//Digital 19 is Analog 5. pinMode(18,INPUT);//Digital 18 is Analog 4. pinMode(17,INPUT);//Digital 17 is Analog 3. pinMode(3,OUTPUT);//Pins 3 and 6 are up and down motion, pinMode(6,OUTPUT);//respectively. pinMode(9,OUTPUT);//Pins 9 and 10 are right and left, pinMode(10,OUTPUT);//respectively. pinMode(11,OUTPUT);//Hopper shaker motor. counter=0; counter2=0; val=analogRead(5);//Read the sensor.\ val2=analogRead(4); Serial.println("Main cylinder state:"); Serial.println(val); Serial.println("Drawer cylinder state:"); Serial.println(val2); //1. Move sec cylinder Left 1/2 sec digitalWrite(10,HIGH); delay(400); digitalWrite(10,LOW); //2. If +, then stop, else keep moving left until +. while (analogRead(4) < 500){ digitalWrite(10, HIGH); } digitalWrite(10, LOW); //3. Wait 6 seconds. If stopped and not zeroed, turn controller on and off. delay(6000); } //**************************** END OF INITIALIZATION void loop{ //L1. Move right to - while(analogRead(4) > 500){ digitalWrite(9, HIGH);//Move right. } //L2. Continue moving right to +. Wait a second. while(analogRead(4) < 500){ } digitalWrite(9, LOW); delay(1000); //L3. Move left till -. Wait a second. digitalWrite(10, HIGH); while (analogRead(4) >500){ } digitalWrite(10, LOW); delay(1000); //L4. Move left till +. Wait a second. digitalWrite(10, HIGH); while (analogRead(4) < 500){ } digitalWrite(10, LOW); delay(1000); }//final loop closure.

Main Cylinder
Note: Position-sensor-magnets induce high and low latch-states in the Hall effect sensor. The magnet positions are ordered: (1), high at the bottom, (2), low in the middle, and (3), high at top. The states are read by the Arduino controller analog inputs. The bottom, mid, and top positions are determined by the magnet locations.

The testing code for the main cylinder actives the following procedure:
 * 1) Moves main cylinder down for 1/2 second, and keeps moving down to the bottom if it's not at the bottom after the 1/2 second.
 * 2) Waits 6 seconds for user-determination of correct zeroing procedure. User cycles power to controller if not zeroed properly at this time.
 * 3) Calibrates the timing of the main cylinder for the purpose of determining the duration of the release stroke. To do this, code moves the main cylinder all the way to the top, and then measures the time to return all the way to the bottom. This calibration depends on the hydraulic fluid flow, hence it is needed for efficient operation under different power source conditions.
 * 4) Repetitive cycling begins:
 * 5) Move up to middle, stop.
 * 6) Release pressure. \
 * 7) Move up to top, stop.
 * 8) Move down to middle, stop.
 * 9) Move down to bottom, stop.

Control Code with Simultaneous Cylinder Motion
Code annotation for testv3 code - full code, including simultaneous cylinder motion, for the Liberator Beta v2.0 open source CEB press.

Definitions

 * 1) Initial or zero position for main cylinder- bottom of stroke.
 * 2) Initial or zero position for main cylinder - leftmost position
 * 3) Left and right - as observed with user facing the control box.
 * 4) Bottom and top - with respect to the ground.
 * 5) Terminal position - Top for main cylinder, rightmost for secondary cylinder.
 * 6) C2 - secondary cylinder.
 * 7) C1 - main cylinder.

Initialization
Move main and secondary cylinder down 1/2 second. Allows one to assess correct zeroing more quickly (in case both cylinders are in 'initialization failure' position, defined as the position of each respective cylinder in which initialization fails.

Zero the cylinders (allows you to determine position, otherwise one has to compensate with further motion for not knowing this information.

Eject soil from chamber with main cylinder, push soil out of way with secondary cylinder. This avoids potential problems asssociated with unbalanced stress on press foot.

The result of initialization is that the secondary cylinder is in the initial position, and main cylinder is the terminal position.

Loop
In order to effect simultaneous cylinder motion, we divide the motion into segments as a general strategy. Each segment consists of the span between two position-sensor-magnets, with the beginning at one sensor and the end at the next sensor. There are 3 magnets for each cylinder, ordered as +, -, and +, where the + or - corresponds to the state that the magnet induces in the sensor circuit. This means that the initial and terminal positions are defined as +, and the middle position is defined as -.

The simultaneous cylinder motion is framed by the motion of the secondary cylinder. In practical terms, this means that it is determined within a while loop for the secondary cylinder. Within this while loop, the code determines the location of the main cylinder.

The motion is continuous through 2 magnets for both the main and secondary cylinders. To determine the terminal position, the cylinders go through a toggle at the midpoint of motion. This toggle is set high (toggle = 1), so that: the toggle combined with the cylinder detector reaching + determines the terminal stroke position.

Summary
The code consists essentially of these steps:

INITIALIZATION


 * 1) Move main and secondary cylinder down 1/2 second.
 * 2) Zero secondary and main cylinders.
 * 3) Eject soil from chamber with main cylinder.
 * 4) With secondary cylinder - push soil out of way, stop in closed compression chamber position, and re-initialize.
 * 5) Calibrate main cylinder (move from top to bottom and obtain time).
 * 6) Move main cylinder to terminal position.

At this point, secondary cylinder is in initial position and main cylinder is in terminal position.

LOOP

#Detect C1 and C2. #If C1 goes low, then toggle1=1 #If C1 is toggled and goes high, stop C1. #Detect C1 and C2. #If C1 goes low, then toggle1=1 #If C1 is toggled and goes high, stop C1. #Use a for loop that escapes upon toggle and terminal position: #for i=1 to 2 #read state of C1                   #if state is low then toggle and set i to 1 #if it's toggled and state is high then i=2 (escapes loop)
 * 1) Move C1 right.
 * 2) Wait 0.2 seconds
 * 3) Move C2 down. This marks the beginning of simultaneous motion.
 * 4) Detect C2. Set toggle2 to 0.
 * 5) While C2 is high (motion from left to middle):
 * 1) While C2 is low (motion from middle to right):
 * 1) Stop C2
 * 2) C1 may not be toggled (may still be moving).
 * 1) Stop C1. This ends the soil loading cycle
 * 2) Wait 0.2 seconds.
 * 3) Close drawer by moving left.
 * 4) Press.
 * 5) Release.
 * 6) Open drawer.
 * 7) Eject. This completes cycle.

Code
See ceb control code 5.15.10