Is it possible to set a variable to a range of values? PID TVC Attempt

Hi All,

I wanted to know if it’s possible to set a variable to a range or any value between two values.

Here’s a brief reason as to why I’m attempting this in case there is a better way for me to go about things.

I’m trying to programme a PID controlled thrust vector system to self balance. I want to set the “Setpoint” (the desired output value) to an accelerometer range between -0.5 and 0.5 to allow for some wiggle room and so that there is no overcorrection or over reaction to slide wobbles or vibration.

Here is what I’ve got so far.

#include <ESP32Servo.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <PID_v1.h>

Adafruit_MPU6050 mpu;

int s1 = 2;

Servo x1;

double Setpoint, Input, Output;

double aggKp=4, aggKi=0.2, aggKd=1;
double consKp=1, consKi=0.05, consKd=0.25;

PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);


void setup(void) {
  Serial.begin(115200);
  while (!Serial) {
    delay(10); // will pause Zero, Leonardo, etc until serial console opens
  }
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);

  x1.setPeriodHertz(50);

  x1.attach(s1, 500, 2400);

  if (!mpu.begin()) {
  Serial.println("Failed to find MPU6050 chip");
  while (1) {
    delay(10);
  }
}
  mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  Serial.println("");
  delay(100);

  x1.write(0);

  Setpoint = 0;

  myPID.SetMode(AUTOMATIC);
}

void loop() {

  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  Input = a.acceleration.x;

  delay(100);

  double gap = abs(Setpoint-Input);
  
  if (gap < 2); {
    myPID.SetTunings(consKp, consKi, consKd);
  }
  if (gap > 2); {
    myPID.SetTunings(aggKp, aggKi , aggKd);
  }

  myPID.Compute();
  int x = map(Output, 0, 255, 0, 180);
  x1.write(x);


  Serial.print(x);
  Serial.print("  /  ");
  Serial.print(Input);
  Serial.print("  /  ");
  Serial.println(gap);

}

I have yet to test the system (still waiting for some components) so the values plugged into the PID are completely arbitrary and I’m sure there are plenty of things wrong with it that I’ll figure out along the way.

Just to highlight, the variable I wish to adjust is.

Setpoint = 0

Please let me know if there is a way to set the setpoint to a range or if there is a better way to go around attempting this.

Thanks in advanced!

I wanted to know if it's possible to set a variable to a range or any value between two values.

No, but what you can do is to test whether the value of a variable is within range of values and if it strays outside of your desired range set its value back to inside the range

amanbasra:
range between -0.5 and 0.5

This is a terrible idea, for an integral processor. Consider that the above range is -5 to +5 or -50 to +50 or -500 to +500 with a little print formatting. That is to say, avoid decimal values. Your math will be more accurate and execute faster. Also, instead of thinking how can I limit the range, consider that in hardware, each register is 8 bits wide and has an address and a value. The only way to change this is in code, which is essentially what you are asking… except you aren’t directly asking that. As already stated, you can use >, >=, ==, <=, < and/or ! to check the value of whatever before assigning that value to your variable.

Thanks for the help!

I’ve added the following to filter out the noisy negligible readings as suggested and it’s doing the trick.

  if ((a.acceleration.x <= 0.5) && (a.acceleration.x >= -0.5)) {
  a.acceleration.x = 0;
  }

Perehama:
This is a terrible idea, for an integral processor. Consider that the above range is -5 to +5 or -50 to +50 or -500 to +500 with a little print formatting. That is to say, avoid decimal values. Your math will be more accurate and execute faster. Also, instead of thinking how can I limit the range, consider that in hardware, each register is 8 bits wide and has an address and a value. The only way to change this is in code, which is essentially what you are asking… except you aren’t directly asking that. As already stated, you can use >, >=, ==, <=, < and/or ! to check the value of whatever before assigning that value to your variable.

Thanks for the suggestion! I will try and map out the decimals to larger numbers to help it calculate better. Could you clarify what the terrible idea is? Using PID in a thrust vectoring system or setting the setpoint to a range?
If using the range the intention was to filter out the accelerometer data to remove negligible values and to prevent over correction as mentioned. Is there a better way to do this or is it a pointless task all togther?
If using the PID for a thrust vector control system is there a better way to attempt this? I won’t pretend to really know what I’m doing, just thought this would be a fun little project. I have no background knowledge of programming or control systems and very much just learning on the fly with this so any suggestions are more than welcome.
Thanks again.

