For an upcoming project I needed a pneumatic ram with a closed loop control system so I could position it accurately. Didn’t have the budget for an off the shelf solution, so I bodged one together with an ardunio, a couple air solenoid valves, and a pair of potentiometers.
How it works is one potentiometer is the target while the other is mounted to the ram. The arduino code compares the two, figures out the direction that the ram needs to move to match them up, it then cycles the solenoid valves on and off accordingly. Once the values match, it turns both valves on, more or less locking the ram in place. The target pot can also be replaced with any analog input.
For the rest of the hardware I am using a pair of clippard mouse valves and an arduino UNO. The valves work well, 10ms response time and very low power consumption you need a transistor and diode to hook them up to the Arduino, look up the solenoid tutorial. The ram is a double acting one. Also It works best if you have an adjustable inline flow restrictor on the incoming air stream. It allows you to fine tune the rate of fill so the servo is less twitchy.
The big secret on this was to mount a wheel onto the knob of one potentiometer, this wheel has a string wrapped around it that is tied to the end of the ram. When the ram extends, it pulls the string, spins the pot and tada you now have the rams position. You need a second string with a spring attached to roll the wheel back and keep everything taut. To work out the diameter of the wheel just take your rams stroke and multiply by PI to get your radius. Keep in mind that your pot might not turn 360 degrees, mine was 270 so factor that into your calculations. Best to make it a bit oversize anyway, worst case is that you lose some resolution if its too large, if its too small the ram will destroy the pot or break the string when it runs out of room. In this case the wheel is made of birch plywood, with a groove turned into it on the lathe to guide the string.
Circuit diagram and breadboard:
I drew these up with Fritzing, which is an awesome open source electrical diagram program. (I have no connections to the project, just a happy downloader)
Pneumatic servo Arduino code:
nt targetPin = A2;// select the input pin for distance sensor or potentiometer
int actualPin = A0;// select the input pin for the potentiometer attached to the ram
int outSol = 12; //digital pin with the solenoid that forces the ram out
int inSol = 11; //digital pin with the solenoid that forces the ram in
int actualRange = 838; // range of the potentiometer attached to the ram -test it with serial out)
int targetRange = 650;
int pollDelay = 60; //how fast to cycle, figgure out how fast your valves will cycle, I am using 5-10ms valves
int fuzzyFactor = 100; //how close the two values need to match
int targetValue = 0; // variable to store the value coming from the sensor
int targetValueLow = 0;
int targetValueHigh = 0;
int actualValue = 0;
void setup() { // declare the solenoid pins as outputs
pinMode(outSol, OUTPUT);
pinMode(inSol, OUTPUT);
Serial.begin(9600);}
void loop() {
pollDelay = random(80,120); //generate a random delay between sensor checks
// read the values from the sensors:
targetValue = analogRead(targetPin);
actualValue = analogRead(actualPin);
actualValue = map(actualValue, 0, actualRange, 0, 1023); //remap to whole range
targetValue = map(targetValue, 0, targetRange, 1023, 0); //remap to whole range and invert
Serial.println(actualValue); //write stuff to the serial for debugging
Serial.println(targetValue);
//Set up the value range thats acceptable
targetValueLow = targetValue – fuzzyFactor;
targetValueHigh = targetValue + fuzzyFactor;
if (targetValue < fuzzyFactor) //if the goal is full retract lock the ram there { digitalWrite (outSol, LOW); digitalWrite (inSol, HIGH); Serial.println (“Case 1”); } else if (targetValue > (1023 – fuzzyFactor)) {//if goal is full extend lock the ram there
digitalWrite (outSol, HIGH);
digitalWrite (inSol, LOW);
Serial.println (“Case 2”); }
else if (actualValue > targetValueLow && actualValue < targetValueHigh){ //if the ram is close enough to the goal apply air to both sides digitalWrite (outSol, HIGH); digitalWrite (inSol, HIGH); Serial.println (“Case 3”); } else if (actualValue < targetValue){ //if its less than the target extend digitalWrite (outSol, HIGH); digitalWrite (inSol, LOW); Serial.println (“Case 4”); } else { //if more than target retract digitalWrite (outSol, LOW); digitalWrite (inSol, HIGH); Serial.println (“Case 5”);} delay(pollDelay); }
For more detail: David Bynoe works in progress