Show Posts
Pages: 1 2 [3] 4
31  Using Arduino / Programming Questions / Re: 2 questions - functions outside loop; using arrays as vectors on: April 04, 2012, 05:19:59 pm
Code:
float PplusI(float Pgain, float Igain, int ref_mv, int output_mv, int SampleTime) {
  float u[3]; // See below
  int e[3]; // e[0] = current error, e[1] = previous error
  e[0] = err(ref_mv, output_mv);
  u[0] = u[1] + Pgain*e[0] - (Pgain - Igain*SampleTime)*e[1];
  u[1] = u[0]; // previous u = current u
  e[1] = e[0]; // previous error = current error
 
  return u[0];
}

Why bother calculating e [ 1 ] = e [ 0 ] when you discard it? Ditto for u [ 1 ].
Oh, I thought that would store the current error as the previous error... Does it get discarded because I'm initialising the arrays at the beginning of the function?
32  Using Arduino / Programming Questions / [Solved] Increasing PWM frequency and resolution on: April 04, 2012, 04:10:40 pm
Hi... I thought I'd make another thread because I am severely confused!

I'm trying to increase the frequency of a PWM pin's output (let's say this pin uses Timer1), and increase the resolution to 10-bit. I've spent the last couple of hours trying to make sense of the datasheet, and lots of old threads and blog entries about how to go about this, and I've seen so many slightly different methods that I don't know what to do any more!

At the moment, this is what I have in setup():
Code:
 TCCR1B = TCCR1B & 0b11111000 | 0x01; // 31250 Hz
  TCCR1A = 0x03; // 10 bit?

Is this correct?

And if the pin is now 10-bit, does this mean I could analogWrite values from 0 to 1023? That's what I'm trying to do...  smiley-sweat

Thanks,
+-
33  Using Arduino / Programming Questions / Re: 2 questions - functions outside loop; using arrays as vectors on: April 04, 2012, 11:21:41 am
Hello, I've just finished coding my simple controllers and I'd like to know if there's anything I can do to improve it. I am still using arrays (because I don't want too many words e.g. previous_error, previous_output...), but inside the functions for each controller, rather than as global variables.

Code:
/***** Controllers: P, P+I, P+DFB, PID *****/
float rVel = 20.00; //reference signal, % of speed
int rPos = 150; //reference signal, degrees
// I think r would be inside the TWS variables function

int delta = 20; // Sample time, in milliseconds
float kp = 34.125;
float ki = 12.2;
float kd = 0.1;
int y_read;
float u;
int u_write;
const int velocityPin = A0;
const int positionPin = A2;
int inputPin; // I could use this to choose which pin to use as input
const int outputPin = 5;

void setup() {
  pinMode(velocityPin, INPUT);
  pinMode(positionPin, INPUT);
  pinMode(outputPin, OUTPUT);
  inputPin = velocityPin; // This would need to change
}

// Float version of map() - I don't think I will need this working with mV
//float fmap(float x, float in_min, float in_max, float out_min, float out_max) {
//  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
//}

// Converting reference values
int rVel_mv = map(rVel, -100.00, 100.00, 0, 5000); // % to mV
int rPos_mv = map(rPos, -180, 180, 0, 5000); // degrees to mV

// Initialise reference value to be used
int r_mv;

// Controller functions
int err(int ref_mv, int output_mv) {
  return ref_mv - output_mv;
}

float P(float gain, int ref_mv, int output_mv) {
  int error = err(ref_mv, output_mv);
  
  return gain*error; // = u
}

float PplusI(float Pgain, float Igain, int ref_mv, int output_mv, int SampleTime) {
  float u[3]; // See below
  int e[3]; // e[0] = current error, e[1] = previous error
  e[0] = err(ref_mv, output_mv);
  u[0] = u[1] + Pgain*e[0] - (Pgain - Igain*SampleTime)*e[1];
  u[1] = u[0]; // previous u = current u
  e[1] = e[0]; // previous error = current error
  
  return u[0];
}