A PID control system should not need any “wiggle room” in the set point.

Not sure how you would provide it anyway. It seems like it would have potential to be working at cross purposes with the PID loop and just complicate tuning and proper functioning.

Your question seems to imply some lack of basic programming knowledge. Have you deployed PID in other circumstances?

a7

alto777:
A PID control system should not need any “wiggle room” in the set point.

Not sure how you would provide it anyway. It seems like it would have potential to be working at cross purposes with the PID loop and just complicate tuning and proper functioning.

Your question seems to imply some lack of basic programming knowledge. Have you deployed PID in other circumstances?

a7

Hit the nail on the head alto, no idea what I'm doing!
I haven't deployed PID in any other project, this is my first project I've ever attempted programming, perhaps a bit too much of an undertaking but I think I'm gettings somewhere (not necessarily in the right direction, but certainly getting somewhere!). I've found a new interest in these things and have been trying to educate myself through youtube. Perhaps the better way to have phrased the question would have been how to refine and filter IMU data as opposed to trying to filter out these values in the PID with the setpoint value.

amanbasra:
Could you clarify what the terrible idea is?

Trying to do complicated math on an integral processor. In all applications for which an UNO is suitable, accuracy has a finite resolution and finite range, making the combination also finite. Therefore, calculate these before-hand using Excel or MATLAB or pen and paper, and list them in a lookup table. You will get to the end result, the correction, much quicker with a lookup table in an integral processor.

Perehama:
Trying to do complicated math on an integral processor. In all applications for which an UNO is suitable, accuracy has a finite resolution and finite range, making the combination also finite. Therefore, calculate these before-hand using Excel or MATLAB or pen and paper, and list them in a lookup table. You will get to the end result, the correction, much quicker with a lookup table in an integral processor.

Ahhh maths... Exactly what I wanted to avoid having to do! :stuck_out_tongue_closed_eyes:

What you're saying makes sense, I will look into understanding the math behind PID more to be able to calculate before hand as you suggested. and referencing this in the code as opposed to processing the math onboard.

For clarity I'm using an ESP32 and programming it using Arduino IDE. A bit more power than an Uno but I can see that the same logic applies. It's becoming clear I should really develop a better understanding of this before blindly jumping into attempting to programme a system with this degree of complexity. A more comprehensive understanding of the maths would definitely be preferable to relying too heavily on libraries that do the bulk of the heavy lifting for me!

What is your actual problem?

aarg:
What is your actual problem?

The initial issue was essentially filtering the data from the IMU so as not to over sensitise the response from the PID.

This issue has snow balled into a realisation that I clearly lack the understanding to take this one!

Perehama:
calculate these before-hand using Excel or MATLAB or pen and paper, and list them in a lookup table. You will get to the end result, the correction, much quicker with a lookup table in an integral processor.

I've been looking into the PID equation and think I have grasped a good understanding of it now...the theory and math portion anyway. As always the application doesn't appear to be quite as straight forward. Perhaps I this should be made a separate topic as this is gradually deviating from the the initial reason I made this post, but, with that being said, what portion of the math is best to calculate off the processor? All of the PID equation works off of data it is receiving from the IMU so I don't see how I could calculate this in any other way than doing it live on the microprocessor.

Unless you are referring to the MPU data which is also chewing through its fair share of maths. Similarly all of the calculations are in reference to data it is receiving live...

A nudge in the right direction or a point to some resources where I can get more of an understanding of what i need to do would be greatly appreciated.

As suggested, the maths can be scaled and written as integer operations, known generally as fixed point calculations.

A build-in floating point processor (FPU) can be used: the UNO and its ilk have no such thing, so ppl code around that using integer maths.

As you surmise, there’s not much you can do in a PID situation to exploit lookup tables; one example I can think of would be using lookup and interpolation to do elementary functions like sin and cosine which are probably not directly supplied by the FPU and might be expensive time-wise to produce on the fly.

Some inexactitude in the calculations can be overcome by the very nature of the PID feedback loop. But you have started with an important small consideration, getting good data from the real world into you algorithms in the first place.

