We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hey guys! I have this code written by 44avalanche (Youtube):
//Artificial Horizon+Compass by Adrian Fernandez 4-19-2013
//Built with Processing 1.5.1
int W=1350; //My Laptop's screen width
int H=690; //My Laptop's screen height
float Pitch;
float Bank;
float Azimuth;
float ArtificialHoizonMagnificationFactor=0.7;
float CompassMagnificationFactor=0.85;
float SpanAngle=120;
int NumberOfScaleMajorDivisions;
int NumberOfScaleMinorDivisions;
PVector v1, v2; //For testing only
void setup()
{
size(W, H);
rectMode(CENTER);
smooth();
//strokeCap(SQUARE);//Optional
}
void draw()
{
background(0);
translate(W/4, H/2.1);
MakeAnglesDependentOnMouse();
Horizon();
rotate(-Bank);
PitchScale();
Axis();
rotate(Bank);
Borders();
Plane();
ShowAngles();
Compass();
ShowAzimuth();
}
void MakeAnglesDependentOnMouse() //For testing only.
{
v2= new PVector();
v1= new PVector(W/2, H/2);
v2.x=mouseX;
v2.y=mouseY;
Bank = PVector.angleBetween(v1, v2);
Pitch=mouseY-H/2;
Azimuth=(180/PI*10*Bank)%360;
}
void Horizon()
{
scale(ArtificialHoizonMagnificationFactor);
noStroke();
fill(0, 180, 255);
rect(0, -100, 900, 1000);
fill(95, 55, 40);
rotate(-Bank);
rect(0, 400+Pitch, 900, 800);
rotate(Bank);
rotate(-PI-PI/6);
SpanAngle=120;
NumberOfScaleMajorDivisions=12;
NumberOfScaleMinorDivisions=24;
CircularScale();
rotate(PI+PI/6);
rotate(-PI/6);
CircularScale();
rotate(PI/6);
}
void ShowAzimuth()
{
fill(50);
noStroke();
rect(20, 470, 440, 50);
int Azimuth1=round(Azimuth);
textAlign(CORNER);
textSize(35);
fill(255);
text("Azimuth: "+Azimuth1+" Deg", 80, 477, 500, 60);
}
void Compass()
{
translate(2*W/3, 0);
scale(CompassMagnificationFactor);
noFill();
stroke(100);
strokeWeight(80);
ellipse(0, 0, 750, 750);
strokeWeight(50);
stroke(50);
fill(0, 0, 40);
ellipse(0, 0, 610, 610);
for (int k=255;k>0;k=k-5)
{
noStroke();
fill(0, 0, 255-k);
ellipse(0, 0, 2*k, 2*k);
}
strokeWeight(20);
NumberOfScaleMajorDivisions=18;
NumberOfScaleMinorDivisions=36;
SpanAngle=180;
CircularScale();
rotate(PI);
SpanAngle=180;
CircularScale();
rotate(-PI);
fill(255);
textSize(60);
textAlign(CENTER);
text("W", -375, 0, 100, 80);
text("E", 370, 0, 100, 80);
text("N", 0, -365, 100, 80);
text("S", 0, 375, 100, 80);
textSize(30);
text("COMPASS-01", 0, -130, 500, 80);
rotate(PI/4);
textSize(40);
text("NW", -370, 0, 100, 50);
text("SE", 365, 0, 100, 50);
text("NE", 0, -355, 100, 50);
text("SW", 0, 365, 100, 50);
rotate(-PI/4);
CompassPointer();
}
void CompassPointer()
{
rotate(PI+radians(Azimuth));
stroke(0);
strokeWeight(4);
fill(100, 255, 100);
triangle(-20, -210, 20, -210, 0, 270);
triangle(-15, 210, 15, 210, 0, 270);
ellipse(0, 0, 45, 45);
fill(0, 0, 50);
noStroke();
ellipse(0, 0, 10, 10);
triangle(-20, -213, 20, -213, 0, -190);
triangle(-15, -215, 15, -215, 0, -200);
rotate(-PI-radians(Azimuth));
}
void Plane()
{
fill(0);
strokeWeight(1);
stroke(0, 255, 0);
triangle(-20, 0, 20, 0, 0, 25);
rect(110, 0, 140, 20);
rect(-110, 0, 140, 20);
}
void CircularScale()
{
float GaugeWidth=800;
textSize(GaugeWidth/30);
float StrokeWidth=1;
float an;
float DivxPhasorCloser;
float DivxPhasorDistal;
float DivyPhasorCloser;
float DivyPhasorDistal;
strokeWeight(2*StrokeWidth);
stroke(255);
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));
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)
{
strokeWeight(15);
stroke(0);
line(DivxPhasorCloser, DivyPhasorCloser, DivxPhasorDistal, DivyPhasorDistal);
strokeWeight(8);
stroke(100, 255, 100);
line(DivxPhasorCloser, DivyPhasorCloser, DivxPhasorDistal, DivyPhasorDistal);
}
else
{
strokeWeight(3);
stroke(255);
line(DivxPhasorCloser, DivyPhasorCloser, DivxPhasorDistal, DivyPhasorDistal);
}
}
}
void Axis()
{
stroke(255, 0, 0);
strokeWeight(3);
line(-115, 0, 115, 0);
line(0, 280, 0, -280);
fill(100, 255, 100);
stroke(0);
triangle(0, -285, -10, -255, 10, -255);
triangle(0, 285, -10, 255, 10, 255);
}
void ShowAngles()
{
textSize(30);
fill(50);
noStroke();
rect(-150, 400, 280, 40);
rect(150, 400, 280, 40);
fill(255);
Pitch=Pitch/5;
int Pitch1=round(Pitch);
Bank=Bank*180/PI;
int Bank1=round(Bank);
text("Pitch: "+Pitch1+" Deg", -20, 411, 500, 60);
text("Bank: "+Bank1+" Deg", 280, 411, 500, 60);
}
void Borders()
{
noFill();
stroke(0);
strokeWeight(400);
rect(0, 0, 1100, 1100);
strokeWeight(200);
ellipse(0, 0, 1000, 1000);
fill(0);
noStroke();
rect(4*W/5, 0, W, 2*H);
rect(-4*W/5, 0, W, 2*H);
}
void PitchScale()
{
stroke(255);
fill(255);
strokeWeight(3);
textSize(24);
textAlign(CENTER);
for (int i=-4;i<5;i++)
{
if ((i==0)==false)
{
line(110, 50*i, -110, 50*i);
}
text(""+i*10, 140, 50*i, 100, 30);
text(""+i*10, -140, 50*i, 100, 30);
}
textAlign(CORNER);
strokeWeight(2);
for (int i=-9;i<10;i++)
{
if ((i==0)==false)
{
line(25, 25*i, -25, 25*i);
}
}
}
The above codes currently takes reading from the movement of my mouse. I have tried editing the Yaw Pitch Roll example and my codes are here:
/**
Visualize orientation information from a FreeIMU device
INSTRUCTIONS:
This program has to be run when you have the FreeIMU_serial
program running on your Arduino and the Arduino connected to your PC.
Remember to set the serialPort variable below to point to the name the
Arduino serial port has in your system. You can get the port using the
Arduino IDE from Tools->Serial Port: the selected entry is what you have
to use as serialPort variable.
Copyright (C) 2011-2012 Fabio Varesano - http://www.varesano.net/
This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import processing.serial.*;
Serial myPort; // Create object from Serial class
float [] q = new float [4];
float [] Euler = new float [3]; // psi, theta, phi
int lf = 10; // 10 is '\n' in ASCII
byte[] inBuffer = new byte[22]; // this is the number of chars on each line from the Arduino (including /r/n)
PFont font;
final int VIEW_SIZE_X = 800, VIEW_SIZE_Y = 600;
int burst = 32, count = 0;
void myDelay(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) { }
}
void setup()
{
size(VIEW_SIZE_X, VIEW_SIZE_Y, P3D);
myPort = new Serial(this, "COM5", 115200);
// The font must be located in the sketch's "data" directory to load successfully
font = loadFont("CourierNew36.vlw");
println("Waiting IMU..");
myPort.clear();
while (myPort.available() == 0) {
myPort.write("v");
myDelay(1000);
}
println(myPort.readStringUntil('\n'));
myPort.write("q" + char(burst));
myPort.bufferUntil('\n');
}
float decodeFloat(String inString) {
byte [] inData = new byte[4];
if(inString.length() == 8) {
inData[0] = (byte) unhex(inString.substring(0, 2));
inData[1] = (byte) unhex(inString.substring(2, 4));
inData[2] = (byte) unhex(inString.substring(4, 6));
inData[3] = (byte) unhex(inString.substring(6, 8));
}
int intbits = (inData[3] << 24) | ((inData[2] & 0xff) << 16) | ((inData[1] & 0xff) << 8) | (inData[0] & 0xff);
return Float.intBitsToFloat(intbits);
}
void serialEvent(Serial p) {
if(p.available() >= 18) {
String inputString = p.readStringUntil('\n');
//print(inputString);
if (inputString != null && inputString.length() > 0) {
String [] inputStringArr = split(inputString, ",");
if(inputStringArr.length >= 5) { // q1,q2,q3,q4,\r\n so we have 5 elements
q[0] = decodeFloat(inputStringArr[0]);
q[1] = decodeFloat(inputStringArr[1]);
q[2] = decodeFloat(inputStringArr[2]);
q[3] = decodeFloat(inputStringArr[3]);
}
}
count = count + 1;
if(burst == count) { // ask more data when burst completed
p.write("q" + char(burst));
count = 0;
}
}
}
void buildBoxShape() {
//box(60, 10, 40);
noStroke();
beginShape(QUADS);
//Z+ (to the drawing area)
fill(#00ff00);
vertex(-30, -5, 20);
vertex(30, -5, 20);
vertex(30, 5, 20);
vertex(-30, 5, 20);
//Z-
fill(#0000ff);
vertex(-30, -5, -20);
vertex(30, -5, -20);
vertex(30, 5, -20);
vertex(-30, 5, -20);
//X-
fill(#ff0000);
vertex(-30, -5, -20);
vertex(-30, -5, 20);
vertex(-30, 5, 20);
vertex(-30, 5, -20);
//X+
fill(#ffff00);
vertex(30, -5, -20);
vertex(30, -5, 20);
vertex(30, 5, 20);
vertex(30, 5, -20);
//Y-
fill(#ff00ff);
vertex(-30, -5, -20);
vertex(30, -5, -20);
vertex(30, -5, 20);
vertex(-30, -5, 20);
//Y+
fill(#00ffff);
vertex(-30, 5, -20);
vertex(30, 5, -20);
vertex(30, 5, 20);
vertex(-30, 5, 20);
endShape();
}
void drawcompass(float heading, int circlex, int circley, int circlediameter)
{
noStroke();
ellipse(circlex, circley, circlediameter, circlediameter);
fill(#006400);
ellipse(circlex, circley, circlediameter/10, circlediameter/10);
stroke(#000000);
strokeWeight(4);
line(circlex- (3*circlediameter)/8 * sin(-heading), circley- (3*circlediameter)/8 * cos(-heading), circlex - circlediameter/2 * sin(-heading), circley - circlediameter/2 * cos(-heading));
noStroke();
fill(#ffffff);
textAlign(BOTTOM, LEFT);
text("NE", circlex + circlediameter/3 + 10, circley - circlediameter/3 - 10);
textAlign(TOP, LEFT);
text("SE", circlex + circlediameter/3 + 10, circley + circlediameter/2.9 + 10);
textAlign(RIGHT, TOP);
text("SW", circlex - circlediameter/3 - 10, circley + circlediameter/3 + 10);
textAlign(RIGHT, BOTTOM);
text("NW", circlex - circlediameter/3 - 10, circley - circlediameter/2.8 - 5);
textAlign(CENTER, BOTTOM);
text("N", circlex, circley - circlediameter/2 - 10);
textAlign(CENTER, TOP);
text("S", circlex, circley + circlediameter/2 + 10);
textAlign(RIGHT, CENTER);
text("W", circlex - circlediameter/2 - 10, circley);
textAlign(LEFT, CENTER);
text("E", circlex + circlediameter/2 + 10, circley);
}
void drawAngle(float angle, int circlex, int circley, int circlediameter, String title) {
angle = angle + PI/2;
noStroke();
ellipse(circlex, circley, circlediameter, circlediameter);
fill(#ff0000);
strokeWeight(4);
stroke(#ff0000);
line(circlex - circlediameter/2 * sin(angle), circley - circlediameter/2 * cos(angle), circlex + circlediameter/2 * sin(angle), circley + circlediameter/2 * cos(angle));
noStroke();
fill(#ffffff);
textAlign(CENTER, BOTTOM);
text(title, circlex, circley - circlediameter/2 - 30);
}
void draw() {
quaternionToYawPitchRoll(q, Euler);
background(#000000);
fill(#ffffff);
textFont(font, 20);
//float temp_decoded = 35.0 + ((float) (temp + 13200)) / 280;
//text("temp:\n" + temp_decoded + " C", 350, 250);
textAlign(LEFT, TOP);
text("Q:\n" + q[0] + "\n" + q[1] + "\n" + q[2] + "\n" + q[3], 20, 10);
text("Euler Angles:\nYaw (psi) : " + degrees(Euler[0]) + "\nPitch (theta): " + degrees(Euler[1]) + "\nRoll (phi) : " + degrees(Euler[2]), 200, 10);
drawcompass(Euler[0], VIEW_SIZE_X/2 - 250, VIEW_SIZE_Y/2, 200);
drawAngle(Euler[1], VIEW_SIZE_X/2, VIEW_SIZE_Y/2, 200, "Pitch:");
drawAngle(Euler[2], VIEW_SIZE_X/2 + 250, VIEW_SIZE_Y/2, 200, "Roll:");
translate(350, 450);
fill(255, 255, 255);
rect(-262, 0, 120, 33, 2); //box 1
rect(-10, 0, 120, 33, 2); //box 2
rect(243, 0, 120, 33, 2); //box 3
textSize(25);
fill(0, 0, 0);
text(Euler[0], -212, 26); //yaw
text(Euler[1], 40, 26); //pitch
text(Euler[2], 293, 26); //roll
}
void quaternionToYawPitchRoll(float [] q, float [] ypr)
{
float gx, gy, gz; // estimated gravity direction
gx = 2 * (q[1]*q[3] - q[0]*q[2]);
gy = 2 * (q[0]*q[1] + q[2]*q[3]);
gz = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
ypr[0] = atan2(2 * q[1] * q[2] - 2 * q[0] * q[3], 2 * q[0]*q[0] + 2 * q[1] * q[1] - 1);
ypr[1] = atan2(gx, sqrt(gy*gy + gz*gz));
ypr[2] = atan2(gy, sqrt(gx*gx + gz*gz));
// Fix the angle returned by atan2 (radians) to the range 0- TWO_PI
// which is 0 - 360 degrees
ypr[0] = (ypr[0] < 0) ? TWO_PI + ypr[0] : ypr[0];
ypr[1] = (ypr[1] < 0) ? TWO_PI + ypr[1] : ypr[1];
ypr[2] = (ypr[2] < 0) ? TWO_PI + ypr[2] : ypr[2];
}
The second sets of codes reads data from my serial port and displays the data out as according. Only Yaw is working perfectly fine. Anyway to combine the first and the second sets of codes such that Processing will display everything that the first set have, and take reading from the serial port?
I am running the following codes on arduino (connected to a 10 dof imu and arduino mega 2560):
#include <ADXL345.h>
#include <bma180.h>
#include <HMC58X3.h>
#include <ITG3200.h>
#include <MS561101BA.h>
#include <I2Cdev.h>
#include <MPU60X0.h>
#include <EEPROM.h>
//#define DEBUG
#include "DebugUtils.h"
#include "CommunicationUtils.h"
#include "FreeIMU.h"
#include <Wire.h>
#include <SPI.h>
float q[4];
// Set the FreeIMU object
FreeIMU my3IMU = FreeIMU();
void setup() {
Serial.begin(115200);
Wire.begin();
delay(5);
my3IMU.init();
delay(5);
}
void loop() {
my3IMU.getQ(q);
serialPrintFloatArr(q, 4);
Serial.println("");
delay(20);
}
Thanks in advance!