# Linear compass display to use with a MPU

**URL:** <https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060>\
**Category:** Electronics (Arduino, etc.)\
**Created:** [March 9, 2026, 8:18pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060 "2026-03-09T20:18:02Z")\
**Posts on this page:** 16\
**Page:** 3

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [April 21, 2026, 12:25am UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/43 "2026-04-21T00:25:05Z")

</div>

@glv

Was reading some material in the reference and had squirrel moment.

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/d/3/d35a6d0fa68a24622347e97f3998961f53691251.png)

> **CODE**
>
> ```processing
> PGraphics sqahm;
> PGraphics acft;
> 
> PShape plane;
> 
> int pitch;
> int yaw;
> int roll;
> 
> void setup()
> {
> size(800,400,P3D);
> 
> sqahm = createGraphics(300,300,P3D);
> acft = createGraphics(300,300,P3D);
>  
> plane = loadShape("model.obj");
>  
> 
> }
> 
> void draw()
> {
> //background(0); 
>    
>   
>   
> sqahm.beginDraw();
> smooth();
> sqHorz();
> image(sqahm, 50, 50);
> sqahm.endDraw();
>   
> acft.beginDraw();
> smooth();
> toyP();
> image(acft, 450, 50);
> acft.endDraw();
>   
>  
>   
>   
>   
> pitch = ((int) map(mouseY,0, 300, 0, 360));
> roll = ((int) map(mouseX,0, 360, 0, 360));
>   
>   
> }
> 
> void sqHorz()
> {
> sqahm.background(0);
> sqahm.translate(150,150); 
> sqahm.stroke(0);
>    
> println("PITCH: ",pitch + " ROLL: ", roll);
>   
> sqahm.pushMatrix();
> 
> sqahm.rotate(radians(roll%360));
>  
> sqahm.noStroke();
>   
> sqahm.fill(0, 180, 255); // SKY COLOR
> sqahm.rect(-250, -250, width+100, height+100);
>   
> sqahm.fill(95, 55, 40); // GROUND COLOR
> sqahm.rect(-250, pitch-250 , width+100, height);
>   
> sqahm.stroke(255);
> sqahm.strokeWeight(1);
> sqahm.line(-250, pitch-250, 250, pitch-250); // Draw line to see center of horizon separation
>   
> sqahm.popMatrix();
>   
> sqahm.stroke(255);
> sqahm.strokeWeight(1);
> sqahm.line(0, -100, 0, 100); // Draw cross hairs for visual reference vertical
> sqahm.line(-100, 0, 100, 0);// horizontal
>   
> sqahm.stroke(0);
> sqahm.strokeWeight(35);
> sqahm.noFill();
> sqahm.rect(-155,-155, 310, 310,75 ); // Draw the outside frame
>   
> }
> 
> void toyP()
> {
> acft.background(0);
> acft.translate(150,150,0); 
> acft.stroke(0); 
>  
>  
> acft.push();
> acft.translate(0,0,-100);
> acft.lights();
> acft.scale(60.0);
> acft.rotateZ(radians(roll%360));
> acft.rotateX(radians(-pitch%360)+45);
> acft.shape(plane);
> acft.pop();
>  
> acft.stroke(255);
> acft.strokeWeight(1);
> acft.line(0, -100, 0, 100); // Draw cross hairs for visual reference vertical
> acft.line(-100, 0, 100, 0);// horizontal
>   
> }
> 
> ```

Sorry don’t see how to upload the model

---

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [April 24, 2026, 5:00am UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/44 "2026-04-24T05:00:33Z")

</div>

@glv

Hi,

I’ve been going through the code some more. I think I’m on the right track. Just a small glitch doing a 360 pitch.

> **CODE**
>
> ```processing
> import processing.serial.*;
> Serial fd;
> 
> PGraphics sqahm;
> PGraphics acft;
> 
> PShape plane;
> 
> int pitch;
> int yaw;
> int roll;
> int acftY;
> int acftRoll;
> 
> void setup()
> {
> size(800, 400, P3D);
> 
> // fd = new Serial(this, Serial.list()[1], 115200);
> // fd.bufferUntil('\n');
> sqahm = createGraphics(300, 300, P3D);
> acft = createGraphics(300, 300, P3D);
> 
> // plane = loadShape("model.obj");
> }
> 
> void draw()
> {
> //background(0);
> 
> sqahm.beginDraw();
> smooth();
> sqHorz();
> image(sqahm, 50, 50);
> sqahm.endDraw();
> 
> acft.beginDraw();
> smooth();
> toyP();
> image(acft, 450, 50);
> acft.endDraw();
> 
> acftY = ((int) map(mouseY, 0, 300, 0, 360)); //MOUSE
> acftY = 360-(acftY+106)%360;
> // acftY = ((int) map(pitch,0, 300, 0, 360)); //MPU
> // acftY = 360-(pitch+106)%360;
> 
> acftRoll = ((int) map(mouseX, 0, 360, 0, 360)); //MOUSE
> acftRoll = 360-(acftRoll%360);
> //acftRoll = ((int) map(roll,0, 360, 0, 360));
> //acftRoll = 360-(roll%360);
> }
> 
> void sqHorz()
> {
> sqahm.background(0);
> sqahm.translate(150, 150);
> sqahm.stroke(0);
> 
> println("PITCH: ", pitch + " ROLL: ", roll);
> 
> sqahm.pushMatrix();
> 
> sqahm.rotate(radians(acftRoll%360));
> 
> sqahm.noStroke();
> 
> sqahm.fill(0, 180, 255); // SKY COLOR
> sqahm.rect(-250, -250, width+100, height+100);
> 
> sqahm.fill(95, 55, 40); // GROUND COLOR
> sqahm.rect(-250, ((acftY%360)-250), width+100, (acftY%360)+225);
> 
> sqahm.stroke(255);
> sqahm.strokeWeight(1);
> sqahm.line(-250, (acftY-250), 250, (acftY-250)); // Draw line to see center of horizon separation
> 
> sqahm.popMatrix();
> 
> sqahm.stroke(255);
> sqahm.strokeWeight(1);
> sqahm.line(0, -100, 0, 100); // Draw cross hairs for visual reference vertical
> sqahm.line(-100, 0, 100, 0);// horizontal
> 
> sqahm.stroke(0);
> sqahm.strokeWeight(35);
> sqahm.noFill();
> sqahm.rect(-155, -155, 310, 310, 75 ); // Draw the outside frame
> }
> 
> void toyP()
> {
> acft.background(0);
> acft.translate(150, 150, 0);
> acft.stroke(0);
> 
> acft.push();
> acft.translate(0, 0, -100);
> acft.lights();
> acft.scale(60.0);
> acft.rotateZ(radians(acftRoll%360));
> acft.rotateX(radians(-acftY%360)+45);
> //acft.shape(plane);
> acft.pop();
> 
> acft.stroke(255);
> acft.strokeWeight(1);
> acft.line(0, -100, 0, 100); // Draw cross hairs for visual reference vertical
> acft.line(-100, 0, 100, 0);// horizontal
> }
> // ***************************************************
> //*
> // ***************************************************
> void serialEvent (Serial fd)
> {
> // get the ASCII string:
> String rpstr = fd.readStringUntil('\n');
> if (rpstr != null) {
> String[] list = split(rpstr, ':');
> pitch = ((int)float(list[0]));
> roll = ((int)float(list[1]));
> yaw = ((int)float(list[2]));
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [April 24, 2026, 6:52pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/45 "2026-04-24T18:52:37Z")

</div>

@philtkp

An example:

```processing
void setup()
  {
  size(400, 200);
  }
  
