Correction of a crooked cylinder

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Correction of a crooked cylinder

Post by bdellal »

Hi folks!
I got to work on a cool project. My programming skills are pretty basic. I would like to start off with a math problem and figure out if it is solvable the way I am planning to do it.

I am building a machine to straighten a crooked cylinder. That means the side and the middle line of the cylinder are not rectangular to the footprint.
To fix that, the cylinder will be clamped in a machine with 6 hydraulic pushers in a circle around it. Proximity sensors inside the cylinder will measure the distance between the sensor and the cylinder wall. Because these sensors are very expensive, I need to figure out, how many I actually need.

I made a quick sketch:

Image

So that is waht I thought:
-the origin of the sensors is my general origin
-four sensors, two on the upper and two on the lower side of the cylinder give me two circles, radius is known
-I calculate the origin of each circle, assuming they are on the same plane
-I calculate a vector out of these two pairs of values
-with the vector I need to figure out, which cylinder to activate, e.g. with an angle or so (C1 activated for angles 0-60deg, C2 for 61-120deg ...)
-dedicated cylinder pushes and bends cylinder in right direction
-start over till cylinder is in spec


For the prototype, I want to start off with an Arduino, my question is:
-Is it possible to easily translate that into C++?
-Is there a better way?

Thanks a lot for your feedback, I appreciate that!

Ben

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: Correction of a crooked cylinder

Post by adafruit_support_mike »

If you known the diameter of the pipe at the off-center end, you can find its center with two points at a 90 degree offset.

If you don't know the diameter, you can get that and the center with three points spaced around a circle. Any three will work, but putting them at 120 degree offsets from each other will make it easiest to get good accuracy.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Correction of a crooked cylinder

Post by bdellal »

I know the diameter. Shouldn't 180 deg also work? It is kinda hard to position the sensors 90 deg from each other.

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: Correction of a crooked cylinder

Post by adafruit_support_mike »

Assume the sensors are at 180 degrees to each other, and the center of the cylinder is 0.1" up and 0.1" to the right of where it should be:

- The left sensor will tell you the edge of the cylinder is 0.1" farther away than it should be.
- The right sensor will tell you the edge of the cylinder is 0.1" closer than it should be.

