Linear compass display to use with a MPU

@glv

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

CODE
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

@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
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]));
  }
}

@philtkp

An example:

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().

:)

@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
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]));
  }
}

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:

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!

:)

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.

@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
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

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

This may help:

//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()

:)

@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. :slightly_smiling_face: :beer_mug:

CODE
//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);
}

@philtkp,

That is certainly one approach that works!

I tinkered with your code a bit:

Summary
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!

:)

@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?:confused: