Question for someone better at maths than me :-)

Hi all.
I have a question that is doing my head in trying to figure it out.
Heres the scenario. I have a GPS unit and I have a color LCD that I am displaying the heading on....using TinyGPS library for this.

What I want to do is, I have a circle showing N E S W on it, like a compass, but what I want to do is show an indicator on the circle to show the course, i.e. 45 deg,145deg etc.

What I am having trouble with is how to work out where to put a colored pixel to show what way I am heading.

I am also using the GLCDI2C library for the LCD.

So I draw the circle as below:
maxX=160
MaxY=128
45 = the radius

lcd.circle(maxX >> 1, (maxY-15) >> 1, 45);

If I wanted to put a colored pixcel to show 25deg for example, what is the math calculation I need to used to work out where to draw the pixcel?

I hope I have provided enough info :blush:

Thanks, Jeremy

You will probably need trig for that, unless you use a lookup table.
Convert the degrees to radians, then use sin and cos to get the x/y offsets from center circle.
http://arduino.cc/en/Reference/Sin
http://arduino.cc/en/Reference/Cos

Actually its easy.
You just have to know how to plot a circle in the first place. :slight_smile:
You just plot sin(a) against cos(a) over 360 degrees or 2PI radians depending on your trig functions.

try

plot(x_center_offset + R * sin(a), y_center_offset + R * cos(a));
or draw a line from xCenter, yCenter to the above 2

dont know if its plot(), havent look at your lib, but the principle is correct.
you may have to play with the + or - and swap the sin and cos depending on where your origin is.
Top left, bottom left etc

.... Simon

remember that when you plot a point you should remember the previous value to clear stuf.

so the function to plot a pixel should look something like .. (code is partial/not tested)

do_plot(int degrees)
{
  x = midX + cos(degrees) * radius;
  y = midY + sin(degrees) * radius;
  plot(x,y, color);
  if (prevX != x || prevY != y) 
  {
    plox(prevX, prevY, 0); // clear
    prevX = x; // remember current point
    prevY = y;
  }
}

Thanks heaps for that. I managed to get is SORT of working :slight_smile: by that I mean, I see pixels now, but not quit going in the right direction :slight_smile:
But I can figure that one out :*

Jeremy

please post your final code if things work for future reference

The sin and cos parameter is radians, not degrees. You must convert from degrees to radians.

edit: Using an array to store the sin/cos values (lookup table) has proven to be much faster and simpler to use for me. It works well when accuracy required is a degree or two. A second hand on an analog clock moves 6 degrees per second. Last I checked, that is 16 entries in a lookup table.

Last I checked, that is 16 entries in a lookup table

with some folding yes.
Instead of the sin/cos values in the lookup table you could put the (delta XY) coordinates in it.

e.g for a radius of 25 pixels it would be (according to excel :slight_smile:

int offsets = {0, 2, 5, 7, 10, 12, 14, 16, 18, 20, 21, 22, 23, 24, 24, 25}

Nice, Rob! :slight_smile:

Now all you would need to do is compute the quadrant to tell whether to add or subtract each value. That is the sine table, and "backwards" is the cosine. I see a division and a modulus to get the quadrant and the offsets for that quadrant.

precisely, should be really fast.

I had a little spare time and curiosity. Here is a sketch that prints all the important stuff for a clock. For heading, divide degrees by 6. It is a 25 pixel radius centered at 25,25.

int offsets[] = {0, 2, 5, 7, 10, 12, 14, 16, 18, 20, 21, 22, 23, 24, 24, 25};
int newQuad;
int newPos;
int newSeconds=0;
int xOff;
int yOff;

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.print("Seconds: ");
  Serial.print(newSeconds);

  newQuad = newSeconds/15;
  newPos = newSeconds%15;

  Serial.print("  Quadrant: ");
  Serial.print(newQuad);
  Serial.print("  Position: ");
  Serial.print(newPos);

  switch(newQuad) {
    case 0:  xOff = 25 + offsets[newPos];
              yOff = 25 - offsets[15 - newPos];
              break;
    case 1:  xOff = 25 + offsets[15 - newPos];
              yOff = 25 + offsets[newPos];
              break;
    case 2:  xOff = 25 - offsets[newPos];
              yOff = 25 + offsets[15 - newPos];
              break;
    case 3:  xOff = 25 - offsets[15 - newPos];
              yOff = 25 - offsets[newPos];
              break;
  }
  
  Serial.print(" LCD X: ");
  Serial.print(xOff);
  Serial.print("  Y: ");
  Serial.println(yOff);
  
  newSeconds++;

  if(newSeconds > 59) newSeconds = 0;
  delay(1000);  
}

that's what I call co-development :slight_smile:

code proofs the concept quite well.

SurferTim:
edit: Using an array to store the sin/cos values (lookup table) has proven to be much faster and simpler to use for me. It works well when accuracy required is a degree or two.

Funny I did something like that few days ago, unfortunately it's slower than calling sin/cos directly, because I put that array in progmem... If array is in ram of course it's much faster :slight_smile:

guix:
Funny I did something like that few days ago, unfortunately it's slower than calling sin/cos directly, because I put that array in progmem... If array is in ram of course it's much faster :slight_smile:

There is no way those sin/cos functions are faster than a lookup table. It had to have been your coding.

No try it :wink:

guix:
No try it :wink:

I have, many times. You may think you are talking to an amateur, but that assumption would be incorrect.

Funny I did something like that few days ago, unfortunately it's slower than calling sin/cos directly, because I put that array in progmem... If array is in ram of course it's much faster

please post your code, as

You can check my sin/cos lookup table [182 bytes] + code here - Arduino Forum -
factor 2.5 faster, and without interpolation even more.

:astonished: Sorry, I was wrong (and that’s cool!) I don’t know what I did wrong in my previous test but I remember using an array in progmem was a little slower than using sin directly :S

Now…

Chrono 01 - { for (float j = 0.0; j < 360.0; j+=0.1) x = sinDegree1(j); } - 10 calls...
Average (microseconds) :   43075.20

Chrono 02 - { for (float j = 0.0; j < 360.0; j+=0.1) x = sinDegree2(j); } - 10 calls...
Average (microseconds) :   43074.80

Chrono 03 - { for (float j = 0.0; j < 360.0; j+=0.1) x = sinDegree3(j); } - 10 calls...
Average (microseconds) :  589187.63

0.84
0.84
0.83

I’m surprised progmem is as fast as ram :slight_smile:

Oh and good code Rob’, I will try it :slight_smile:

test_sin_array.ino (9.26 KB)

I learn more from being wrong than being right. :slight_smile: