Ми розглянули використання цифрового компаса HMC5883L з Arduino для вимірювання магнітного поля Землі. Спробуємо зробити 3D-моделювання отиманих даних з допомогою Processing. Скористаємося кодами для Arduino і Processing, знайденими в Інтернеті, але додамо більше коментарів, щоб легше було зрозуміти їх роботу. Бібліотеку для HMC5883L завантажимо звідси, хоча спочатку можете спробувати і бібліоте з попереднього уроку.
Код для Arduino
// Підключення бібліотеки I2C
#include <Wire.h>
// Підключення бібліотеки компасу HMC5883L
#include <HMC5883L.h>
// Збереження нашого compass як змінної.
HMC5883L compass;
// Запис будь-яких помилок, які можуть виникнути в компасі.
int error = 0;
//кут повороту
int RoundDegreeInt;
int PreviousDegree = 0;
// З функцією setup() ми налаштовуємо мікроконтролер і компас.
void setup()
{
Serial.begin(9600); // Ініціалізація послідовного порта
Wire.begin(); // Запуск інтерфейсу I2C.
compass = HMC5883L(); // Створення нового компасу HMC5883.
error = compass.SetScale(1.3); // Встановлення максимальної шкали компасу.
if(error != 0) // Якщо помилка, то виводимо на екран.
Serial.println(compass.GetErrorText(error));
error = compass.SetMeasurementMode(Measurement_Continuous); // Встановлення режиму безперервного вимірювання
if(error != 0) // Якщо помилка, то виводимо на екран.
Serial.println(compass.GetErrorText(error));
}
// Основний цикл програми.
void loop()
{
// Отримання первинних значень з компасу (без маштабування).
MagnetometerRaw raw = compass.ReadRawAxis();
// Отримання маштабованих значень з компасу (маштабування згідно виставленої шкали).
MagnetometerScaled scaled = compass.ReadScaledAxis();
// Значення доступні подібно цьому:
int MilliGauss_OnThe_XAxis = scaled.XAxis; // (або YAxis, або ZAxis)
// Розрахунок напрямку, коли є рівень магнітометра, то знак осі правильний.
float heading = atan2(scaled.YAxis, scaled.XAxis);
// Оскільки маємо напрямок, то повинні додати свій кут зміщення, який є «помилкою» магнітного поля для вашої місцевості.
// Знаходимо його, як і в попередньому уроці, тут: http://www.magnetic-declination.com/
// Для Києва ми знайшли +7° 19′, або (що нам необхідно) 0.1277 радіана.
// Якщо не можете знайти відхилення, то закоментуйте нижні два рядки, але компас буде дещо неточним.
float declinationAngle = 0.1277;
heading += declinationAngle;
// Коригування, коли змінюються знаки.
if(heading < 0)
heading += 2*PI;
// Перевірка повертання із-за додавання магнітного зміщення.
if(heading > 2*PI)
heading -= 2*PI;
// Перетворення для зручності радіанів в градуси.
float headingDegrees = heading * 180/M_PI;
//корекція значення кута
if (headingDegrees >= 1 && headingDegrees < 240)
{
headingDegrees = map(headingDegrees,0,239,0,179);
}
else if (headingDegrees >= 240)
{
headingDegrees = map(headingDegrees,240,360,180,360);
}
//кут повертання
RoundDegreeInt =round(headingDegrees);
//згладжування значення
if( RoundDegreeInt < (PreviousDegree + 3) && RoundDegreeInt > (PreviousDegree - 3) )
{
RoundDegreeInt = PreviousDegree;
}
Output(RoundDegreeInt);
PreviousDegree = RoundDegreeInt;
// Зазвичай робимо затримку додатка 66 мс при циклу
// для запуску на 15 Гц (полоса за замовчуванням для HMC5883L).
// Однак, оскільки ми маємо велику затримку на послідовному порту (104 мс при 9600),
// то дозволимо йому працювати з природною швидкістю.
// delay(66);
}
// Виведення даних через послідовний порт.
void Output(int RoundDegreeInt)
{
//Serial.println();
Serial.println(RoundDegreeInt);
delay(150);
}
Код для Processing
import processing.serial.*;
Serial myPort;
PFont b;
int lf = 10; // Перетворюємо рядки в ASCII
String myString = null;
float angle;
void setup(){
size(600,400);
b = loadFont("Arial-BoldMT-48.vlw");
myPort = new Serial(this, "COM3", 9600);
}
void draw(){
background(255);
while (myPort.available() > 0) {
myString = myPort.readStringUntil(lf);
if (myString != null) {
//print(myString); // Друкуємо рядок
angle=float(myString); // Конвертуємо і друкуємо поплавок
println(angle);
}
}
translate(160, 50);
// малюємо фон для компасу
ellipseMode(CENTER);
fill(50);
stroke(10);
strokeWeight(2);
ellipse(150,150,300,300);
// малюємо лінії і точки
translate(150,150); // переводимо лінії і точки в середину компасу
float CompassX = -angle;
rotate(radians(CompassX));
noStroke();
fill(51, 255, 51);
int radius = 120;
for( int degC = 5; degC < 360; degC += 10) //Точки компасу
{
float angleC = radians(degC);
float xC = 0 + (cos(angleC)* radius);
float yC = 0 + (sin(angleC)* radius);
ellipse(xC,yC, 3, 3);
}
for( int degL = 10; degL < 370; degL += 10) //Лінії компасу
{
float angleL = radians(degL);
float x = 0 + (cos(angleL)* 145);
float y = 0 + (sin(angleL)* 145);
if( degL==90 || degL==180 || degL==270 || degL==360)
{
stroke(51, 255, 51);
strokeWeight(4);
}
else
{
stroke(234,144,7);
strokeWeight(2);
}
line(0,0, x,y);
}
fill(102, 102, 102);
noStroke();
ellipseMode(CENTER);
ellipse(0,0, 228,228); //малюємо заповнений круг, щоб сховати в середині лінії
b = loadFont("Arial-BoldMT-48.vlw");
textAlign(CENTER);
// Малюємо букви
fill(250);
textFont(b, 32);
text("N", 1, -90);
rotate(radians(90));
text("E", 0, -90);
rotate(radians(90));
text("S", 0, -90);
rotate(radians(90));
text("W", 0, -90);
rotate(radians(90));
textFont(b,40);
textAlign(CENTER);
//text((angle), 20, 20);
println(angle);
//draw the needle
rotate(radians(-CompassX)); //зробити це стаціонарним
stroke(234,144,7);
strokeWeight(3);
triangle(-10, 0, 10, 0, 0, -85);
fill(234,144,7);
triangle(-10, 0, 10, 0, 0, 60);
}
На зхакінчення, коротке відео:
(Джерело: arduikyo.blogspot.nl)