a7

amanbasra:
The initial issue was …

A nudge in the right direction or a point to some resources where I can get more of an understanding of what i need to do would be greatly appreciated.

IMU,MPU,PID… doesn’t matter…
Step 1, manipulate data coming from sensor into an unsigned integral value. If it’s a float value, string, pulse train, whatever, count it, round it off, truncate, scale it whatever, get it into an integral value with the lowest value being 0.

Step 2, the underlying math problem has the form f(x) or f(x)(y)(z)(…) so it can be put into a lookup table. Here is what a lookup table looks like for f(x):const signed long CalculatedValueLUT[] = {32, -54, 75, 64, -85, 123, 234,};const means constant not a variable, never will be reassigned a different value. signed is optional but could be replaced with unsigned if your table does not have negative integers and you want to take advantage of the increased range. long can be char, int or long depending on your range of values. Look at the reference for each variable type to know the signed and unsigned ranges. This is an array, and each position has an integral index. In fact, they are 0 indexed, meaning the first value is accessed by the index 0. The second is 1. And, so on. Accessing a value from the lookup table is as easy as:signed long pidValue = CalculatedValueLUT[sensorIntegralValue];Here is what a lookup table for f(x)(y)(z) looks like:const signed long CalculatedValueLUT[][2][2] = {{{32, -54}, {75, 64}}, {{-85, 123}, {234, 0}}};Notice we have to give bounds for each grouping except the first. The curly braces group the constant values into the respective vectors. So now, accessing it looks like:signed long pidValue = CalculatedValueLUT[inputValue1][inputValue2][inputValue3];

Step 3, do what you need to do with the calculated value.

Quote from: aarg on Dec 29, 2020, 02:50 pm

  • What is your actual problem?*
    ...
    The initial issue was essentially filtering the data from the IMU so as not to over sensitise the response from the PID. This issue has snow balled into a realisation that I clearly lack the understanding to take this one!

What I meant was, "what is this 'thrust vector control system' for, how does it work and interface with the Arduino, what are the parameters and requirements (bandwidth? precision?, etc.?)". Have you done any dynamic testing with the IMU to find out what kind of data you can expect? Any testing with your 'thrust vector' device to determine its speed and precision?

Without this information, it's hard to intelligently specify the arrangement of elements in your control system. For example, for some systems, "bang bang" control is enough (brute force negative feedback), and it gets fancier as you add performance features to that. PID is just one of those possible enhancements.

aarg:
What I meant was, “what is this ‘thrust vector control system’ for, how does it work and interface with the Arduino, what are the parameters and requirements (bandwidth? precision?, etc.?)”. Have you done any dynamic testing with the IMU to find out what kind of data you can expect? Any testing with your ‘thrust vector’ device to determine its speed and precision?

The system is a EDF powered rocket system I’ve been working on designing and trying to programme. The two options I’ve been considering is a gimbaling system or a thrust vectoring veins system. I’m fairly fixed on the thrust vector vein design at this point as it will give me greater control as well as allow me to control the roll as I’m cautious the torque of the motor may cause some spin. The goal is to automate everything. I’ve taken a massive interest into the development of the starship at space x and this little project is inspired by the starship. I will be designing the flight controller from scratch, including drawing up the schematics and having the PCB’s printed so it will have all relevant sensors and data to perform complex procedures and manoeuvres

My main consideration was the amount of trial and error that would go into the ‘bang bang’ approach to get a system that works consistently. I also can’t imagine the bang bang approach would be very adaptive to environment changes such as a slight breeze hitting it for example hence why I thought a PID system would offer more control to keep it stable, particularly for the landing sequence where accuracy will be vital.

I have yet to establish how I am going to make 4 PID loops work in conjunction (as there will be 4 servos controlling 4 different thrust vectoring veins but I guess I’ll cross that bridge when I get to it. I’m planning on designing a gimbaling gig to hold the prototype and test the TVC to tune the PID loop. It’s very possible I’m missing steps as I’m not sure how the system will establish how much x degrees of movement in the servo will have on the whole unit but this is something I’m anticipating realise while testing. Unfortunately my ESC has given up on me during some thrust testing with the EDF so I will have to wait to do further testing until the new ESC arrives.

I have done testing with an MPU6050 and got some solid results using a library. I haven’t had much luck using the built in wire library. I believe I’m having issues with the I2c address. Again something I need to look into in more depth. I’ve managed to clarify the data and make the servos move to set degrees when the IMU is positioned in certain orientations using simple if statements.

As you say I think the bang bang approach at first will help to collect data and get a better understanding of how all the components work and communicate, hence why I am starting with a simple RC design which i’ve cobbled together using two ESP32’s.

Again I’d appreciate any tips and suggestions or things that I’m outright just doing wrong.

Have a great new years !

An intriguing project.

Bang bang on this kinda thing would actually be bang bang crash.

I don't think you need multiple PID loops. Check out quadcopters. Unless you are thinking you will need a control system to handle each vein - quadcopters tell the motors what to do, and to the extent that they get it wrong as indicated by the (the) PID loop, they are told something different next time slice.

If the veins are run by servos, the servos themselves incorporate feedback to establish maintain the desired position as calculated by the flight controller.

I would (if I dared embark on this ambitious project) probably go with the gimbal; to overcome the torque problem I would employ two motors spinning in opposite directions.

PID won't be your problem, tuning the system will. Be a challenge.

I do admire the spirit of the undertaking, but I think you might benefit from serious experimentation in a number of areas before spinning PCBs for this thing.

If you haven't, as I say check out the state of the art in multirotors (quadcopters). There are several mature control system "ecosystems" and lotsa inexpensive gear. All open source and a largely friendly community. If you spend a bit more you can get good stuff overnight from multiple vendors (assume USA).

If you ultimately want to DIY every last bit of this, there is no shame in starting by cobbling together known tested understood supported widely used and relatively cheap pieces into which thousands of man years of research, development and testing has been invested.

TX RX FCB PDB BEC PDB and then you can start worrying about the mechanical aspects.

Srsly, this is a huge project for a blank slate, speaking for myself I know I would not have whatever it takes and would give up at some point having spent a bunch of money and time. Both precious resources, time now more for me, haha.

In any case, good luck, keep us posted, and if you go elsewhere for more advices and help let us ( we who would like kibitz or just enjoy vicariously your efforts) know so we can follow along.

a7

Perehama:
Step 3, do what you need to do with the calculated value.

Thanks for that, very helpful. i have created new variables to multiply the data by 10 and store them as integers as suggested, I must admit its even easier to analyse the data this way.

As for adding in the lookup table, I see what you mean and it makes a lot more sense with that explanation so thanks! I'll definitely look toward implementing this once I've got the basics working. Unfortunately, after a pouring a frustrating amount of time into trying to clean up and filter the MPU6050 data, I've come to the conclusion a 9 axis IMU would provide less noisy and cleaner data so things are on pause til that arrives.

The good news is that the basic controls are functioning. The servos are reacting to the IMU data so there is some light beaming from the end of the distant tunnel end!

alto777:
I don't think you need multiple PID loops. Check out quadcopters.

You are definitely right. Upon further consideration I can use the output value for both the X and Y axis and modify the output to each servo to ensure correct orientation so that shouldn't be too difficult (famous last words!)

I initially chose and EDF for their thrust output capabilities as well as the fact that I have a few design for increasing the thrust with nozzles and extensions of the EDF. A couple of quad copter motors would definitely be a lot easier to work with and would allow me to cancel out the torque factor as you mentioned so I'm definitely keeping that as a backup if I feel the EDF method is heading toward a brick wall. I have had the idea to model my own EDF that holds two counter rotating motors but I feel this would be overkill...That being said the whole project is overkill haha! I definitely preference the gimbal design, again it more closely mimics the design use in the real starship however, I'm not sure it would have sufficient range of motion to be able to stabilise the rocket without significantly increasing the footprint of the rocket. I do have a design for a gimbal drawn up in cad and ready to 3d so I do intend to test this but I'm just not very optimistic.

I'm not strictly creating everything from the ground up, after all, the bulk of the code is just copied and pasted from libraries, altered to fit my purpose and cobbled together. The flight controller I am only designing because I don't think there are any out there with the functionality I require for low cost. Surprisingly having PCB's printed and putting together the components is nice and cheap so it actually seems like the simpler solutions, as well as giving me incite into how schematics and PCB's work. Also designing it myself gives me a better understanding of the components I'm working with. I've had a PCB's with my design made (for the transmitter) and they have worked well so far. This is just basically having a PCB to solder the arduino/ESP32 and the mpu6050 and barometer etc soldered onto so it isn't quite as intricate as designing the PCB from scratch and fitting all the surface mount components myself but still gives me the functionality I need easily and cheaply. It's a lot more manageable than a bunch of breadboards that are a mess of jumper cables.

I'm painfully aware how much of an undertaking is! Especially as complete novice to design and programming. So far I have thoroughly enjoyed the project and although there are a few components that are somewhat pricey (pretty much just the EDF and battery) the vast majority of the components are very cheap so the only resource really be expended thus far is time.

I may begin documenting the process on a separate post or on youtube, if I do I'll be sure to post a link on this thread.

  myPID.Compute();
  int x = map(Output, 0, 255, 0, 180);
  x1.write(x);

Note: Rather than re-mapping, you can set the Output range. I'd use a range of 1000 to 2000 and use x.writeMicroseconds(Output);

I just took a look at some EDF motors and while doing it occurred to me

that you should make your own as they look kinda pricey.

In any case, would 4 smaller EDFs in the same plane running CW, CCW, CW, CCW be worth considering? Kinda like the engine layout on the Saturn 5 without the middle engine of the quincunx.

No net torque, smaller cheaper motors (or EDFs) and ESC required, again maybe better matched to existing parts (4-in-1 ESCs, quadcopter FCBs).

Still obvsly trying to make the case for repurposing quadcopter parts and software; I have no doubt you will have lotsa fun (!) no matter what you decide to do.

a7

Argh!

Please stop me before I take on another hobby. The more I think about it, the more it seems that a quadcopter at the bottom of a tube would practically be all and what you need… with a bit of tuning to account for the mass distribution and orientation towards operation mostly in the Z axis.

Look ma, no thrust vanes, no gimbal. The mechanical simplicity of quadcopters is a huge win over helicopters, e.g.

a7

alto777:
Argh!

Please stop me before I take on another hobby. The more I think about it, the more it seems that a quadcopter at the bottom of a tube would practically be all and what you need… with a bit of tuning to account for the mass distribution and orientation towards operation mostly in the Z axis.

Look ma, no thrust vanes, no gimbal. The mechanical simplicity of quadcopters is a huge win over helicopters, e.g.

a7

Haha someones caught the same random urge to build something ridiculously complicated and time consuming for no good reason!

This is a very good point. The quad copters would work with small motors and props. I'm looking at keeping within 80mm diameter for the thrust veins or 135mm for the gimbaling design (which I've modified to allow for up to 20 degrees of gimbaling in any axis so its very much back on the cards). The thing is I already got the EDF. Managed to find a bit of a hack which was finding the duct itself for really cheap then just fitting an out-runner EDF motor into it (This was before I had access to a 3d printer). I managed to pick up a motor capable of putting out 1.2kg of thrust for around £10 (under $15) and I believe I'll be able to get even more thrust out of it than that with some of my designs (not that I need anymore). Worked a charm before the ESC gave out. Turns out the EDF has a counter measure to prevent torque being a factor. There are little veins within the EDF that are angled against the rotation of the motor. Clever little design and lucky for me means I don't have to worry about the torque (though I haven't actually tested this, just an assumption off of further inspection of the duct)/ The thing is very noisy and produced a lot of vibration though so there is still a good chance of me switching to a straight up motor and prop/ a form of quadcopter configuration. I'm designing things very modularly so I'll be able to switch things in and out of the chassis if one design doesn't work.

Quad copters are amazing, as you say, in comparison to the mechanical complexity of helicopters they're a dream. For some reason unknown to even myself the challenge of doing things in a more complicate way seems more fun (Look ma, no logic!) . I do think just having a quadcopter as the thrust provider it is essentially sticking a tube on top of a drone though but there is definitely a sweet spot between the two ideas. The idea of having a multi motor powered system has already given me a bunch of ideas to add even more complications to the project though! Luckily I have access to a 3d printer so the possibilities are endless!