Gradually increasing and decreasing pneumatic pressure

I am using Arduino Mega, MOS Module, Air valve FA0520D and FA0520E. I would like to gradually increase and decrease the pneumatic pressure. There is a 6DoF IMU (MPU 6050) to measure the angular deformation for extension and contraction of the actuated object. I found that while pressure increases, IMU can read almost the exact amount of angular increment. But when the pressure decreases, IMU cannot show the right amount. There is always a lag although the actuated object reaches to its initial position after contraction. This is the part of the code I wrote:

void loop() {
  float t_cycle = 100; // total period of PWM in ms
  float ki = 0.1; 
  float t1i = ki*t_cycle; 
  float t2i = (1-ki)*t_cycle;  

  float kr = 0.35; 
  float t1r = kr*t_cycle; 
  float t2r = (1-kr)*t_cycle;  
}
// for increasing the pressure:
              digitalWrite(5,LOW); //keep 2 way valve off
              digitalWrite(3,HIGH); //keep 3 way valve on
              delay(t1i); 
              digitalWrite(3,LOW); //keep 3 way valve off
              delay(t2i); 
              digitalWrite(3,HIGH); //keep 3 way valve on

// for decreasing the pressure:
              digitalWrite(3,LOW); //keep 3 way valve off
              digitalWrite(5,HIGH); //keep 2 way valve on
              delay(t1r); 
              digitalWrite(5,LOW); //keep 2 way valve off
              delay(t2r); 
              digitalWrite(5,HIGH); //keep 2 way valve on

Can anyone please help? Is it the problem of the code or the problem of IMU? And how can I fix it? The following figure could be helpful to understand my problem. The left one is the result of the IMU reading and the right one is the result obtained by a camera:

From your code, it would appear that the pressure is vented from the actuated device through the 2 way valve. Are you certain it is being opened? If open, does it have enough capacity to vent in the time required? Can you provide a sketch of how all the valves and the activated device are connected?

1 Like

Here is the circuit diagram. I apologize for the quality.

Could you please check the above diagram and let me know what goes wrong?

Your system looks reasonable and I don't understand why the imu data does not match the camera position. If the camera is correct, then the issue is not with the valve and venting, but with the response of the IMU.

It would help if you posted the code reading the IMU as well as driving the valves.

Can you calibrate the IMU for angular position?

One observation: For different Ki and Kr values (thus different amounts of delay), the IMU reading changes. For ki=0.1 and kr=0.35, I have obtained comparatively less amount of lag ( while decreasing the pressure, the IMU reading does not reach zero). If I put kr=0.25, the lag is more ( i.e. the plot starts from 0 and ends at -15, forming a cascade shape). Although the actuated object reaches its initial position, just IMU could not read it. What could be the possible reason?

If you just position what the IMU is reading at the endpoints of the motion, does the IMU read the angles correctly?

Can You give some figures to the pressure being used? Pressure when incressing? Is there any spring involved?
Is the 1 bar atmospheric pressure an actor on the scene?

1 Like

You show a 2 way valve with only 1 air connection. Do we assume that the second connection is an exhaust vent to atmosphere? Why aren't you using manual throttle valves for flow rate control?

1 Like

Yes, the air is exhausted to the atmosphere by the two-way valve. Any suggestion?

No spring is involved here. The pressure is measured by the MPRLS pressure sensor. The range of pressure is 14 to 22 Psi. This is the part of the code where I increase and decrease the pressure:

  tcaselect(0);
  float pressure_hPa_0 = mpr0.readPressure();
  float pressure_PSI_0 = pressure_hPa_0 / 68.947572932;
  float pressure_Set = 22; 

  //Geting the IMUs reading when the object is pressurized
  while (abs(pressure_PSI_0 - pressure_Set) > 0.25 && pressure_PSI_0 <pressure_Set ){
              tcaselect(0);
              pressure_hPa_0 = mpr0.readPressure();
              pressure_PSI_0 = pressure_hPa_0 / 68.947572932;
              Serial.print("Pressurized");
              Serial.print("\t");
             

              timer = millis();
              Serial.print(timer*0.001);
              Serial.print("\t");
              tcaselect(3);
              mpu.update();
              Serial.print(mpu.getAngleX());
              Serial.print("\t");
              
              tcaselect(4);
              mpu1.update();
              Serial.print(mpu1.getAngleX());
              Serial.print("\t");
              
              tcaselect(5);
              mpu2.update();
              Serial.print(mpu2.getAngleX());
              Serial.print("\t");
           
              tcaselect(6);
              mpu3.update();
              Serial.print(mpu3.getAngleX());
              Serial.print("\t");
              
              Serial.print(pressure_hPa_0 / 68.947572932);
              Serial.print("\t");
              
              Serial.println(' ');
              
              digitalWrite(5,LOW);
              digitalWrite(3,HIGH);
              delay(t1i); 
              digitalWrite(3,LOW);
              delay(t2i); 
              digitalWrite(3,HIGH);
             }