float PplusDFB(float Pgain, float Dgain, int ref_mv, int output_mv, int SampleTime) {
  int e[3];
  int y[3]; // y[0] = current output, y[1] = previous output
  e[0] = err(ref_mv, output_mv);
  y[0] = output_mv;
  u = Pgain*e[0] - (Pgain*Dgain/SampleTime)*(y[0] - y[1]);
  y[1] = y[0];
  
  return u;
}

float PID(float Pgain, float Igain, float Dgain, int ref_mv, int output_mv, int SampleTime) {
  int e[4]; // error: e[0] = e(k), e[1] = e(k-1), e[2] = e(k-2)
  float u[3];
  e[0] = err(ref_mv, output_mv);
  u[0] = u[1] + Pgain*(e[0] - e[1]) + Igain*SampleTime*e[0] + (Dgain/SampleTime)*(e[0] - 2*e[1] + e[2]);
  u[1] = u[0];
  e[2] = e[1];
  e[1] = e[0];
  
  return u[0];
}
  

void loop() {
  // Choose which variable to use as a reference value
  if (inputPin == velocityPin) {
    r_mv = rVel_mv;
  }
  else if (inputPin == positionPin) {
    r_mv = rPos_mv;
  }
  
  // Read output
  y_read = analogRead(inputPin);
  int y_mv = map(y_read, 0, 1024, 0, 5000); // convert to mV
  
  // Controllers: choose one
//  u = P(kp, r_mv, y_mv);
//  u = PplusI(kp, ki, r_mv, y_mv, delta);
//  u = PDFB(kp, kd, r_mv, y_mv, delta);
//  u = PID(kp, ki, kd, r_mv, y_mv, delta);
  
  u_write = map(u, -5000, 5000, 0, 256); // convert mV to [0,255]
  // Why 256? http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1266045058/22#22
  
  // Limit output
  if (u_write > 255) {
    u_write = 255;
  }
  else if (u_write < 0) {
    u_write = 0;
  }
  
  analogWrite(outputPin, u_write); // PWM output
}

+-
34  Using Arduino / Programming Questions / Re: 2 questions - functions outside loop; using arrays as vectors on: April 03, 2012, 06:41:49 pm
I see, that sounds better. I take it you mean something like this:
Code:
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
?


Yes, that's the right idea (although there is an existing function called map, but NVM that).

Yes, I took it from the map Reference page as an example. It's settled then. I will rewrite my code today!
35  Using Arduino / Project Guidance / Re: Making a controller - Do I need to take the low pass filter into account? on: April 03, 2012, 06:35:48 pm
Quote
So I am not sure if, when I am calculating my gains (for say, a PID controller), I need to include the transfer function of the LP filter, as it would effectively add another order to the plant transfer function.

Yes, putting together what you said before about the PWM LPF, which I computed
had a 2-msec time-constant, and your wish to have 10-msec loop updates, I
think you are close to having a problem. The LPF will not really settle in 10-msec.

Also, as mentioned previously, I seriously doubt the servo-amp in the PDF file you
gave will take a direct PWM input, those things are made for analog driving.

Also, from what you say, I'll re-iterate that I think you'd be better off getting
a true D/A converter and using it to drive the servo-amp. With an Arduino,
you should be able to get DAC updates of 10KHZ or better I should think,
then you can stick a LPF on that signal which is much faster than the current
one, and have really low ripple.
Yes, a proper DAC sounds so much better! I will have to ask if there's one I could borrow in the workshop tomorrow. It's a little late for me to order one now as my project is coming to an end, but I'll see what I can do  smiley-cry

Thanks for your reply
36  Using Arduino / Programming Questions / Re: 2 questions - functions outside loop; using arrays as vectors on: April 03, 2012, 06:30:04 pm
For a more "black box" approach it is better to pass data into functions, and return a result. You don't have to do it that way, but that tends to give a neater result. The type of data depends on the application. For example, if you want decimal places you use the float type.

I don't want to sound snippy, but if you search for "C tutorial" and read up on some of the basics, you will find a lot of your questions answered.
I see, that sounds better. I take it you mean something like this:
Code:
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
?

I will have to think about how I can code my controllers in a form like that. As a first idea, I'd have separate functions for say... calculating the error, and then one (for each controller) to calculate the control signal, is that a better approach to take? And yes, I'm getting a little confused with data types at the moment, but hopefully I will be able to make sense of everything after I get some sleep!

I've read through various tutorials for other things, but with these particular questions I wasn't exactly sure what to look for...

Thanks for your reply!  smiley
37  Using Arduino / Programming Questions / Re: 2 questions - functions outside loop; using arrays as vectors on: April 03, 2012, 08:19:28 am
Quote
Sorry, I have another question! For the controller functions, would they all be void as in my little snippet of code, or would I have to specify a data type (presumably double) and then return the control signal u at the end?
That's up to you to decide. The snippet you posted seems to use all global variables, so there is no need to return anything. Not the best design, but it works.
Hmm, in that case, what would you suggest? Would you rather give each controller its own set of variables?
38  Using Arduino / Programming Questions / Re: 2 questions - functions outside loop; using arrays as vectors on: April 03, 2012, 08:07:46 am
Yes.
Sorry, I have another question! For the controller functions, would they all be void as in my little snippet of code, or would I have to specify a data type (presumably double) and then return the control signal u at the end?
39  Using Arduino / Programming Questions / Re: 2 questions - functions outside loop; using arrays as vectors on: April 03, 2012, 08:04:09 am
Quote
would these functions be inactive and not do any working while another controller has been selected?
They would not be doing anything unless called.

Quote
is it possible to use arrays as vectors?
Yes.
Thank you very much Paul, I might as well lock the topic now!  smiley-wink
40  Using Arduino / Programming Questions / [Solved] 2 questions - functions outside loop; using arrays as vectors on: April 03, 2012, 07:56:33 am
Hi, it's me again, with a couple of questions smiley

