oscillation in pneumatic system

Hello Everyone and thank you. I have a project that uses a joystick to control some pneumatic cylinders. My problem is that I get oscillations of the cylinders around the desired position without stopping at the desired position sometimes. (see graph) I have tried PID loops which were really complicated and could not get to work. I am a noobie and would love any suggestions to try. Thank you.

/* This program uses an Arduino Uno and compares operator input from a control potentiometers on a joystick 
   vs. positional potentiometers on air cylinders to actuate relays that move valves that move the pneumatic cylinders.
*/

//---------------------constants (don't change)---------------------------


const byte ESWITCHPIN = 2;
const byte PORTPOTPIN = A1;
const byte JOYWHEELPIN = A2;
const byte RELAYPIN7 = 8;
const byte RELAYPIN3 = 12;
const byte RELAYPIN4 = 13;


//-------------------------variables (will change)---------------------

int PortPot = 0;
int PotDiff = 0;
int JoyWheel = 0;
unsigned long previousMillis = 0;

//-----------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  pinMode(ESWITCHPIN, INPUT); //estop switch
  pinMode(RELAYPIN3, OUTPUT);//relay#3
  pinMode(RELAYPIN4, OUTPUT);//relay#4
  pinMode(RELAYPIN7, OUTPUT);//relay#7
}

//================================================================================

void loop() {

  digitalRead(ESWITCHPIN);
  while (digitalRead(ESWITCHPIN) == HIGH) {
    digitalWrite(RELAYPIN7, LOW);
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= 30) {
      previousMillis = currentMillis;
      updatePots();
      updateSolenoids();
    }
  }
  digitalWrite(RELAYPIN7, HIGH);
}
//==================================================================================

void updatePots() {

  analogRead(PORTPOTPIN);
  PortPot = analogRead(PORTPOTPIN); //Port cylinder potentiometer
  delay(2);
  JoyWheel = analogRead(JOYWHEELPIN); //Joystick wheel potentiometer
  delay(2);

  PortPot = map(PortPot, 215, 916, 0, 500);
  JoyWheel = map(JoyWheel, 1, 1023, 0, 500);

  PotDiff = (PortPot - JoyWheel);
  Serial.print(JoyWheel);
  Serial.print(",");
  Serial.println(PortPot);
}

//===================================================================================================

void updateSolenoids() {

  if (PotDiff >= 30) {
    digitalWrite(RELAYPIN3, HIGH);
    digitalWrite(RELAYPIN4, LOW);
  }

  else if (PotDiff <= -30) {
    digitalWrite(RELAYPIN3, LOW);
    digitalWrite(RELAYPIN4, HIGH);
  }

  else {
    digitalWrite(RELAYPIN3, HIGH);
    digitalWrite(RELAYPIN4, HIGH);
  }
}

Untitled 1.pdf (37.2 KB)

Please explain your theory about why and how that code should work.

Not at sure at all what that request means but...the pots on the cylinders are read, mapped and then compared to the desired position of the mapped joystick. If the position of the cylinders are off the relays are energized to let air into the pneumatic cylinders to move the cylinders in the desired direction of the joystick.

relays are not something you can control with PID.

there is a device called a pilot postioner. it is a chain and a spring as the feedback
it has a seat over an orifice at the signal goes to move more, it does the feed back to move the correct amount.
what pneumatics have is a thing we call stiction like friction, but sticky.
it takes X to un-stick, but if you need 1/2x then X will move too far.

OK, I'll try again.

(1) What, actually, does setting a relay pin HIGH or LOW do?
(2) Where do the magic numbers 215, 916 and 500 come from?
(2) Why were differences of 30 and -30 chosen?
(3) Why should this control scheme NOT oscillate? What is to prevent a cylinder from overshooting a desired position, if its control can be only on or off?

In fact, PID is not any more complicated than what you are trying to do right now. But as mentioned above, you can't control a relay with PID.

Welcome to the fun world of discrete control systems :slight_smile:

Increase your thresholds (-30 and 30) until it's stable, then we can start to optimize on the steady state error.

By the way, the type of controller you have in your mind here is called a 3-Point-Controller.
That's the keyword you might need to find instructions on how to optimize those.