Similarly, for decreasing the pressure.
Any suggestion?

Can you please provide your complete code.
Please provide links to any libraries used.

I would focus on the IMU and the reading of the tilt angle. If the camera records the correct angles, then the pressure side must be correct.

How is the IMU physically connected to the rotating piece?
Are you certain that the rotated angle is all in the one plane you are measuring?

Can you answer my previous question about if the IMU measures the correct angle when the rotating piece is fixed at the min and max rotation.

1 Like

Here is the full code:

#include "Wire.h"
#include <MPU6050_light.h>
#define TCAADDR 0x70

#include "Adafruit_MPRLS.h"
#include <Wire.h>

#define RESET_PIN  -1  // set to any GPIO pin # to hard-reset on begin()
#define EOC_PIN    -1  // set to any GPIO pin to read end-of-conversion by pin

Adafruit_MPRLS mpr0 = Adafruit_MPRLS(RESET_PIN, EOC_PIN);

unsigned long startMillis;
unsigned long runTime = 1000; // in milliseconds
unsigned long timer;
void tcaselect(uint8_t i) {
  if (i > 7) return;

  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}


MPU6050 mpu2(Wire);
MPU6050 mpu3(Wire);


void setup() {
  while (!Serial);
  delay(1000);

  Wire.begin();
  Serial.begin(115200);
  
  Serial.println("\nTCAScanner ready!"); 
    
  for (uint8_t t=0; t<7; t++) { 
     tcaselect(t);
     Serial.print("TCA Port #"); Serial.println(t);

     for (uint8_t addr = 0; addr<=127; addr++) {
       if (addr == TCAADDR) continue;

       Wire.beginTransmission(addr);
       if (!Wire.endTransmission()) {
         Serial.print("Found I2C 0x");  Serial.println(addr,HEX);
        }
      }
    }
    Serial.println("\ndone");
  


  pinMode(3,OUTPUT); // 1st 3 way valve
 
  pinMode(5,OUTPUT); // 1st 2 way valve
  
  
  digitalWrite(3,LOW);
  digitalWrite(5,HIGH);
  
  delay(15000);

  digitalWrite(5,LOW);
  
  
  Serial.begin(115200);
  
  tcaselect(0);
  Serial.println("MPRLS0 Simple Test");
  if (! mpr0.begin()) {
    Serial.println("Failed to communicate with MPRLS0 sensor, check wiring?");
    while (1) {
      delay(10);
    }
  }
  Serial.println("Found MPRLS0 sensor");



  tcaselect(5);
  byte status2 = mpu2.begin();
  Serial.print(F("MPU6050 status: "));
  Serial.println(status2);
  while(status2!=0){ } // stop everything if could not connect to MPU6050
  
  Serial.println(F("Calculating offsets, do not move MPU6050"));
  delay(1000);
  mpu2.calcOffsets(); // gyro and accelero
  Serial.println("Done!\n");

  tcaselect(6);
  byte status3 = mpu3.begin();
  Serial.print(F("MPU6050 status: "));
  Serial.println(status3);
  while(status3!=0){ } // stop everything if could not connect to MPU6050
  
  Serial.println(F("Calculating offsets, do not move MPU6050"));
  delay(1000);
  mpu3.calcOffsets(); // gyro and accelero
  Serial.println("Done!\n");
  }

