Linear Actuator position control with IMU

Hi all,

I am building a heliostat with 300mm linear actuator control having potentiometer feedback (https://uk.rs-online.com/web/p/electric-linear-actuators/1774510), using a BNO055 IMU to give me the location and orientation of the elevation and azimuth angle of the mirror.

I am really lost as to how to control the linear actuator so that they move after they recieve data from the IMU.
Current normal is the current orientation and destination normal is the destination where the mirror needs to point.

My thought process goes like this: I've got the current normal vectors and from them I've calculated the destination normal vectors. Seems like a simple logic to move the linear actuators untill the Current IMU angle matches calculated anlge but I am unsure how to write that in code. How should I go about writing the code.

I've also attached the code I've written so far. Any advise will be greatly appreciated

#include <SolarPosition.h>
#include <DS3232RTC.h>

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>

uint16_t BNO055_SAMPLERATE_DELAY_MS = 100;
Adafruit_BNO055 myIMU = Adafruit_BNO055(55, 0x28);

// number of decimal digits to print
uint8_t digits = 3;


//AZIMUTH ACTUATOR
//const int ENA_PIN = 7; // the Arduino pin connected to the EN1 pin L298N
const int IN1_PIN = 6; // the Arduino pin connected to the IN1 pin L298N
const int IN2_PIN = 5; // the Arduino pin connected to the IN2 pin L298N
//ELEVATION ACTUATOR
//const int ENA_PIN = 8; // the Arduino pin connected to the EN2 pin L298N
const int IN3_PIN = 10; // the Arduino pin connected to the IN3 pin L298N
const int IN4_PIN = 9; // the Arduino pin connected to the IN4 pin L298N


// Initialising Variables-
float SunX;     //sun vectors
float SunY;
float SunZ;

//You get the target vectors from another code called "Find_Target_WITH_LinearActuators".
//Input the target vectors manually in this code
float TargetX = 1.25;  //target vector x
float TargetY = 2.34;  //target vector y
float TargetZ = 5.11;  //target vector z

//float dCNx, dCNy, dCNz;     //euler degrees of current normal 
//float vCNx, vCNy, vCNz;     //vectors of the current normal

float DestinationNormalX;   //this needs to be calculated from the sun and target vectors
float DestinationNormalY;
float DestinationNormalZ;

SolarPosition Loughborough(52.76336662631451, -1.2481144519918814);  // Loughborough, UK

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  myIMU.begin();
  SolarPosition::setTimeProvider(RTC.get);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.print("Loughborough: ");
  SolarPosition(Loughborough.getSolarPosition(), digits);
  delay(60000);
}

void SolarPosition(SolarPosition_t pos, int numDigits){
 
  float  sunEle = pos.elevation;  //Sun Elevation Angle in Degrees
  float sunAzt = pos.azimuth;     //Sun Azimuth Angle in Degrees
  
  Serial.print("elevation: ");
  Serial.print(sunEle, numDigits);
  Serial.print(" deg   ");

  Serial.print("azimuth: ");
  Serial.print(sunAzt, numDigits);
  Serial.println(" deg");

  //Calculating Sun Vectors from the azimuth and elevation angles
  float degToRadian = PI / 180.0;           //converting degrees to radians
  SunX = cos(sunEle * degToRadian) * cos((360 - sunAzt) * degToRadian);  //Sun x coordinate
  SunY = cos(sunEle * degToRadian) * sin((360 - sunAzt) * degToRadian);  //Sun y coordinate
  SunZ = sin(sunEle * degToRadian);                                      //Sun z coordinate

  //MATHS to calculate the destination normal vectors
  
  float ax = SunX + TargetX;
  float ay = SunY + TargetY;
  float az = SunZ + TargetZ;
  double denominator = sqrt((ax*ax) + (ay*ay) + (az*az));

  DestinationNormalX = ax / denominator;      //Destination normal vector x
  DestinationNormalY = ay / denominator;      //Destination normal vector y
  DestinationNormalZ = az / denominator;      //Destination normal vector z

  Serial.print("Destination Normal X, Y, Z are  ");
  Serial.print(DestinationNormalX, 3);
  Serial.print(DestinationNormalY, 3);
  Serial.println(DestinationNormalZ, 3);

  //CODE to find the current normal of the mirror
  
  float dCNx, dCNy, dCNz;     //euler degrees of current normal 
  imu::Vector<3> CurrentNormal = myIMU.getVector(Adafruit_BNO055::VECTOR_EULER);
  
  Serial.print("Current normal Angles x, y, z are ");
  Serial.print(dCNx = CurrentNormal.x());     //x euler angle in degress
  Serial.print(", ");
  Serial.print(dCNy = CurrentNormal.y());     //y euler angle in degress
  Serial.print(", ");
  Serial.print(dCNz = CurrentNormal.z());     //z euler angle in degress
  Serial.println(" respectively.");

  //the angles returned from the IMU are in degrees.
  //we need to convert them to vectors to work with them

  float vCNx, vCNy, vCNz;     //vectors of the current normal
      vCNx = cos(dCNx * degToRadian);   //Current normal vector x
      vCNy = cos(dCNy * degToRadian);   //Current normal vector y
      vCNz = cos(dCNz * degToRadian);   //Current normal vector z


  //Now we do some more maths to understand how much the linear actuator needs to move and then then we send the command to the linear actuator to move by that amount
  //

  //Now, we need to move the azimuth and elevation linear actuators accordingly
  
}