You have come into of the little discussed parts of a control loop. the drive and driven parts or the final or control elements.
Consider a relay/solenoid to be a digital device. the fastest pulse will deliver 1 digit.
another way, you relay/solenoid, working at it's fastest will deliver 1 unit of air.

1 unit would be the volume allowed by the diameter of the orifice and the differential pressure of the supply and the chamber of the actuator.

your control can be said to be with a resolution of 1 unit, +/-1 unit. that is just theory.
assume you can drive a solenoid from open to close in 1/10th of one second
your pressure differential and orifice will allow the displacement of 1 cu cm of air
1 cu cm of air will move your actuator 1mm. that would be the theoretical limit of one pulse.
all these are fictional numbers for discussion.

if you need to put in 10 units of pressure to get the device to move. And 9 are needed to equal the friction and 1 to overcome it.
You then have movement, but you might get a few units of movement if the friction is sufficient to slow the movement, or you may get all 10, plus the inertia of the mass of the piston and drive rod and thing driven.

A pneumatic piston in single action (spring return) has to overcome not only force of the spring, but also the friction.
Since the spring force will increase as it is compressed, and is balanced with the pressurized chamber the friction is the problem. The spring is part of the balance of operation.

The pilot postioner is what is used in commercial and industrial applications and eleminates the problems you are seeing.
however, if you want to try to operate with other devices, consider getting small orifices. 0.005" (red if plastic) or 0.007" (green)

You can have two drive solenoids. One for higher volume(faster) and one for precision.
0.005 on the pressure side to dive the unit, 0.007 on the bleed side to allow the spring to reposition.

As part of calibration, you should use a very low differential pressure to drive the piston and see at what point it moves and how far it moves. the inherent overshoot is resolved by a pilot postioner by a series of oscillations. once the sticktion has been overcome, the movement is free enough to oscillate the piston around the desired resting point, typically 5-7 oscillations occur in a fraction of a second, settling on the desired distance.

Since 100% of my experience was in pneumatics in commercial and industrial applications of fans and blowers. the loads were the drive arms and the blades of variable pitch fans, or the crank are and damper blades of a blower. Not moving objects like steering, etc. So my experice may be limited and not fully apply to your application.

WOW thank you everyone for the help it gives me some real direction. It is basically and extremely simple negative feedback loop but due to the compressibility of air everyrhing is sloppy so to speak. The mapping compares the joysticks pot maximum and minimum and compares to the pots on the air cylinders max and miins. The 30 to -30 is basically what is called the loops dead band and can be increase to a point where the system is stable but of cpurse the accuracy suffers. Higher pressures to move and lower pressures for final posit work great but the pneumatics to accomplish that are expensive. I am teying to write a loop that actually reverses the solenoid Before IT OVERSHOOTS (called feed forward loop)or at least pulse the air when the cylinder gets to rhe desired position

I am afraid what you are trying to do with software will not work if the air temperature changes much. Then you will have to monitor the temperature and make further adjustments.

Paul

the 30 to -30 is basically what is called the loops dead band

We know that. What I and others are trying to do is to get you to explain how you arrived at those constants, because those are a large part of the problem, along with the fact that you have provided no useful information about the system and its response characteristics.

This guide is a good place to start learning how to control your system.

const byte RELAYPIN7 = 8;

const byte RELAYPIN3 = 12;
const byte RELAYPIN4 = 13;

You have surpassed the usual idiocy of using numbers in variable names. Any time you have numbers in the variable names, you are doing it wrong. Either you should use an array or you should give them real names like relayExtendPin and relayRetractPin. The only time it's acceptable to have numbers is if that's the actual name of the physical thing. The A0 pin on the Arduino has "A0" written on the circuit board. That's its name. Do these relays actually have "7" "3" and "4" painted on them?

The while() loop is not entirely wrong but it would be better to make that an if() ... else ... Let the loop() loop.

  delay(2);

Why? The whole thing is limited to 30ms sample periods, so these delays do nothing except cut into the amount of things that your program can do in the 30ms period. There are some old recommendations to put delays or dummy reads between analogRead()'s but those are band-aids covering up other problems that are fixable. The original Arduino designers worked very hard to make analogRead() as bullet-proof as possible without wasting entire milliseconds.