I built this control box to cycle a piston in some of our assemblies at work. We had problems with rebuilt assemblies sticking after a few hours of cycling. The rebuilders couldn’t test this because they would have to manually cycled the piston back and forth many times to verify the functionality (time-consuming). This piston cycler is capable of automatically cycling a dual action cylinder at an adjustable rate, and enable the operator to pause the motion to make adjustments, and continue testing. The counter keeps track of the number of cycles for record keeping purposes. Here’s how I made it.
First I checked to see if there was anything like this in the market already. Most times buying a premade solution is cheaper and faster, provided it does everything you want. I found a few halloween prop controllers that could activate a relay based on a trigger input, but it was not adjustable and I could not add any other inputs or outputs.
I started by making a list of the devices operation and features, what types of components I was likely to need and how they would connect. Also some psuedo code to get the structure of the code down.
For projects such as these I usually start at its most basic functionality and then add complexity. Kind of like programming, you make sure the simple code works, then add complexity. If you start out trying to implement everything at once, you spend an enormous amount of time debugging it.
I needed a microcontroller to turn on a high current load (the solenoid) beyond it’s capability to drive, so I bread boarded a small circuit with a transistor, resistors, and diodes to allow the solenoid to be switched on and off. Since I selected a small 12v power supply (to match the solenoid and counter) I used a LM317 to drop the voltage down to 5V for the MCU.
I then coded a small arduino sketch to cycle the solenoid on and off for a set amount of time. Once the circuit was functional I moved the components to a bread board shield to reduce the assemblies’ footprint.
With a basic functioning circuit I began to increase its complexity by adding features:
- A potentiometer to change the rate at which the piston would cycle.
- Buttons and indicator lights to start and pause the program.
- A counter to measure cycles competed
- An enclosure
- Tubing connections
- Air pressure gauge
I created the panel layout and sized the enclosure by modeling the components and arranging them like tetris blocks.
Since I had access to a laser cutter I used that to make the panel cut outs and engrave the labels.
A few notes on cutting ABS with a laser cutter:
- ABS melts with the laser, rather than vaporizing like acrylic. So make sure you have air assist turned on to blow out the molten bits
- Taking multiple shallow passes instead of one deep one cuts down on flare ups, air assist also helps here
- The etch did not turn out so well, a CNC router would have worked better, but some sharpie made them stand out
- The cleaner cut is actually on the bottom of the piece. So put the finished side down if possible.
The coding was relatively simple. The hardest parts were implementing the pause button and getting the cycle delay time to update as soon as you changed the dial.
The first was solved with an if loop , where the buttons set the state of a boolean variable which controls the entering and exiting of the if loop (rather than the button directly).
if (program_state == LOW){ //program state low is the paused state
digitalWrite(led_start, LOW); //turn off start LED
analogWrite(led_pause, 100); //turn on pause LED, pwm to dim led slightly
program_state = digitalRead(button_start); //read start button to see if user wants to start cycling} else { //else case send the program to the cycle mode
PROGRAM GOES HERE
}
program_state = !digitalRead(button_pause); //read pause button tto see if user wants to pause cycling
The second was a little trickier. Originally I had used a potentiometer set the cycle time variable which then determined the time of a delay function. The problem with that was that if you set it to 10 sec, but then wanted to quickly change it to one second you had to wait the full 10 seconds before it would update. Also the pause button did not function during the delay. To get around this I used the millis function. Using millis, the code runs in its entirety many times a second, so it is always looking for updates to the delay time input or the pause button.
unsigned long currentMillis = millis();
digitalWrite(led_pause, LOW); //turn off pause LED
analogWrite(led_start, 100); //turn on start LED, pwm to dim led slightly
val = analogRead(potpin); //read value of potentiometer
delay_time = ((-0.0088*val)+10)*1000; //calculate the delay (1 to 10 seconds) in microseconds based on the pot reading (0 to 5Kohm)if(currentMillis – previousMillis > delay_time) {
previousMillis = currentMillis;if (valvestate == LOW)
valvestate = HIGH;
else{
valvestate = LOW;
digitalWrite(counter, HIGH); //increase counter by one
delay(10); //delay other wise counter will not catch the previous HIGH state
digitalWrite(counter, LOW);
}
digitalWrite(valvepin, valvestate); //turn valve on/off based on valvestate
}
I always like my projects to be serviceable, So I used a molex connectors to make the front panel and power supply removable.
Here’s a video of it in action:
Going forward I will add an additional input from the assemblies optical sensors that detect for a jammed piston and alert the operator.