They both give you the same information (the 0.1" horizontal offset), so one is redundant. Neither one tells you the vertical offset though.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Correction of a crooked cylinder

Post by bdellal »

Thanks, I did not think about that. My setup does not allow me to put the sensors 90 deg apart. The best I can do is 108 degrees. Do you think it should still work okay?

User avatar
adafruit_support_bill
 
Posts: 88096
Joined: Sat Feb 07, 2009 10:11 am

Re: Correction of a crooked cylinder

Post by adafruit_support_bill »

If the diameter is known, you could make it work with 2 sensors at 108 degrees. But the math would not be quite as clean.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Correction of a crooked cylinder

Post by bdellal »

Yeah, I am stuck on a system of equations like that, if I set the origin in one of the sensors:

(a-x)^2 + y^2 = r^2
(c+x)^2 + (d-y)^2 = r^2

Would I have to solve this numerical?

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: Correction of a crooked cylinder

Post by adafruit_support_mike »

It's slightly easier if you think about finding the intersection of two circles.

The center of a circle is R distance away from any point on its edge, so if you know you have a point on the edge of the circle, you know the center will be R distance away from it. In other words, the center of circle-A will be somewhere on the edge of circle-B, where circle-B has radius R and is centered at the the point you know:

(x-x1)^2 + (y-y1)^2 = R^2 // point of contact at (x1, y1)

If you have another point of contact, you get another equation of the same form for circle-C:

(x-x2)^2 + (y-y2)^2 = R^2 // point of contact at (x2, y2)

The center of circle-A has to be on the edges of both circle-B and circle-C, so you want the points where the circles intersect:

(x-x1)^2 + (y-y1)^2 = (x-x2)^2 + (y-y2)^2

From there, you just turn the crank and solve for x and y. You'll get quadratic equations, so there are two possible (x,y) points that will work as solutions.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Correction of a crooked cylinder

Post by bdellal »

Thanks a lot for your advise! I managed to put the sensors 90deg apart.

I am planning on using 4 proximity sensors with an analog voltage output 0-10V, similar to these:
http://www.automationdirect.com/static/ ... alogam.pdf

Do you think, if I build a voltage divider and scale the voltage to 0-5V the arduino will be able to process the data accurately? I need a pretty accurate signal. Otherwise I will have to buy an additional Data acquisition system.

Thanks,
Ben

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: Correction of a crooked cylinder

Post by adafruit_support_mike »

You only need two sensors (one at zero degrees, one at 90 degrees). The other two opposite them will be redundant.

Normally a bit of redundancy isn't bad, but if the sensors cost more than $100 each you can save a lot of money by using only two.

A voltage divider should work to scale the signal down. From what I can see in the specs, those sensors have a range of 6mm and a resolution of 0.01mm, meaning you can trust about 600 different output values from them. An Arduino has a built-in 10-bit ADC (1024 distinct values) so you should be able to hit your resolution limit without needing any additional hardware.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Correction of a crooked cylinder

Post by bdellal »

Hi!
I dived in the code for this project a little bit and got stuck at a feedback loop I try to create. Here is the part of the code:

Code: Select all

        //Read sensors
      analog_read_value_1 = analogRead(sensor_1);
      sensor_voltage_1 = analog_read_value_1/1023*5;
      distance_1 = analog_read_value_1/1023*6;
      
      analog_read_value_2 = analogRead(sensor_2);
      sensor_voltage_2 = analog_read_value_2/1023*5;
      distance_2 = analog_read_value_2/1023*6;
      
      analog_read_value_3 = analogRead(sensor_3);
      sensor_voltage_3 = analog_read_value_3/1023*5;
      distance_3 = analog_read_value_3/1023*6;
      
      analog_read_value_4 = analogRead(sensor_4);
      sensor_voltage_4 = analog_read_value_4/1023*5;
      distance_4 = analog_read_value_4/1023*6;
      
      //calculate vector between center of two circles measured by sensors
      x_1 = distance_1 + r;
      y_1 = distance_2 + r + sensor_2_y_position;
      x_2 = distance_3 + r;
      y_2 = distance_4 + r + sensor_2_y_position;
     
      vector_length = sqrt( sq(x_2-x_1) + sq(y_2-y_1));
      
      //for direction of vector, need to use origin in centor of stator, which means all x-values need to be 114.08 mm smaller
      
      x_1_center = x_1 - 114.08;
      x_2_center = x_2 - 114.08;
      
      direct = atan2((y_2 - y_1),(x_2_center - x_1_center));   //atan2 will give a value between -pi and pi that correlates with angle of vector
      
      if ( -3*pi/4 <= direct < -5*pi/12) {
        
          digitalWrite(valve_2_push, HIGH);
          digitalWrite(valve_3_push, HIGH);
          digitalWrite(valve_4_push, HIGH);
          digitalWrite(valve_5_push, HIGH);
          digitalWrite(valve_6_push, HIGH);
          
          digitalWrite(valve_2_pull, HIGH);
          digitalWrite(valve_3_pull, HIGH);
          digitalWrite(valve_4_pull, HIGH);
          digitalWrite(valve_5_pull, HIGH);
          digitalWrite(valve_6_pull, HIGH);
        
          while ( vector_length_old - vegtor_length >= 0) { //vector_length is decreasing 
      
    
        
          digitalWrite(valve_1_push, LOW);      //actuate cylinder 1
        
          }
        
          vector_length_old = vector_length;
        
     
Important is the while loop in the bottom. It obviously does not work like that. What I am trying to do:
-calculating a vector from the sensor readings
-calculate length and angle of the vector
-actuate the desired hydraulic cylinder.
-As soon as the hydraulic cylinder starts pushing on the measured object, the vector length will change. I want the cylinder to push until the vector length starts increasing again.

Therefore the program needs to read all sensors and calculate the length continuously in that loop. I am actually not sure how to do that.

Here is the full code of the program:

Code: Select all

// include the library code 
#include <FlexiTimer2.h>
#include "Adafruit_MAX31855.h"
#include <Wire.h>
#include <math.h>                       //double 	atan2 (double __y, // arc tangent of y/x
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield(); // this creates an LCD object that is controlled using the Adafruit library

// These #defines make it easy to set the backlight color
#define OFF 0x0
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7 


//Pin definition
#define sensor_1                          0         // Pin sensor connection
#define sensor_2                          1         // Pin sensor connection
#define sensor_3                          2         // Pin sensor connection
#define sensor_4                          3         // Pin sensor connection

#define button_green                      4         // Pin button
#define button_blue                       5         // Pin button
#define button_red                        6         // Pin button

#define valve_clamp                       7         // Pin clamp valve relay

#define valve_1_push                      8         // Pin cylinder valve relay
#define valve_1_pull                      9         // Pin cylinder valve relay
#define valve_2_push                      10         // Pin cylinder valve relay
#define valve_2_pull                      11         // Pin cylinder valve relay
#define valve_3_push                      12        // Pin cylinder valve relay
#define valve_3_pull                      13        // Pin cylinder valve relay
#define valve_4_push                      14        // Pin cylinder valve relay
#define valve_4_pull                      15        // Pin cylinder valve relay
#define valve_5_push                      16        // Pin cylinder valve relay
#define valve_5_pull                      17        // Pin cylinder valve relay
#define valve_6_push                      18        // Pin cylinder valve relay
#define valve_6_pull                      19        // Pin cylinder valve relay

#define pump_relay                        20        // Pin pump relay



//Variable definition

  //lower sensor
float sensor_voltage_1;      //voltage output of the sensor
float distance_1;            //variable to calculate distance correlating with voltage
float analog_read_value_1;   //value between 0 and 1023 that the analog input of arduino can read

  //lower sensor
float sensor_voltage_2;      //voltage output of the sensor
float distance_2;            //variable to calculate distance correlating with voltage
float analog_read_value_2;   //value between 0 and 1023 that the analog input of arduino can read

  //upper sensor
float sensor_voltage_3;      //voltage output of the sensor
float distance_3;            //variable to calculate distance correlating with voltage
float analog_read_value_3;   //value between 0 and 1023 that the analog input of arduino can read

  //upper sensor
float sensor_voltage_4;      //voltage output of the sensor
float distance_4;            //variable to calculate distance correlating with voltage
float analog_read_value_4;   //value between 0 and 1023 that the analog input of arduino can read

  //center of two circles
float x_1 = 0;
float x_2 = 0;
float y_1 = 0;
float y_2 = 0;

float x_1_center = 0;    //variables for origin in stator instead of origin in sensor
float x_2_center = 0;

float direct = 0;    //direction of vector

const float pi = 3.1416;

float r = 220.16;    //radius of stator is 220.11 ro 220.21 according to specs
float sensor_2_y_position = -224.16;  //sensor placed 4mm away from ideal radius

float vector_length = 0;

float vector_length_old = 100000;

float max_tolerance = 0.5;

  //buttons
int button_green_state = 0;    // variable for reading the pushbutton status
int button_blue_state  = 0;    // variable for reading the pushbutton status
int button_red_state   = 0;    // variable for reading the pushbutton status

int button_var = 0;    // variable activating desired action for button

int run = 1;      //variable for counting straightening runs

int pressure_built_up = 10000;    //run time of pump before start straightening in millis

int clamping = 10000;            //clamping time in millis


void setup() {

  // Debugging output
  Serial.begin(9600);  
  
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  
  pinMode(button_green, INPUT);
  pinMode(button_blue, INPUT); 
  pinMode(button_red, INPUT);  
  
  pinMode(valve_1_push, OUTPUT);        //set all relay controls as output
  digitalWrite(valve_1_push, HIGH);     //HIGH opens the relay and circuit is not closed. Valve is in center position and no oil flowing to device.
  pinMode(valve_2_push, OUTPUT);
  digitalWrite(valve_2_push, HIGH);
  pinMode(valve_3_push, OUTPUT);
  digitalWrite(valve_3_push, HIGH);
  pinMode(valve_4_push, OUTPUT);
  digitalWrite(valve_4_push, HIGH);
  pinMode(valve_5_push, OUTPUT);
  digitalWrite(valve_5_push, HIGH);
  pinMode(valve_6_push, OUTPUT);
  digitalWrite(valve_6_push, HIGH);
  
  pinMode(valve_1_pull, OUTPUT);        
  digitalWrite(valve_1_pull, HIGH);   
  pinMode(valve_2_pull, OUTPUT);
  digitalWrite(valve_2_pull, HIGH);
  pinMode(valve_3_pull, OUTPUT);
  digitalWrite(valve_3_pull, HIGH);
  pinMode(valve_4_pull, OUTPUT);
  digitalWrite(valve_4_pull, HIGH);
  pinMode(valve_5_pull, OUTPUT);
  digitalWrite(valve_5_pull, HIGH);
  pinMode(valve_6_pull, OUTPUT);
  digitalWrite(valve_6_pull, HIGH);
  
  pinMode(valve_clamp, OUTPUT);
  digitalWrite(valve_clamp, HIGH);
  
  pinMode(pump_relay, OUTPUT);
  digitalWrite(pump_relay, HIGH);    //pump is off
  
}


void loop() {
  
  button_green_state = digitalRead(button_green);  // read the state of the pushbutton value
  button_blue_state = digitalRead(button_blue);
  button_red_state = digitalRead(button_red);
  
  // check if and which pushbutton is pressed.
  // if it is, the buttonState is HIGH.
  if (button_green_state = HIGH) {
    //set button_var to 1
    button_var = 1;
  }
  if (button_blue_state = HIGH) {
    //set button_var to 2
    button_var = 2;
  }
  if (button_red_state = HIGH) {
    //set button_var to 3
    button_var = 3;
  }
  
  //button_var will lead program in desired loop: Green-Work, Blue-Measure stator and display, Red-Stop and reset
  if (button_var == 3) {  //STOP
    
    digitalWrite(pump_relay, HIGH);    //pump is off
    delay(10);  
  }
  if (button_var == 2) {  //MEASURE
  
    digitalWrite(pump_relay, HIGH);    //pump is off
    
      //Read sensors
    analog_read_value_1 = analogRead(sensor_1);
    sensor_voltage_1 = analog_read_value_1/1023*5;
    distance_1 = analog_read_value_1/1023*6;
    
    analog_read_value_2 = analogRead(sensor_2);
    sensor_voltage_2 = analog_read_value_2/1023*5;
    distance_2 = analog_read_value_2/1023*6;
    
    analog_read_value_3 = analogRead(sensor_3);
    sensor_voltage_3 = analog_read_value_3/1023*5;
    distance_3 = analog_read_value_3/1023*6;
    
    analog_read_value_4 = analogRead(sensor_4);
    sensor_voltage_4 = analog_read_value_4/1023*5;
    distance_4 = analog_read_value_4/1023*6;
    
    //calculate vector between center of two circles measured by sensors
    x_1 = distance_1 + r;
    y_1 = distance_2 + r + sensor_2_y_position;
    x_2 = distance_3 + r;
    y_2 = distance_4 + r + sensor_2_y_position;
   
    vector_length = sqrt( sq(x_2-x_1) + sq(y_2-y_1));
   
   
    // set the cursor to column 0, line 0
    lcd.setCursor(0, 0);
    // print the sensor voltage
    lcd.print("Crookedness:");
    lcd.print(vector_length*1000);
    lcd.print(" micron");
    
    if (vector_length > max_tolerance)  {                          //check if stator is within tolerance 
      // set the cursor to column 0, line 1
      lcd.setCursor(0, 1);
      lcd.setBacklight(RED);
      lcd.print("Out of Spec");
    }
    
    else  {
      // set the cursor to column 0, line 1
      lcd.setCursor(0, 1);
      lcd.setBacklight(GREEN);
      lcd.print("In Spec");
    }


    
     
  }
  if (button_var == 1) {  //START STRAIGHTENING
    
    
        digitalWrite(pump_relay, LOW);        //pump is ON
        
        if (run == 1) {
          
          delay(pressure_built_up);          //time for pump to build pressure for first run
          
          digitalWrite(valve_clamp, LOW);    //actuate clamps
          
          delay(clamping);                    //time for clamps to clamp cap
           
        }
    
        //Read sensors
      analog_read_value_1 = analogRead(sensor_1);
      sensor_voltage_1 = analog_read_value_1/1023*5;
      distance_1 = analog_read_value_1/1023*6;
      
      analog_read_value_2 = analogRead(sensor_2);
      sensor_voltage_2 = analog_read_value_2/1023*5;
      distance_2 = analog_read_value_2/1023*6;
      
      analog_read_value_3 = analogRead(sensor_3);
      sensor_voltage_3 = analog_read_value_3/1023*5;
      distance_3 = analog_read_value_3/1023*6;
      
      analog_read_value_4 = analogRead(sensor_4);
      sensor_voltage_4 = analog_read_value_4/1023*5;
      distance_4 = analog_read_value_4/1023*6;
      
      //calculate vector between center of two circles measured by sensors
      x_1 = distance_1 + r;
      y_1 = distance_2 + r + sensor_2_y_position;
      x_2 = distance_3 + r;
      y_2 = distance_4 + r + sensor_2_y_position;
     
      vector_length = sqrt( sq(x_2-x_1) + sq(y_2-y_1));
      
      //for direction of vector, need to use origin in centor of stator, which means all x-values need to be 114.08 mm smaller
      
      x_1_center = x_1 - 114.08;
      x_2_center = x_2 - 114.08;
      
      direct = atan2((y_2 - y_1),(x_2_center - x_1_center));   //atan2 will give a value between -pi and pi that correlates with angle of vector
      
      if ( -3*pi/4 <= direct < -5*pi/12) {
        
          digitalWrite(valve_2_push, HIGH);
          digitalWrite(valve_3_push, HIGH);
          digitalWrite(valve_4_push, HIGH);
          digitalWrite(valve_5_push, HIGH);
          digitalWrite(valve_6_push, HIGH);
          
          digitalWrite(valve_2_pull, HIGH);
          digitalWrite(valve_3_pull, HIGH);
          digitalWrite(valve_4_pull, HIGH);
          digitalWrite(valve_5_pull, HIGH);
          digitalWrite(valve_6_pull, HIGH);
        
          while ( vector_length_old - vegtor_length >= 0) { //vector_length is decreasing 
      
    
        
          digitalWrite(valve_1_push, LOW);      //actuate cylinder 1
        
          }
        
          vector_length_old = vector_length;
        
     
     
      // set the cursor to column 0, line 0
      lcd.setCursor(0, 0);
      // print the sensor voltage
      lcd.print("Crookedness:");
      lcd.print(vector_length*1000);
      lcd.print(" micron");
      
      if (vector_length > max_tolerance)  {                          //check if stator is within tolerance 
        // set the cursor to column 0, line 1
        lcd.setCursor(0, 1);
        lcd.setBacklight(RED);
        lcd.print("Out of Spec");
      }
      
      else  {
        // set the cursor to column 0, line 1
        lcd.setCursor(0, 1);
        lcd.setBacklight(GREEN);
        lcd.print("In Spec");
      }
  
      
      run++;
      
      
      
      }
  

  
    }
    
}

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Correction of a crooked cylinder

Post by bdellal »

No one?

User avatar
adafruit_support_bill
 
Posts: 88096
Joined: Sat Feb 07, 2009 10:11 am

Re: Correction of a crooked cylinder

Post by adafruit_support_bill »

What exactly does the code do or not do? It is not easy to spot a bug in 300+ lines of code if you don't even know what the problem is.

User avatar
bdellal
 
Posts: 51
Joined: Tue Jun 10, 2014 6:00 pm

Re: Correction of a crooked cylinder

Post by bdellal »

I am trying to create a closed loop. Out of my sensor values, the program calculates a vector-length. I want the program to monitor this length continuously. After actuating the machine, this vector length decrease to a certain point. As soon, as it starts increasing again, I want to stop the actuator. I don't know how to write that loop. It is not a simple while loop or something like that.

Thanks

User avatar
adafruit_support_bill
 
Posts: 88096
Joined: Sat Feb 07, 2009 10:11 am

Re: Correction of a crooked cylinder

Post by adafruit_support_bill »

That's a fairly simple while loop. Each time through the loop you calculate the change in vector length:

Code: Select all

while (vectorChange < 0)  // while the length is decreasing
{
    //
    // Take measurements and calculate new length here
    //

    //
    // move actuator here
    //

    vectorChange = newLength - oldLength;
    oldLength = newLength;
}

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”