Please post a diagram showing how the actuator controls the angle of the surface.

It should be a straightforward application of trigonometry to solve for the required actuator movement.

You may find some useful information in this project: GitHub - jremington/Arduino_heliostat: Model alt/az heliostat using Arduino

Do you mean the pivot point locations?

I'm not able to interpret that diagram. You will need an equation for how the actuator lengths specify the altitude and azimuth angles of the surface normal vector.

Yes I've got a trignometric relationship between the actuator length and the azimuth/elevation angles

This is just for the elevation angle:

My question is how and where do I apply the trignometric equation.

Say the destination elevation is 35 degreess and I am currently at 28 degrees. How do I move the linear actuator using this trig equation? What code do i write? been staring at this problem the whole day...

Your equation for the elevation is not useful in that particular form. You need to work out the exact relationship between elevation angle and "a", the length of the actuator arm (which will probably include another constant for the actuator mount and housing), then substitute the known constants into the equation.

Invert to get "a" in terms of elevation.

I suspect that elevation = 90 - <A in degrees, but the inverse cosine function gives radians.

Yes you are completely correct so the resulting equations is

image

Please could you assist me as to how I should go about writing the code

I should have checked earlier, but the link you posted does not indicate whether the actuator you have has position feedback (such are available). If not, there is no direct way to know "a", the extension length.

Does it have position feedback, and if so, have you worked out how to read it and get accurate position information? It would be straightforward to make a table of a versus angle.

Yes the linear actuator has position feedback via a potentiometer. I am currently in the process of figuring out how to manipulate the analog feedback from the potentiometer. How should I go about the code?
Could you please please help.
This is from the datasheet
image
r

All you have to do is make an experimentally determined table of analog input readings versus measured elevation angle, for the finished setup. Google "arduino linear actuator position control" for tutorials.

The first step is to complete the build, so that you can drive the actuator to different lengths, and make the required angle measurements.

Ok I'll do that. Thank you so much. What would you suggest my steps after that would be?

If you see my code, I've got the destination normal vectors which are the vectors the normal of the mirror must point to. How do I use those in the code to move the linear actuator? Basically trying to understand what relationahip the vectors have with the linear actuator stroke length

Determine the azimuth and elevation angles of the "destination normal vector" and, for the elevation angle, invert the equation in post #7 to get "a". Or, use the experimentally determined lookup table of "a" versus elevation angle.

Thank you. I feel really dumb asking this again but what happens after that.

Say I've determined the destination elevation angle is 30 degrees and its current elevation angle is 25 deg. From the trig equation the 'a' needs to be 530mm. If the housing length of the actuator is 400mm, the stroke needs to change by 130mm. How do I tell the linear actuator to do that?

One approach, which may be adequate, is to drive the actuator at full speed until the voltage on the feedback pot says you are at 530 mm.

Get the direction to drive from the sign of the result: (desired position - current position).

If that isn't accurate enough, PID control of the actuator position should work better.

You can also measure the actual, current elevation angle using the BNO055 and drive the actuator accordingly. The problem with that approach is that the code may attempt to drive the mechanism out of bounds.