void draw()
  {
  int a = (int) map(mouseX, 0, 400, 0, 3*360); // I used 3*360 but you will only need 1*360
  strokeWeight(1);
  
  //int mx = a%360;
  int mx = ((a % 360) + 360) % 360; // 0..359, safe for larger angles
  int t = mx%180;    
  float split = 20+t*2;
  
  color c0 = 0;
  color c1 = 0;
  
  if (mx >= 180)
    {
    c0 = color(255, 0, 0);
    c1 = color(0, 255, 0);
    }
  else
    {
    c1 = color(255, 0, 0);
    c0 = color(0, 255, 0);
    }  
       
  for (int i = 0; i<100; i++)  
    {
    stroke(c0);
    int yl = i+50;
    line (20, yl, 
          split, yl);
  
    stroke(c1);
    line (split, yl, 
          380, yl); 
    }
  }

```

This can be adapted to a rectangle.  
I had a single _line()_ for this example and added a loop instead of making a _rect()_.

`:)`

---

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [April 25, 2026, 9:13pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/46 "2026-04-25T21:13:32Z")

</div>

@glv

I was able to get it to get your example to give me pitch, I’m not sure what I’m doing wrong for the rotate

> **Summary**
>
> ```processing
> import processing.serial.*;
> Serial fd;
> 
> int pitch;
> int yaw;
> int roll;
> void setup()
> {
> size(400, 400);
> 
> // fd = new Serial(this, Serial.list()[1], 115200);
> // fd.bufferUntil('\n');
> background(0);
> }
> 
> void draw()
> {
> 
> translate(0, 0);
> pushMatrix();
> int a = (int) map((mouseY%360)+295, 0, 400, 0, 360); // I used 3*360 but you will only need 1*360
> strokeWeight(1); // +295 to center horizon
> 
> //int mx = a%360;
> int mx = ((a % 360) + 360) % 360; // 0..359, safe for larger angles
> int t = mx%180;
> float split = 20+t*2;
> 
> color c0 = 0;
> color c1 = 0;
> 
> pushMatrix();
> translate(width/2, height/2);
> rotate((mouseX%360));
> popMatrix();
>   
> if (mx >= 180)
> {
> c0 = color(0, 180, 255);
> c1 = color(95, 55, 40);
> } else
> {
> c1 = color(0, 180, 255);
> c0 = color(95, 55, 40);
> }
> 
> for (int i = 0; i<390; i++)
> {
> stroke(c0);
> int yl = i+5;
> line (yl, 5, yl, split);
> println("yl", yl);
> stroke(c1);
> line (yl, split, yl, 395);
> }
> popMatrix();
> }
> // ***************************************************
> //*
> // ***************************************************
> void serialEvent (Serial fd)
> {
> // get the ASCII string:
> String rpstr = fd.readStringUntil('\n');
> if (rpstr != null) {
> String[] list = split(rpstr, ':');
> pitch = ((int)float(list[0]));
> roll = ((int)float(list[1]));
> yaw = ((int)float(list[2]));
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [April 25, 2026, 10:31pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/47 "2026-04-25T22:31:46Z")

</div>

Hello @philtkp,

I am sharing concepts and it is not always plug and play.  
There are many approaches to this.

One approach with code I provided:

```processing
float pitch;
float roll;

void setup()
  {
  size(400, 400);
  background(0);
  }

void draw()
  {
  background(0);
 
 pitch = constrain(mouseY, 100, 300);
 roll = radians(mouseX%360); // MUST be radians!
 
 // Isolate this within a push() and pop() May not be needed but future ready!
 pushMatrix();  
  // What the heck! 
  // Split this into steps (comment out) and see what is happening.
  translate(width/2, height/2); //0 Trnaslate to center now (0, 0)
  rotate(roll); //1 Rotate about the center (0, 0)
  translate(-width/2, -height/2); //2 Translate back 
   
  fill(128);
  rect(100, 100, 200, 200);
  fill(255);
  
  rect(pitch, 100, 5, 200);
  circle(width/2, height/2, 10);
 popMatrix();  
}

```

These can be a real challenge to understand when rotating something with a center other than 0, 0 origin.  
Break it into steps by commenting out the transforms and seeing what they do .  
Try all commented and then 0, 01, 012 uncommented …

It may be easier to make a `PGraphic` and then center the image with `imageMode`.

Have fun!

`:)`

---

<div class="post-metadata">

**Author:** ![HackinHarry](https://avatars.discourse-cdn.com/v4/letter/h/3e96dc/32.png) [@HackinHarry](https://discourse.processing.org/u/HackinHarry)\
**Post date:** [April 26, 2026, 2:19am UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/48 "2026-04-26T02:19:14Z")

</div>

I’ve been down this road a few times with a BNO055 and also a GY gyro and acc, and a separate magnetometer. For the magnetometer only attempt, I borrowed a set of .PNG that were super realistic looking. The creator of the .PNG was someone in Poland. I even had some calibration code that made it very accurate for my location. It’s a challenging exercise for sure.

---

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [April 26, 2026, 2:30am UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/49 "2026-04-26T02:30:32Z")

</div>

@glv I understood that these were possible approaches. I’m grateful for what you have shared.

I’m just not understanding why this works

> **CODE**
>
> ```processing
> int pitch;
> int yaw;
> int roll;
> void setup()
> {
> size(400, 400);
> 
> // fd = new Serial(this, Serial.list()[1], 115200);
> // fd.bufferUntil('\n');
> }
> 
> void draw()
> {
> 
> translate(0, 0);
> 
> pushMatrix();
> int a = (int) map((mouseY%360)+295, 0, 400, 0, 360); // I used 3*360 but you will only need 1*360
> strokeWeight(1); // +295 to center horizon
> 
> //int mx = a%360;
> int mx = ((a % 360) + 360) % 360; // 0..359, safe for larger angles
> int t = mx%180;
> float split = 20+t*2;
> 
> color c0 = 0;
> color c1 = 0;
> 
> translate(width/2, height/2);
> rotate(radians(mouseX%360));
> translate(-width/2, -height/2);
> 
> if (mx >= 180)
> {
> c0 = color(0, 180, 255);
> c1 = color(95, 55, 40);
> } else
> {
> c1 = color(0, 180, 255);
> c0 = color(95, 55, 40);
> }
> 
> for (int i = 0; i<425; i++)
> {
> stroke(c0);
> int yl = i-25;
> line (yl, 5, yl, split);
> 
> stroke(c1);
> line (yl, split, yl, 425);
> }
> popMatrix();
> 
> noFill();
> stroke(0);
> strokeWeight(100);
> rect(5, 5, 380, 380, 75);
> }
> 
> ```

but this doesn’t

> **CODE**
>
> ```processing
> 
> import processing.serial.*;
> Serial fd;
> 
> int pitch;
> int yaw;
> int roll;
> void setup()
> {
> size(400, 400);
> 
> // fd = new Serial(this, Serial.list()[1], 115200);
> // fd.bufferUntil('\n');
> background(0);
> }
> 
> void draw()
> {
> 
> translate(0, 0);
>   
> pushMatrix();
> int a = (int) map((mouseY%360)+295, 0, 400, 0, 360); // I used 3*360 but you will only need 1*360
> strokeWeight(1); // +295 to center horizon
> 
> //int mx = a%360;
> int mx = ((a % 360) + 360) % 360; // 0..359, safe for larger angles
> int t = mx%180;
> float split = 20+t*2;
> 
> color c0 = 0;
> color c1 = 0;
> 
> pushMatrix();
> translate(width/2, height/2);
> rotate(radians(mouseX%360));
> popMatrix();
> 
> if (mx >= 180)
> {
> c0 = color(0, 180, 255);
> c1 = color(95, 55, 40);
> } else
> {
> c1 = color(0, 180, 255);
> c0 = color(95, 55, 40);
> }
> 
> for (int i = 0; i<390; i++)
> {
> stroke(c0);
> int yl = i+5;
> line (yl, 5, yl, split);
> println("yl", yl);
> stroke(c1);
> line (yl, split, yl, 395);
> }
> popMatrix();
>   
> noFill();
> stroke(0);
> strokeWeight(100);
> rect(5, 5, 380, 380, 75);
> }
> // ***************************************************
> //*
> // ***************************************************
> void serialEvent (Serial fd)
> {
> // get the ASCII string:
> String rpstr = fd.readStringUntil('\n');
> if (rpstr != null) {
> String[] list = split(rpstr, ':');
> pitch = ((int)float(list[0]));
> roll = ((int)float(list[1]));
> yaw = ((int)float(list[2]));
> }
> }
> 
> ```

Thanks

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [April 26, 2026, 4:14pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/50 "2026-04-26T16:14:01Z")

</div>

This may help:

```processing
//int pitch;
//int yaw;
//int roll;

float rx, ry;

void setup()
{
  size(800, 800);
  background(0);
}

void draw()
{
  background(0);
  // translate(0, 0); //No effect here. Already at 0, 0 (upper left of sketch)
  
  // Difficult to understand.
  //int a = (int) map((mouseY%360)+295, 0, 400, 0, 360); // +295 to center horizon
  
  // Simplified and added phaseshift (ps) below of 90. 270 also works. Any value works!
  int a = (int) map(mouseY, 0, height, 0, 360);
  println(a);
                                   
  int ps = 90; // try other values!
  int mx = ((a%360) + 360 + ps) % 360; // 0..359, safe for larger angles
  int t = mx%180; // 360/2 = 180 the halfway mark that rolls over
  float split = 20+t*2;
  //println(split);

 pushMatrix(); //0 start // The push() pop() pair not needed in this example. No harm leaving.
  
// *****************************
// This does nothing in the code!
// You need elements (shapes, text, image, etc.) to transform between push() and pop()
  pushMatrix(); //1 start
  translate(width/2, height/2);
  rotate(radians(mouseX%360));
  popMatrix(); //1 end
// *****************************    
  
  float rxo = 20 + rx;
  float ryo = 20 + ry;
  
  float rxc = 360/2 +rxo; // See below for rect() dimensions and origin.
  float ryc = 360/2 +ryo; // ...
  
// Move the coordinate system to the rectangle's centre.
// The rectangle's centre is used as the fixed rotation point (pivot).
// Rotate around the rectangle's centre (pivot).
// Move the coordinate system back.
  //pushMatrix(); //1 start
  translate(rxc, ryc);
  rotate(radians(mouseX%360));
  translate(-rxc, -ryc);
  
  // Simplified shape (no colour)
  stroke(255);
  strokeWeight(2); 
  noFill();
  rect(rxo, ryo, 360, 360);
  line (rxo, split+ ryo, 360+rxo, split+ryo);
    
 popMatrix(); //0 end
  }
  
void keyPressed()
  {
  rx = random(0, width-360);
  ry = random(0, height-360);   
  }

```

`rx = 0 and ry = 0` initially and can be ignored!  
I added this to demonstrate this working at any location.

It may be easier with `rectMode(CENTER)` and working with the coordinate system centered `translate(width/2, height/2)`

I would replace my lines in a loop example with a rect.  
I originally had a single line and just expanded it before implementing a `rect()`.  
If you add a background() there you can see it between the lines! Increase the `strokeWeight()`

`:)`

---

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [April 29, 2026, 3:32am UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/51 "2026-04-29T03:32:57Z")

</div>

@glv

I’ve been looking at the code, and I think I’m starting to see the light. I’m glad that it’s only things like this that keep me up at night these days. Thank you for the explanation. I changed line() to rect() and some of the numbers. I’m happy with what I see. 🙂 🍺

> **CODE**
>
> ```processing
> //int pitch;
> //int yaw;
> //int roll;
> 
> float rx, ry;
> 
> void setup()
> {
> size(800, 800);
> background(0);
> }
> 
> void draw()
> {
> background(0);
> // translate(0, 0); //No effect here. Already at 0, 0 (upper left of sketch)
> 
> // Difficult to understand.
> //int a = (int) map((mouseY%360)+295, 0, 400, 0, 360); // +295 to center horizon
> 
> // Simplified and added phaseshift (ps) below of 90. 270 also works. Any value works!
> int a = (int) map(mouseY, 0, height, 0, 360);
> 
> int ps = 225; // try other values!
> int mx = ((a%360) + 360 + ps) % 360; // 0..359, safe for larger angles
> int t = mx%180; // 360/2 = 180 the halfway mark that rolls over
> float split = 20+t*4;
> //println(split);
> println("A:", a +" SPLIT:", split);
> pushMatrix(); //0 start // The push() pop() pair not needed in this example. No harm leaving.
> 
> float rxo = 20 + rx;
> float ryo = 20 + ry;
> 
> float rxc = 360/2 +rxo; // See below for rect() dimensions and origin.
> float ryc = 360/2 +ryo; // ...
> 
> // Move the coordinate system to the rectangle's centre.
> // The rectangle's centre is used as the fixed rotation point (pivot).
> // Rotate around the rectangle's centre (pivot).
> // Move the coordinate system back.
> //pushMatrix(); //1 start
> translate(rxc, ryc);
> rotate(radians(mouseX%360));
> translate(-rxc, -ryc);
> 
> // Simplified shape (no colour)
> stroke(255);
> strokeWeight(2);
> noFill();
> rect(rxo, ryo, 360, 360);
> strokeWeight(2);
> rect (rxo-20, height/2-split, 360+20 + rxo, height/2);
> println("ryo:", ryo +" SPLIT:", split + " total: ", (split+ryo));
> popMatrix(); //0 end
> }
> 
> void keyPressed()
> {
> rx = random(0, width-360);
> ry = random(0, height-360);
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [April 30, 2026, 11:49pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/52 "2026-04-30T23:49:35Z")

</div>

@philtkp,

That is certainly one approach that works!

I tinkered with your code a bit:

> **Summary**
>
> ```processing
> PGraphics pg;
> 
> void setup()
> {
> size(800, 800);
> background(0); 
> pg = createGraphics(360, 360);
> }
> 
> void draw()
> {
> background(0);
> // translate(0, 0); //No effect here. Already at 0, 0 (upper left of sketch)
> 
> // Difficult to understand.
> //int a = (int) map((mouseY%360)+295, 0, 400, 0, 360); // +295 to center horizon
> 
> // Simplified and added phaseshift (ps) below of 90. 270 also works. Any value works!
> int a = (int) map(mouseY, 0, height, 0, 360);
> 
> int ps = 45; // try other values!
> int mx = ((a%360) + 360 + ps) % 360; // 0..359, safe for larger angles
> int t = mx%180; // 360/2 = 180 the halfway mark that rolls over
> float split = t*4; // Removed the +20
>  
> // Changing this showed errors later and you can see fix:
> float rxo = 180;
> float ryo = 180;
> 
> float rxc = 360/2 +rxo; // See below for rect() dimensions and origin.
> float ryc = 360/2 +ryo; // ...
> 
> // Move the coordinate system to the rectangle's centre.
> // The rectangle's centre is used as the fixed rotation point (pivot).
> // Rotate around the rectangle's centre (pivot).
> // Move the coordinate system back.
> //pushMatrix(); //1 start
>   
> // I did not include this:
> //pgMake();  
> //image(pg, 0, 0);
>    
> if (true)
> {
> translate(rxc, ryc);
> rotate(radians(mouseX%360));
> translate(-rxc, -ryc);
>   
> // Simplified shape (no colour)
> stroke(255);
> strokeWeight(2);
> noFill();
> fill(255, 0, 0);
> stroke(255, 0, 0);  
> rect(rxo, ryo, 360, 360);
>   
> stroke(0, 255, 0); 
> fill(0, 255, 0);
> //rect (rxo, height/2-split, 360 + rxo, height/2); // Step 1
> //rect (rxo, height/2-split, 360, height/2); // Step 2
> // This is no longer coupled to the sketch window size:
> rect (rxo, ryo + 360-split, 360, 360); // Step 3
>   
> // Mask with overlay:
> fill(0);
> stroke(255, 255, 0 , 128);
> rect (rxo-20, ryo-2, 360+40, 0-rxo);
> rect (rxo-20, ryo+360+2, 360+40, height-(ryo+360)-4);
>   
> //println("ryo:", ryo +" SPLIT:", split + " total: ", ryo + 360-split);
> }
> //popMatrix(); //0 end
> }
> 
> ```

After adding the black rectangles to cover the two ends I decided to make an equivalent _PGraphics_ (not included) and the ends were not seen!

`:)`

---

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [May 1, 2026, 2:49am UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/53 "2026-05-01T02:49:45Z")

</div>

@glv like what you did. I have just one question. Why did you add the `if (true) { }` ?

Also, when using PGraphics can you share a function between two separate PGraphics windows?😕

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 1, 2026, 12:31pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/54 "2026-05-01T12:31:04Z")

</div>

> [@philtkp](#):
>
> Why did you add the `if (true) { }` ?

It uses that block of code when _true_ and does not when _false_. I was using _false_ when testing the _PGraphics_.  
Just leftovers.

> [@philtkp](#):
>
> Also, when using PGraphics can you share a function between two separate PGraphics windows?

Yes. You must give consideration to variable scope.

_[Variable Scope / Examples / Processing.org](https://processing.org/examples/variablescope.html)_

`:)`

---

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [May 1, 2026, 6:44pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/55 "2026-05-01T18:44:21Z")

</div>

I’m seeing it

this is what I’m trying to do. I want to share ctrX() with both myBx1() and myBx2() while using PGraphics.

> **example**
>
> ```processing
> PGraphics bx1;
> PGraphics bx2;
> 
> void setup() {
> size(400,200, P2D);
> 
> bx1 = createGraphics(160, 160, P2D);
> bx2 = createGraphics(160, 160, P2D);
> }
> 
> void draw() {
> 
> //background(0);
> 
> bx1.beginDraw();
> myBx1();
> bx1.endDraw();
> image(bx1, 20, 20);
>   
> bx2.beginDraw();
> myBx2();
> bx2.endDraw();
> image(bx2, 220, 20);
> }
> 
> void myBx1() {
> 
> bx1.background(23, 250, 32);
> ctrX();
>   
> }
> 
> void myBx2() {
>   
> bx2.background(250, 140, 23);
> ctrX();
> }
> 
> void ctrX(){
>   
> stroke(255);
> strokeWeight(2);
> line(0,height/2-20,width, height/2-20);
>   
> }
> 
> ```

this way i can share it with having to make two of the same functions. for each image.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 1, 2026, 7:03pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/56 "2026-05-01T19:03:39Z")

</div>

> [@philtkp](#):
>
> I want to share ctrX() with both myBx1() and myBx2() while using PGraphics.

The target `PGraphics` object is passed into into `ctrX()`, so the same helper function can draw into either `bx1` or `bx2`.

```processing
void myBx1() {
  bx1.background(23, 250, 32);
  ctrX(bx1); 
}

void myBx2() { 
  bx2.background(250, 140, 23);
  ctrX(bx2);
}

void ctrX(PGraphics p){
  p.stroke(255);
  p.strokeWeight(2);
  p.line(0,height/2-20,width, height/2-20);
}

```

The system is telling me:

> You’ve posted a lot in this topic! Consider giving others an opportunity to participate, too.

I chuckled when that popped up!

`:)`

---

<div class="post-metadata">

**Author:** ![philtkp](https://avatars.discourse-cdn.com/v4/letter/p/6a8cbe/32.png) [@philtkp](https://discourse.processing.org/u/philtkp)\
**Post date:** [May 15, 2026, 4:01am UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/57 "2026-05-15T04:01:22Z")

</div>

@glv

added all the parts together and cleaned it up a bit. Seems to work great with the GY80. I posted all the files on github. [philtkp/Linear-and-dial-compass-artificial-horizon-indicator-GY80: Processing code for GY80](https://github.com/philtkp/Linear-and-dial-compass-artificial-horizon-indicator-GY80) this will have the plane model and other things used. Thanks so much for the help and knowledge.

 ![Dials](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/b/1/b12564b8fafa3a1c4d22a48e73e9290097ac147f.jpeg)

> **CODE**
>
> ```processing
> // Alot of thanks goes to GLV for sharing his knowledge 
> 
> import processing.serial.*;
> Serial fd;
> 
> PGraphics ahi; // Artifical Horision Indicator
> PGraphics ac; // Aircraft
> PGraphics gi; // Globe Artifical horizion indicator
> PGraphics dc; // Dial Compass
> PGraphics db; // Directional Block
> PGraphics lc; // Directional Block
> 
> PImage fade;
> PImage compassglass;
> PImage earth;
> 
> PShape acft;
> PShape globe;
> 
> float SpanAngle=120;
> float yawOffset = 0.0f;
> float rxo = 180;
> float ryo = 180;
> float rxc = 360/2;
> float ryc = 360/2;
> 
> int pitch = 0;
> int roll = 0;
> int yaw = 0;
> int yawDeg = 0;
> int rollDeg = 0;
> int pitchDeg = 0;
> int degree = 0;
> int NumberOfScaleMajorDivisions;
> int NumberOfScaleMinorDivisions;
> int a;
> 
> void setup()
> {
> size(1120, 750, P3D);
> 
> //fd = new Serial(this, Serial.list()[1], 115200);
> //fd.bufferUntil('\n');
>   
> ahi = createGraphics(360, 360); // Artifical Horision Indicator
> ac = createGraphics(360, 360, P3D); // Aircraft
> gi = createGraphics(360, 360, P3D); // Globe Artifical horizion indicator
> dc = createGraphics(360, 360, P3D); // Dial Compass
> db = createGraphics(360, 360, P3D); // Directional Block
> lc = createGraphics(360, 360); // Directional Block
> 
> acft = loadShape("model.obj");
> fade = loadImage("fade2.png");
> compassglass = loadImage("compassglass.png");
> earth = loadImage( "horz.jpg");
> 
> globe = createShape(SPHERE, 200);
> globe.setStroke(false);
> globe.setTexture(earth);
> noStroke();
> }
> void draw()
> {
> 
> //background(0);
> 
> ahi.beginDraw(); // Artifical Horision Indicator
> smooth();
> myAHI();
> ahi.endDraw();
> image(ahi, 10, 10);
> 
> ac.beginDraw(); // Aircraft
> smooth();
> myac();
> ac.endDraw();
> image(ac, 380, 10);
> 
> gi.beginDraw(); // Globe Artifical horizion indicator
> smooth();
> mygi();
> gi.endDraw();
> image(gi, 750, 10);
> 
> dc.beginDraw(); // Dial Compass
> smooth();
> mydc();
> dc.endDraw();
> image(dc, 10, 380);
> 
> db.beginDraw(); // Directional Block
> smooth();
> mydb();
> db.endDraw();
> image(db, 380, 380);
> 
> lc.beginDraw(); // Directional Block
> smooth();
> mylc();
> image(lc, 750, 380);
> lc.endDraw();
> 
> a = (int) map((mouseY%360), 0, height, 0, 360);
> // a = (int) map((pitch%360), 0, height, 0, 360); // For MPU
> //pitch = (int)(a%360);
>   
> pitchDeg=(int)(a%360);
>  
> roll = ((int) map((mouseX%360), 0, 360, 0, 360));
> //roll = ((int) map((roll%360), 0, 360, 0, 360)); // For MPU
> rollDeg = (int)(roll%360);
>   
> yaw = (int)map((mouseY%360), 0, 360, 0, 360);
> //yaw = (int)map((yaw%360), 0, 360, 0, 360); // For MPU
> yawDeg = (int)(yaw%360);
>   
>   
>  
>   
> }
> 
> // **************************************
> // Arificial Horizion Indicator
> // **************************************
> void myAHI()
> {
> 
> ahi.background(0);
> ahi.stroke(255);
> ahi.noFill();
> ahi.rect(30, 30, 300, 300);
> 
> int ps = 45; // try other values!
> int mx = ((a%360) + 360 + ps) % 360; // 0..359, safe for larger angles
> int t = mx%180; // 360/2 = 180 the halfway mark that rolls over
> float split = t*4;
> ahi.pushMatrix(); //0 start // The push() pop() pair not needed in this example. No harm leaving.
> 
> float rxo = 180;
> float ryo = 180;
> 
> float rxc = 360/2; // See below for rect() dimensions and origin.
> float ryc = 360/2; // ...
> 
> ahi.translate(rxc, ryc);
> ahi.rotate(radians(roll%360));
> ahi.translate(-rxc, -ryc);
> 
> // Simplified shape (no colour)
> ahi.noStroke();
> ahi.fill(0, 180, 255); //SKY
> ahi.rect(rxo-rxo, ryo-ryo, 360, 360);
> 
> ahi.fill(95, 55, 40); //GROUND
> ahi.rect (rxo-rxo, ryo-ryo + 360-split, 360, 360);
> ahi.stroke(255);
> ahi.strokeWeight(2);
> ahi.line(rxo-ryo, (height/2-15) - split, 360+rxo, (height/2-15) - split);
>   
> ahi.translate(rxc, ryc);
> 
> PitchScale(ahi);
> Axis(ahi);
> ahi.translate(-rxc, -ryc);
> 
> ahi.popMatrix(); //0 end
> 
> ahi.push();
> ahi.translate(180, 180); // Places pitch scale center
> ahi.rotate(-PI-PI/6); // Centers upper scale
> 
> SpanAngle=120;
> NumberOfScaleMajorDivisions=12;
> NumberOfScaleMinorDivisions=24;
> 
> CircularScale(ahi);//Draws upper scale
> ahi.rotate(PI+PI/6); // Centers lower scale
> ahi.rotate(-PI/6); //
> CircularScale(ahi); //Draws lower scale
> ahi.translate(-180, -180);
> ahi.pop();
>  
> ahi.stroke(0);
> ahi.strokeWeight(70);
> ahi.noFill();
> ahi.rect(10, 10, 340, 340, 75 ); // Draw the outside frame
> ahi.rect(0, 0, 360, 360 );
> };
> // **********************************************
> // Aircraft
> void myac()
> {
> ac.background(80, 80, 80);
>  
> ac.pushMatrix();
>   
> ac.translate(rxc, ryc, -100); // center
> ac.lights();
> ac.scale(60.0);
> ac.rotateZ(radians((roll%360)-10));
> ac.rotateX(radians((a%360)*2)-135);
> 
> ac.shape(acft);
>   
> ac.popMatrix();
> 
> ac.stroke(255);
> ac.strokeWeight(1);
> ac.line(175, 180, 185, 180); // Draw cross hairs for visual reference horizontal
> ac.line(180, 175, 180, 185);
> ac.line(180, 50, 180, 150); // vertical line
> ac.line(180, 210, 180, 310);
> ac.line(50, 180, 150, 180); // horizontal line
> ac.line(210, 180, 310, 180);
> ac.noFill();
> ac.ellipse(180, 180, 35, 35); // center
> ac.stroke(0);
> ac.strokeWeight(70);
> ac.rect(10, 10, 340, 340, 75 );
> ac.rect(0, 0, 360, 360 );
> }
> 
> // ****************************************************
> // Globe Artificial horizion indicator
> // ****************************************************
> void mygi()
> {
> 
> gi.background(0);
> gi.translate(rxc, ryc, -200); // Places pitch scale center
> gi.pushMatrix();
> 
> gi.rotateX(radians((a%360)*2));
> gi.rotateZ(radians(roll%360));
> 
> gi.shape(globe);
> 
> gi.popMatrix();
> 
> gi.translate(0, 0, 200); // places pitch scaale and axis infront of globe
> 
> gi.push();
> gi.rotateZ(radians(roll%360));
>     
> PitchScale(gi);
> Axis(gi);
> gi.pop();
> 
> gi.rotate(-PI-PI/6); // Centers upper scale
>     
> SpanAngle=120;
> NumberOfScaleMajorDivisions=12;
> NumberOfScaleMinorDivisions=24;
> 
> CircularScale(gi); //Draws upper scale
> gi.rotate(PI+PI/6); // Centers lower scale
> gi.rotate(-PI/6); //
> CircularScale(gi); //Draws lower scale
> gi.rotate(PI/6); // Aligns pitch scale and axis
>   
> }
> 
> // ***************************************************
> // Dial Compass
> // ***************************************************
> 
> void mydc()
> {
> dc.background(0);
> 
> if ((int)yaw >= 1 && (int)yaw <= 180) // keeps degrees positive
> yawDeg = (int)yaw;
> else yawDeg = 360 + (int)yaw;
>   
> dc.pushMatrix();
> dc.noStroke();
> dc.fill(108, 108, 108); // Fill sky color
> dc.ellipse(180, 180, 245, 245);
> 
> // DRAW DEGREES INSIDE COMPASS
> dc.noFill();
> dc.stroke(255); //Black
> dc.rect(155, 222, 50, 30);
> dc.fill(0); //Black
> dc.rect(155, 222, 50, 30);
> dc.textSize(20);
> dc.fill(255, 255, 255);
> dc.textAlign(CENTER);
> dc.text(yawDeg%360, 180, 245);
> 
> dc.translate(180, 180);
> 
> CompassPointer(dc);
> 
> dc.popMatrix();
> dc.pushMatrix();
> 
> /* Draws the circular scale on compass */
> dc.translate(180, 180);
> dc.stroke(50);
> dc.strokeWeight(1);
> dc.noFill();
> dc.ellipse(0, 0, 245, 245);
> dc.ellipse(0, 0, 299, 299);
> SpanAngle=180;
> NumberOfScaleMajorDivisions=18;
> NumberOfScaleMinorDivisions=36;
> 
> CircularScale(dc);
> 
> dc.rotate(PI);
> SpanAngle=180;
> 
> CircularScale(dc);
> dc.rotate(-PI);
> 
> dc.translate(-300, 100);
> dc.textSize(20);
> dc.fill(255, 255, 255);
> dc.textAlign(CENTER);
> dc.text("W", 165, -92);
> dc.text("E", 432, -92);
> dc.text("N", 300, -230);
> dc.text("S", 300, 42);
> dc.rotate(PI/4);
> dc.textSize(15);
> dc.text("NW", 4, -278);
> dc.text("SE", 275, -280);
> dc.popMatrix();
> dc.rotate(-PI/4);
> dc.text("NE", 135, 258);
> dc.text("SW", -135, 258);
> dc.image(compassglass, -175, 80);
> }
> 
> // ***************************************************
> // Directional Block
> // ***************************************************
> void mydb()
> {
> db.background(0);
> 
> if ((int)pitch >= 1 && (int)pitch <= 180) // keeps degrees positive
> pitchDeg = (int)pitch;
> else pitchDeg = 360 + (int)pitch;
>   
> if ((int)roll >= 1 && (int)roll <= 180) // keeps degrees positive
> rollDeg = (int)roll;
> else rollDeg = 360 + (int)roll;
>   
> // db.pushMatrix();
> db.fill(255);
> db.textSize(16);
> db.textAlign(LEFT);
> db.text("Yaw...: " + ((int) (yawDeg%360)), 15, 25);
> db.text("Pitch.: " + ((int) (pitchDeg%360)), 15, 50);
> db.text("Roll..: " + ((int) (rollDeg%360)), 15, 75);
> // db.popMatrix();
> 
> db.pushMatrix();
> 
> db.translate(180, 180, 0);
> db.scale(.8);
> db.rotateY(-radians(yaw - yawOffset));
> db.rotateX(radians(a%360)*2);
> db.rotateZ(radians(roll%360));
> 
> //gi.rotateX(radians((a%360)*2));
> // gi.rotateZ(radians(roll%360));
> 
> buildBoxShape(db);
> 
> db.popMatrix();
> }
> 
> / ********************************************************** /
> /* DRAW LINEAR COMPASS WITH FADE
> / ********************************************************** /
> void mylc()
> {
> 
> lc.background(0);
> 
> // black rect (the whole compass)
> lc.noFill();
> lc.stroke(0); //Black
> lc.rect(30, 160, 299, 49);
> 
> // white upper par of rectangle (the display)
> lc.fill(255, 255, 255);
> lc.rect(30, 160, 299, 24);
> 
> // yellow lower part of rectangle (the display)
> lc.fill(255, 255, 2);
> lc.rect(30, 184, 299, 24);
> 
> // yellow triangle
> lc.stroke(0);// black
> lc.fill(255, 255, 2); // yellow
> lc.triangle(180-6, 177, 180+6, 177, 180, 183);
> 
> if ((int)yaw >= 1 && (int)yaw <= 180) 
> yawDeg = (int)yaw;
> else yawDeg = 360 + (int)yaw;
> 
> // DISPLAY DEGREES
> lc.stroke(0);// black
> lc.fill(0); // black
> lc.textAlign(CENTER);
> lc.textSize(16);
> lc.text(yawDeg%360, 180, 174);
> 
> // DRAW BLACK DEGREE MARKS
> lc.stroke(0); // black
> int lengthLine = 0;
> for (int i=0; i < 360; i+=5)
> {
> if (i%90==0) {
> lengthLine=9;
> } else if (i%45==0) {
> lengthLine=6;
> } else
> {
> lengthLine=3;
> }
> lc.line(((yaw)+i)%360, 185, ((yaw)+i)%360, 186+lengthLine);
> lc.fill(0);
> }
> 
> lc.textSize(14);
> lc.text("S", ((yaw+1)+360)%360, 206);
> lc.text("N", ((yaw+1)+180)%360, 206);
> lc.text("E", ((yaw+1)+270)%360, 206);
> lc.text("W", ((yaw+1)+450)%360, 206);
> lc.textSize(11);
> lc.text("NW", ((yaw)+495)%360, 205);
> lc.text("NE", ((yaw)+225)%360, 205);
> lc.text("SE", ((yaw)+315)%360, 205);
> lc.text("SW", ((yaw)+405)%360, 205);
> 
> // draw red line in display
> lc.stroke(255, 2, 2);
> lc.line(180, 185, 180, 208);
> 
> lc.image(fade, 30, 160); // load image
>   
> }
> / ********************************************************* /
> /* build cube */
> / ********************************************************* /
> void buildBoxShape(PGraphics p) {
> //box(60, 10, 40);
> p.pushMatrix();
> 
> p.translate(0, 0, 0);
> p.noStroke();
> p.beginShape(QUADS);
> 
> //Z+ (to the drawing area)
> p.fill(#00ff00);
> p.vertex(-60, -10, 100);
> p.vertex(60, -10, 100);
> p.vertex(60, 10, 100);
> p.vertex(-60, 10, 100);
> 
> //Z-
> p.fill(#0000ff);
> p.vertex(-60, -10, -100);
> p.vertex(60, -10, -100);
> p.vertex(60, 10, -100);
> p.vertex(-60, 10, -100);
> 
> //X-
> p.fill(#ff0000);
> p.vertex(-60, -10, -100);
> p.vertex(-60, -10, 100);
> p.vertex(-60, 10, 100);
> p.vertex(-60, 10, -100);
> 
> //X+
> p.fill(#ffff00);
> p.vertex(60, -10, -100);
> p.vertex(60, -10, 100);
> p.vertex(60, 10, 100);
> p.vertex(60, 10, -100);
> 
> //Y-
> p.fill(#ff00ff);
> p.vertex(-60, -10, -100);
> p.vertex(60, -10, -100);
> p.vertex(60, -10, 100);
> p.vertex(-60, -10, 100);
> 
> //Y+
> p.fill(#00ffff);
> p.vertex(-60, 10, -100);
> p.vertex(60, 10, -100);
> p.vertex(60, 10, 100);
> p.vertex(-60, 10, 100);
> 
> p.endShape();
> 
> // Draw base
> p.translate(0, 0, -115);
> p.fill(#FF8400);
> p.box(30, 20, 30);
> // Draw pointer
> 
> p.beginShape(QUAD_STRIP);
> p.vertex(-40, -10, -10);
> p.vertex(40, -10, -10);
> p.vertex(-40, 10, -10);
> p.vertex(40, 10, -10);
> 
> p.vertex(40, -10, -10);
> p.vertex(0, -10, -50);
> p.vertex(0, 10, -50);
> p.vertex(40, 10, -10);
> 
> p.vertex(-40, -10, -10);
> p.vertex(0, -10, -50);
> p.vertex(0, 10, -50);
> p.vertex(-40, 10, -10);
> p.endShape();
> p.beginShape(TRIANGLES);
> p.vertex(-40, -10, -10);
> p.vertex(40, -10, -10);
> p.vertex(0, -10, -50);
> p.vertex(-40, 10, -10);
> p.vertex(40, 10, -10);
> p.vertex(0, 10, -50);
> p.endShape();
> 
> p.popMatrix();
> }
> // *************************************************** /
> //* Draw red axis lines */
> // *************************************************** /
> void Axis(PGraphics p)
> {
> p.stroke(255, 0, 0);
> p.strokeWeight(2);
> p.line(-45, 0, 45, 0);
> p.line(0, 90, 0, -90);
> p.fill(100, 255, 100); //GREEN
> p.stroke(0);
> p.strokeWeight(1);
> p.triangle(0, -107, -6, -90, 6, -90);
> p.triangle(0, 107, -6, 90, 6, 90);
> }
> 
> // *************************************************** /
> /* Draw the pitch scale */
> // *************************************************** /
> void PitchScale(PGraphics p)
> {
> p.stroke(255);
> p.fill(255);
> p.strokeWeight(2);
> p.textSize(14);
> p.push();
> p.translate(0, 0);
> p.textAlign(CENTER, CENTER);
> for (int i=-4; i<5; i++)
> {
> if ((i==0)==false)
> {
> p.line(40, 20*i, -40, 20*i); // Draws wider lines
> }
> 
> p.text(""+i*20, 20, 20*i -10, -150, 20); // draws left side degrees
> p.text(""+i*20, -20, 20*i -10, 150, 20); // draws right side degrees
> }
> //textAlign(CORNER);
> p.strokeWeight(1);
> for (int i=-9; i<10; i++)
> {
> if ((i==0)==false)
> {
> p.line(20, 10*i, -20, 10*i); // Draws narrower lines
> }
> }
> p.pop();
> }
> 
> // ******************************************************** /
> //* Draw cirular scale */
> //* Code from Adrian Fernandez 4-19-2013 */
> // ******************************************************** /
> void CircularScale(PGraphics p)
> {
> float GaugeWidth=304;
> p.textSize(GaugeWidth/20);
> float StrokeWidth=1;
> float an;
> float DivxPhasorCloser;
> float DivxPhasorDistal;
> float DivyPhasorCloser;
> float DivyPhasorDistal;
> p.strokeWeight(2*StrokeWidth);
> p.stroke(255);
> p.noFill();
> 
> float DivCloserPhasorLenght=GaugeWidth/2-GaugeWidth/9-StrokeWidth;
> float DivDistalPhasorLenght=GaugeWidth/2-GaugeWidth/7.5-StrokeWidth;
> 
> for (int Division=0; Division<NumberOfScaleMinorDivisions+1; Division++)
> {
> an=SpanAngle/2+Division*SpanAngle/NumberOfScaleMinorDivisions;
> DivxPhasorCloser=DivCloserPhasorLenght*cos(radians(an));
> DivxPhasorDistal=DivDistalPhasorLenght*cos(radians(an));
> DivyPhasorCloser=DivCloserPhasorLenght*sin(radians(an));
> DivyPhasorDistal=DivDistalPhasorLenght*sin(radians(an));
> 
> p.line(DivxPhasorCloser, DivyPhasorCloser, DivxPhasorDistal, DivyPhasorDistal);
> }
> 
> DivCloserPhasorLenght=GaugeWidth/2-GaugeWidth/10-StrokeWidth;
> DivDistalPhasorLenght=GaugeWidth/2-GaugeWidth/7.4-StrokeWidth;
> 
> for (int Division=0; Division<NumberOfScaleMajorDivisions+1; Division++)
> {
> an=SpanAngle/2+Division*SpanAngle/NumberOfScaleMajorDivisions;
> DivxPhasorCloser=DivCloserPhasorLenght*cos(radians(an));
> DivxPhasorDistal=DivDistalPhasorLenght*cos(radians(an));
> DivyPhasorCloser=DivCloserPhasorLenght*sin(radians(an));
> DivyPhasorDistal=DivDistalPhasorLenght*sin(radians(an));
> if (Division==NumberOfScaleMajorDivisions/2|Division==0|Division==NumberOfScaleMajorDivisions)
> {
> p.strokeWeight(5);
> p.stroke(255);
> 
> p.line(DivxPhasorCloser, DivyPhasorCloser, DivxPhasorDistal, DivyPhasorDistal);
> p.strokeWeight(1);
> p.stroke(100, 255, 100);
> 
> p.line(DivxPhasorCloser, DivyPhasorCloser, DivxPhasorDistal, DivyPhasorDistal);
> } else
> {
> p.strokeWeight(3);
> p.stroke(255);
> p.line(DivxPhasorCloser, DivyPhasorCloser, DivxPhasorDistal, DivyPhasorDistal);
> }
> }
> }
> // *************************************************** /
> //* Draws the compass pointer */
> // *************************************************** /
> void CompassPointer(PGraphics p)
> {
> p.rotate(radians(yaw));
> p.stroke(0);
> strokeWeight(1);
> p.fill(255, 255, 255);
> 
> p.beginShape();
> p.vertex(0, -105);
> p.vertex(12, 100);
> p.vertex(0, 80);
> p.vertex(-12, 100);
> p.endShape(CLOSE);
> 
> p.ellipse(0, 0, 9, 9);
> p.ellipse(0, 0, 3, 3);
> }
> 
> // ***************************************************
> //*
> // ***************************************************
> void serialEvent (Serial fd)
> {
> // get the ASCII string:
> String rpstr = fd.readStringUntil('\n');
> if (rpstr != null) {
> String[] list = split(rpstr, ':');
> pitch = ((int)float(list[0]));
> roll = ((int)float(list[1]));
> yaw = ((int)float(list[2]));
> }
> }
> 
> ```

> ****
>

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [May 15, 2026, 2:49pm UTC](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060/58 "2026-05-15T14:49:03Z")

</div>

@philtkp.

> [@philtkp](#):
>
> Seems to work great with the GY80. I posted all the files on github.

Cool beans! I will definitely visit this after the [long weekend](https://en.wikipedia.org/wiki/Long_weekend).

> [@philtkp](#):
>
> Thanks so much for the help and knowledge.

You are welcome!

`:)`

[Previous page](https://discourse.processing.org/t/linear-compass-display-to-use-with-a-mpu/48060.md?page=2)
