My project requires rotating a servo motor to various degrees at constant time increments. The position as a function of time is calculated as a composite of sine waves of various amplitudes, frequencies, and time offsets.
Currently, I am calculating these positions in excel and manually imputing these values into an array in my sketch. Now, however, I would like to use a much higher precision of positions, which requires a much larger array (500+ values). I am aware of the following issues & options, and would love your input on the best way to proceed:
-RAM limitations being what they are, storing my array in PROGMEM. And retrieving the values for this array from a .txt file by using a Processing sketch. Or storing the array as a .txt file on an SD card, and retrieving the values directly from there using the Arduino sketch.
-Making the calculations realtime on the Arduino, which seems so much easier than the previous option. But, is this an okay thing to do if I am trying to update the position every ~2 milliseconds? Should I expect an unreasonable amount of computational delay (>0.1 milliseconds) if I am computing multiple sine functions every 2 milliseconds?
I have a habit of over-complicating things. So please let me know if there is a clearly easiest way to do this. Thank you!
It is rather easy to time calculations. Just record the time in milliseconds using the millis() function, do any sort of calculation, then get the time again and subtract.
If the time taken is less than 1 millisecond, repeat the calculation (say 100 times in the inner loop) in order to get a better estimate.
I think you should be able to calculate a number of sines/cosines in 2 milliseconds. The times have been posted somewhere.
gcloudfarmer:
Currently, I am calculating these positions in excel and manually imputing these values into an array in my sketch. Now, however, I would like to use a much higher precision of positions, which requires a much larger array (500+ values). I am aware of the following issues & options, and would love your input on the best way to proceed:
Good News For You!
You can store a lookup table in flash along with the program. Keyword is PROGMEM, there are threads and tutorials but I would also ask which are dated (old IDE version info) and which work now and any simple examples you can get.
Your sketch is probably less than 10KB? There is 32KB flash on Uno/all-ATmega328P-duinos.
You should be able to look up values in a few microseconds at 16 cycles per micro.
I calculate the servo angles on the fly for 18 servos for my hexapod. I had an array of 200 xyz coordinates for the foot of a leg. 50 times a second I grabbed the next foot position out of the array, ran it through inverse kinematics and wrote the result to the servos.
As I recall, arctan() was an expensive function time wise. We could complete the calculations but with little leeway. We went out and got an approximation for arctan() and then most of the time was idle, waiting for the next compute cycle to start.
We had 20ms to work with between each servo frame. Are you using a servo with a higher frame rate? The newer digital ones have a higher rate.
Thank you all for your replies! I ended up storing my array (servo positions) in PROGMEM and retrieving them via the following code:
#include <Servo.h>
#include <avr/pgmspace.h>
Servo myservo;
const int ServoPos[] PROGMEM = {1,2,3,4,etc...};
const long interval = 1000;
int pos = 1500;
int Index = 0;
unsigned long lastUpdate = 0;
void setup() {
myservo.attach(9);
}
void loop() {
if (micros() - lastUpdate >= interval) {
lastUpdate = micros();
Index = Index + 1;
pos = pgm_read_word_near(ServoPos + Index);
myservo.writeMicroseconds(pos);
}
}
I am wondering now if, instead of calculating my servo position array in an excel sheet and copying them over, I can write a function in the arduino IDE that will calculate the positions and store them in PROGMEM once I upload the sketch?
My research into storing things into PROGMEM from functions didn't lead to very clear understanding. Any help in understanding this would be much appreciated! Thanks!
Why would you manually input the values from Excel? Use formulas to format the data, then just copy and paste it over. That's what I did when I needed to generate bitmaps for a POV display.
You can write a separate program that will produce a bunch of data statements, containing formulas, for inclusion in your Arduino source code. Example:
#include <avr/pgmspace.h>
#define OFF1 1.0
const int ServoPos[1] PROGMEM = {(int) 499.*sin(.001+OFF1)};
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("starting");
Serial.println(pgm_read_word_near(ServoPos));
}
void loop() {
// put your main code here, to run repeatedly:
}}
jremington:
You can write a separate program that will produce a bunch of data statements, containing formulas, for inclusion in your Arduino source code. Example:
#include <avr/pgmspace.h>
#define OFF1 1.0
const int ServoPos[1] PROGMEM = {(int) 499.*sin(.001+OFF1)};
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("starting");
Serial.println(pgm_read_word_near(ServoPos));
}
void loop() {
// put your main code here, to run repeatedly:
}}
From what you said, that sounds like what I want to do. But, I don't understand your example and how to implement it.
What do you mean when you say a "separate program"? Can't I only upload one sketch to the arduino at a time?
In your example code, it looks like the ServoPos array has only one value in it. This value is calculated based on previously defined parameters, which is exactly what I am looking for. But, could this be easily turned into a 200 element array? I also am not sure what purpose the "(int)" has inside the ServoPos array.
jremington:
You can write a separate program that will produce a bunch of data statements, containing formulas, for inclusion in your Arduino source code. Example:
#include <avr/pgmspace.h>
#define OFF1 1.0
const int ServoPos[1] PROGMEM = {(int) 499.*sin(.001+OFF1)};
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("starting");
Serial.println(pgm_read_word_near(ServoPos));
}
void loop() {
// put your main code here, to run repeatedly:
}}
Don't do that. That's just about the most inefficient way to generate large tables.
Jiggy-Ninja:
Why would you manually input the values from Excel? Use formulas to format the data, then just copy and paste it over. That's what I did when I needed to generate bitmaps for a POV display.
It is a little embarrassing, but I currently populate a column of calculated values in Excel, populate a column of commas next to it, and copy/paste that over to my ServoPos array in my arduino sketch. It works great, and doesn't require too much manual entry, but everything would be so much cleaner if I could just calculate everything in my arduino sketch.
Juraj:
What is the interval of calculated values? Can you store them in one byte? 200 bytes is not so match
The calculated values are 3-4 digit integers, irregularly intervaled. My initial example code was a little misleading. The ServoPos array looks more like {1386, 1455, 1500, 1633, 1883, ...}. Can't store them as individual bytes.
Jiggy-Ninja:
Don't do that. That's just about the most inefficient way to generate large tables.
Is there an efficient way to generate these large tables (values calculated from a composite sinusoidal equation with predefined parameters and incrementing time steps) within the arduino sketch?
gcloudfarmer:
The calculated values are 3-4 digit integers, irregularly intervaled. My initial example code was a little misleading. The ServoPos array looks more like {1386, 1455, 1500, 1633, 1883, ...}. Can't store them as individual bytes.
and the interval? is the precision to the last digit needed? can't you divide with 10?
gcloudfarmer:
It is a little embarrassing, but I currently populate a column of calculated values in Excel, populate a column of commas next to it, and copy/paste that over to my ServoPos array in my arduino sketch. It works great, and doesn't require too much manual entry, but everything would be so much cleaner if I could just calculate everything in my arduino sketch.
Not really. However you do it, you'll still need one equation per entry in the table. There's no concise way to populate a PROGMEM table.
Is there an efficient way to generate these large tables (values calculated from a composite sinusoidal equation with predefined parameters and incrementing time steps) within the arduino sketch?
I'd just stick with the Excel method. If you want better organization, put each table in a separate .h file and #include it in the main sketch file.