First question: If I have functions outside setup() and loop(), to be called in loop() depending on the value of a variable (I am intending to use if statements for this), do these functions do anything while they are not in use? I don't want to give my Arduino more work than it has to do. To expand, I wish to have several discrete-time controllers in a sketch, with the user able to choose a controller. So if I had the calculations of each controller in their own functions, outside loop() e.g.
Code:
void P() { //or would this need to be double?
e = r - y;
u = kp*e;
would these functions be inactive and not do any working while another controller has been selected?

In loop() I would have things common to all the controllers, such as reading an analog pin, converting this value to volts, converting the control signal u to an integer and analogWriting this value.

My second question: is it possible to use arrays as vectors? I am trying to convert a Simulink model into code (Simulink never builds successfully and I have my own code to add anyway!) and in this controller there are 2-element vectors being multiplied, using the dot (scalar) and cross (vector) products in different situations. If I put the two elements into an array could I then pretend it's a vector, and calculate the dot and cross products using a little formula?

I'd really appreciate any help, as I'm going to start coding today and it would be nice to know if I'm on the right track before I've finished  smiley

Thanks,
+-
41  Using Arduino / Project Guidance / Re: Making a controller - Do I need to take the low pass filter into account? on: April 02, 2012, 08:20:15 pm
Well then theoretical the filter response will just become another part of the whole loop's response including process delay. That is why you will hardly ever find someone able to calculate the final tuning values for the P,I, and D terms, but rather manually adjusting them and watching the loop's response until optimized.


Gah, it's not telling me when I have unread replies any more!

I think what could be interesting is if I calculate my gains for a first-order (velocity) or second-order system (position), ignoring the transfer function of the low-pass filter, and then comparing it to an adaptive control scheme, to see if the results are drastically different. If I find out how to work out the PID gains for a third order system (position with low-pass filter) I will try it, but I know nothing beyond second order at the moment.

Thank you for your reply!  smiley
42  Using Arduino / Project Guidance / Re: Making a controller - Do I need to take the low pass filter into account? on: April 01, 2012, 07:58:49 am
Now it begins to make a little more sense. You are driving a real servo-motor
amplifier, and not an h-bridge type of motor, as I had thought might be the
case. Your system does take an analog input.

I probably shouldn't even be commenting here, as I'm not a graduate control
engineer, and you have a real systems engineering situation here. Maybe
someone else will comment [who knows better what they're talking about !!!].

You have to know what sort of dynamic response you want from the servo-motor,
and then choose an input signal that is in line with that. You need to choose the
gains and solve the equation shown in sections 1 and 2 of your pdf file, and
determine the Bode Plot response characteristics for the motor system. Then
you need to produce the correct input response using the Arduino.

Do you know how fast the servo-motor is supposed to sweep? Do you know
the step-response and frequency characteristics of the system under different
loading conditions?

With your R,C values, the time-constant of the low-pass filter = 2.2 msec. I
would guess that, IF your motor response time is roughly 100X slower than that,
then the Arduino analog.write might do the job. The problem is, as mentioned,
there is a good deal of ripple on the smoothed analog signal out of the filter,
and when fed into a servo-control system, that might produce a lot of jitter.
Also, you might not be able to change the analog.write output fast enough to
produce the system response that you need.

I would imagine a better solution would be to get a true D/A [digital to analog]
converter and connect that to the Arduino pins, rather than trying to use the
analog.write function.

Aside from that, to me, this is the sort of problem one solves by knowing all
the parameters, having the hardware in front of you, experimentally testing the
servo-motor, measuring its dynamic response, hooking a driver up and testing
it some more until it's working how you want it to.

IOW, this is a non-trivial problem, except maybe for a graduate control
engineer. That's about all I can say [probably should not have even opened
my mouth, ???].  Good luck.
Hello, thanks for your reply! I came in here to bump and I noticed you had replied  smiley-razz

I will be doing system identification in the next couple of days to get the plant transfer function, and from that I can look at the frequency response. I will be using a function generator to produce a swept wave with frequencies of between 0.1 and 10 Hz (I doubt the motor could go much further than that).

I have been reading about the Arduino's built-in Timers, which I can use to increase the frequency of the PWM (to 976 Hz, 3906 Hz for example), and this will decrease the ripple voltage. I was thinking of having the control loop run for 10 ms an iteration, maybe 100. I will calculate a sampling interval after I have a plant TF.

But... as useful as all of this is, I think these issues are all separate from this control issue, and I will have to consider this after system identification smiley-razz

Quote
I have not found any documentation regarding PWM.
What sort? Have you seen this basic introduction:-
http://www.thebox.myzen.co.uk/Tutorial/PWM.html

It is not clear what you are trying to do. It sounds like you have a more theoretical question than a practical one.
Are you implementing a closed loop servo system?
Sorry! To clarify, I meant documentation related to my servo amp being able to use PWM (which suggests that it doesn't)

Yes, I'd say my question was almost purely theoretical. Yes, I am using my Arduino as a controller in the closed loop. The problem I have is that I am converting the PWM, 'analog output' to a (relatively) smooth signal using an RC filter... but the RC filter has its own transfer function. So I am not sure if, when I am calculating my gains (for say, a PID controller), I need to include the transfer function of the LP filter, as it would effectively add another order to the plant transfer function.  smiley-eek

Thank you both
 smiley-wink
43  Using Arduino / Project Guidance / Re: Making a controller - Do I need to take the low pass filter into account? on: March 30, 2012, 08:07:07 pm
I really have no idea what you're asking [????], and your link didn't seem to work,
but after some massaging I got to here, which shows a different transfer
function:

http://sim.okawa-denshi.jp/en/PWMtool.php

However, the other link above the text on that page is much more straightforward,
and is the formula I've used for many years to compute 1st-order 3dB rolloff
frequency:

http://sim.okawa-denshi.jp/en/CRlowkeisan.htm

F3dB = 1 / (2 * PI * R C)

Basically this is a simple low-pass filter that smooths out the PWM signal to give
a DC voltage with some small ripple riding on top.

Is your motor controller supposed to be taking a DC voltage input? Most motor
controllers, it seems to me, actually use the PWM directly. ????
Hello, sorry about the link! Fixed it now  smiley-razz

The link doesn't use the same values that I'm using (for the record, I used 976 Hz, R = 22k, C = 100n).

I was under the impression that it took a DC voltage input, I have not found any documentation regarding PWM. I intend to plug the Arduino into a pre-amp unit which provides a push-pull output to the servo amplifier, to allow rotation in both directions. I believe the pre-amp sums several inputs, so there is an op-amp in there, which should be able to handle PWM, right? Now, I'm not sure if the servo amplifier could handle PWM...

Let me try to find a picture of the servo amp... please see page 2: http://www.ee.hacettepe.edu.tr/~solen/ELE356/exp2.pdf

I don't think PWM would work with it, because it will be going in both directions, which implies a negative voltage (while in reverse). In this case, we return to my original question.
44  Using Arduino / Project Guidance / Making a controller - Do I need to take the low pass filter into account? on: March 30, 2012, 07:22:29 pm
Hi everyone  smiley

This is something that's been on my mind for a few days. I have a low pass filter to convert the Arduino's PWM output (I will be changing the setting for Timer1 to increase the PWM frequency), with a settling time under 0.01s. The transfer function according to this page is 454.54545/(s + 454.54545), and I was just wondering if it was absolutely necessary to take it into account when I select my controller gains. I ask this because I don't know how to work out gains for third-order systems! (I will be controlling a motor; its position [1st order TF] and velocity [2nd order TF], and including the low-pass filter would add another order  smiley-cry )

Thanks,
+-
45  Using Arduino / Project Guidance / Re: Controllers using PID library and Simulink - do I need to convert to volts? on: March 28, 2012, 11:35:09 am
Not real sure what you mean...

Analogread is going to convert the voltage on its pin to a number from 0 to 1023. You need to know what this number means - voltage, degrees, velocity... and how to scale it for the PID routine. Perhaps you can use this raw number, perhaps you will convert it to a number that means more to you when you look at it. Does the PID work with reals or ints? That will have the biggest influence as to what you do with that number. The more range you have to work with the better results you will get from the PID. You then will have to scale the output from the PID to 0-255 for analog write.
Hi, thanks for your reply!

To expand on my original question, I am controlling a motor, and I will be controlling both the velocity and the position. I understand that the motor's tachometer gives an output proportional to the 'speed', and the potentiometer connected to the shaft maps 0 - 360 to -10 - +10 volts. So in both cases, the output is volts. In-between the motor and the Arduino, I have some circuits that scale [-10,+10]V to [0,5]V (and the other way round for the Arduino output). So when the Arduino reads the values of the analog pins that the vel. and pos. feedback are connected to, it will give a value from 0 to 1023, depending on the voltage.

Since I will be entering the desired speed or angle as a number, I could either convert it into a value from 0 to 1023, or to volts, in which case I would also need to convert the feedback readings to volts as well.

I'm just not sure whether I should convert everything to [0,1023] or volts (using value/1023 x 5) and then letting the controller do its thing. I will then have to convert the control signal to [0,255], either by dividing by ~4, or using another formula for the voltage.

I haven't finished reading all the documentation for the PID library, unfortunately, so I'm not sure whether it uses the AnalogRead value, or if it needs volts, but I have spoken to a couple of people who are doing similar projects using pseudo-code (not the library) who said they converted values to volts.

Thank you,
+-
Pages: 1 2 [3] 4