void loop() {
  float t_cycle = 100; // total period of PWM in ms
  float ki = 0.1; 
  float t1i = ki*t_cycle; 
  float t2i = (1-ki)*t_cycle; 

  float kr = 0.35; 
  float t1r = kr*t_cycle; 
  float t2r = (1-kr)*t_cycle;  
  
  
  //Geting the IMUs reading when the object is stationary 
  startMillis = millis(); // mark time
  while (millis() - startMillis < runTime)
  {
   timer = millis();
   Serial.print(timer*0.001);
   Serial.print("\t");

   tcaselect(5);
   mpu2.update();           
   Serial.print(mpu2.getAngleX());           
   Serial.print("\t");
   tcaselect(6);
   mpu3.update();           
   Serial.print(mpu3.getAngleX());           
   Serial.print("\t");
  Serial.print("\n");           
  }
  tcaselect(0);
  float pressure_hPa_0 = mpr0.readPressure();
  float pressure_PSI_0 = pressure_hPa_0 / 68.947572932;
  float pressure_Set = 22; 

  //Geting the IMUs reading when the object is pressurized
  while (abs(pressure_PSI_0 - pressure_Set) > 0.25 && pressure_PSI_0 <pressure_Set ){
              tcaselect(0);
              pressure_hPa_0 = mpr0.readPressure();
              pressure_PSI_0 = pressure_hPa_0 / 68.947572932;
              Serial.print("Pressurized");
              Serial.print("\t");
             

              timer = millis();
              Serial.print(timer*0.001);
              Serial.print("\t");

              
              tcaselect(5);
              mpu2.update();
              Serial.print(mpu2.getAngleX());
              Serial.print("\t");
           
              tcaselect(6);
              mpu3.update();
              Serial.print(mpu3.getAngleX());
              Serial.print("\t");
              
              Serial.print(pressure_hPa_0 / 68.947572932);
              Serial.print("\t");
              
              Serial.println(' ');
              
              digitalWrite(5,LOW);
              digitalWrite(3,HIGH);
              delay(t1i); 
              digitalWrite(3,LOW);
              delay(t2i); 
              digitalWrite(3,HIGH);
             }
   //Geting the IMUs reading when the object is stationary after being pressurized
   startMillis = millis(); // mark time
  while (millis() - startMillis < runTime)
  {Serial.print("MCP");
   Serial.print("\t");
   timer = millis();
   Serial.print(timer*0.001);
   Serial.print("\t");

   tcaselect(5);
   mpu2.update();           
   Serial.print(mpu2.getAngleX());           
   Serial.print("\t");
   tcaselect(6);
   mpu3.update();           
   Serial.print(mpu3.getAngleX());           
   Serial.print("\t");
   Serial.print("\n");           
  } 
  //Geting the IMUs reading when the object is being de-pressurized        
   pressure_Set = 14;
   while (abs(pressure_PSI_0 - pressure_Set) > 0.25 && pressure_PSI_0 >pressure_Set){
               tcaselect(0);
               pressure_hPa_0 = mpr0.readPressure();
               pressure_PSI_0 = pressure_hPa_0 / 68.947572932;
               Serial.print("De-Pressurized");
               Serial.print("\t");
              
              timer = millis();
              Serial.print(timer*0.001);
              Serial.print("\t");

             
              tcaselect(5);
              mpu2.update();
              Serial.print(mpu2.getAngleX());
              Serial.print("\t");
              
              tcaselect(6);
              mpu3.update();
              Serial.print(mpu3.getAngleX());
              Serial.print("\t");

              Serial.print(pressure_hPa_0 / 68.947572932);
              Serial.print("\t");
              
              Serial.println(' ');
              
              digitalWrite(3,LOW);
              digitalWrite(5,HIGH); 
              delay(t1r);
              digitalWrite(5,LOW);
              delay(t2r); 
              digitalWrite(5,HIGH);         
   }
   //Geting the IMUs reading when the object is stationary after being depressurized
   startMillis = millis(); // mark time
  while (millis() - startMillis < runTime)
  {
   timer = millis();
   Serial.print(timer*0.001);
   Serial.print("\t");

   tcaselect(5);
   mpu2.update();           
   Serial.print(mpu2.getAngleX());           
   Serial.print("\t");
   tcaselect(6);
   mpu3.update();           
   Serial.print(mpu3.getAngleX());           
   Serial.print("\t");
   Serial.print("\n");           
  }
}

I tied the IMU with the actuated object with Velcro. The IMU is in its vertical position. The rotation is along the x-axis. The actuated object is a human finger shaped object made with silicone. So, when actuated, it bends like a human finger. Considering 3 joints in our fingers, I am taking 2 IMUs readings attached in 2 links of each joints. My original post's figure is for the last joint's scenario, when 1st 2 joints are rigid.

I am not sure I understand your last question correctly. But, I don't think the angle measurement by the IMU is correct. When it is pressurized, it bends for 6 degrees. When it is depressurized, it reaches to its original position. So, the IMU should show that it reaches to 0 degrees. I can see it actually reaches to its initial position, just IMU is not reading it properly.

IMU source code : MPU6050_light/src at master · rfetick/MPU6050_light · GitHub

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.