2018年11月28日 星期三

GY-271 磁力計上的晶片差異 HMC5883 & QMC 5883 Library 並不相容 & 電子羅盤轉方向

先講結論 : ESP32 or ESP8266  請使用HMC5883L (L883) 的晶片,可以省掉不少麻煩

groups.io 的討論

https://github.com/DFRobot/DFRobot_QMC5883   
可自動判別HMC or QMC
QMC數據會飄
HMC正常
ESP32 可編譯上傳,但載入執行失敗



https://github.com/dthain/QMC5883L 
這個QMC 專用,簡單穩定,在328上運行良好,佔用空間小 (ESP8266 ,ESP32 會編譯錯誤)

由於銲在PCB版的晶片不是所需方向時,調整順時鐘轉90度

/*
   2020-06-18 測試轉方向 OK
*/

#include <QMC5883L.h>
QMC5883L compass;

void setup()
{
  compass.init();
  compass.setSamplingRate(100);  // 10,50,100,200
  //compass.setOversampling(64); // 64,128,256,512  設置採樣率
  compass.setRange(8);           // 2 or 8 量程
  compass.resetCalibration();

  Serial.begin(115200);
  // Serial.println("QMC5883L Compass Demo");
  // Serial.println("Turn compass in all directions to calibrate....");
}

void loop()
{

  static int16_t x, y, z, t;
  compass.readRaw(&x, &y, &z, &t);
  Serial.print("x: ");  Serial.print(x);
  Serial.print("    y: "); Serial.print(y);
  //  Serial.print(" z: ");  Serial.print(z);

  // --------------  順時鐘轉90度 (銲在PCB版的晶片不是所需方向時)------------------
  // 就是把xy座標順時中轉90度
  static int16_t xx , yy;
  xx = x; yy = y;
  if (xx >= 0 )y = xx * -1;   //  x  ->  -y
  if (xx  < -1)y = xx * -1;   // -x  ->  y
  if (yy >= 0 )x = yy;        //  y  ->   x
  if (yy  < -1)x = yy;        // -y  ->  -x

  Serial.print("    x: ");  Serial.print(x);
  Serial.print("    y: ");  Serial.print(y);
  //  Serial.print(" z: ");  Serial.print(z);
  // --------------  End ---------------------------------------------------

  /* Update the observed boundaries of the measurements */
  static  int16_t xhigh, xlow;
  static  int16_t yhigh, ylow;
  if (x < xlow) xlow = x;  if (x > xhigh) xhigh = x;
  if (y < ylow) ylow = y;  if (y > yhigh) yhigh = y;

  /* Bail out if not enough data is available. */
  if ( xlow == xhigh || ylow == yhigh ) return 0;

  /* Recenter the measurement by subtracting the average */
  x -= (xhigh + xlow) / 2;
  y -= (yhigh + ylow) / 2;

  /* Rescale the measurement to the range observed. */
  float fx = (float)x / (xhigh - xlow); Serial.print(F(" fx: "));  Serial.print(fx);
  float fy = (float)y / (yhigh - ylow); Serial.print(F("     fy: "));  Serial.print(fy);

  static int heading;
  heading = (atan2(fy, fx) * 180.0) / PI;


  if (heading <= 0) heading += 360;

  Serial.print(F("  Heading: "));  Serial.print(heading);
  Serial.println();  delay(1000);
}







所有QMC都在芯片上有“DA”,而HMC卻沒有。

左邊是HMC,右邊是QMC。






ESP8266 ,ESP32 QMC5883L  用底下這個,測試過讀取數據OK ,但該作者提供的library 測試轉換磁方位不成功
https://github.com/mechasolution/Mecha_QMC5883L/blob/master/test.ino


#include <Wire.h>                   //I2C Arduino Library
#define addr 0x0D                   //I2C Address for The QMC5883

void setup() {

  Serial.begin(115200);
  Wire.begin();
  Wire.beginTransmission(addr);   //start talking
  Wire.write(0x0B);               // Tell the QMC5883 to Continuously Measure
  Wire.write(0x01);               // Set the Register
  Wire.endTransmission();
  Wire.beginTransmission(addr);   //start talking
  Wire.write(0x09);               // Tell the QMC5883 to Continuously Measure
  Wire.write(0x1D);               // Set the Register
  Wire.endTransmission();
}

void loop() {


  int x, y, z, t;                 //triple axis data

  Wire.beginTransmission(addr);   //Tell the QMC what regist to begin writing data into
  Wire.write(0x00);               //start with register 3.
  Wire.endTransmission();  
  Wire.requestFrom(addr, 6);      //Read the data.. 2 bytes for each axis.. 6 total bytes
  if (6 <= Wire.available()) {
    x = Wire.read();              //MSB  x
    x |= Wire.read() << 8;        //LSB  x
    y = Wire.read();              //MSB  y
    y |= Wire.read() << 8;        //LSB  y
    z = Wire.read();              //MSB  z
    z |= Wire.read() << 8;        //LSB  z
  }

  // Show Values

  Serial.print("X Value: ");
  Serial.println(x);
  Serial.print("Y Value: ");
  Serial.println(y);
  Serial.print("Z Value: ");
  Serial.println(z);
  Serial.println();

  delay(500);

}



校正
http://wukcsoft.blogspot.com/2014/06/read-gy-80.html

2018年11月9日 星期五

Arduino 計算兩個衛星定位點之間的距離和相對角度

/*
 *   2018-11-09 Test OK
 *
 * 計算兩個衛星定位點之間的距離和相對角度
 * 這個函式是從TinyGPSPlus-0.92 Libraty 擷取出來的
 *
 *
 */

void setup() {
  Serial.begin(115200, SERIAL_8N1);

//distanceBetween(24.1365, 121.6588,24.1403, 121.64723);

Serial.println(distanceBetween(24.1365, 121.6588,24.1403, 121.64723));
Serial.println(courseTo(24.1365, 121.6588,24.1403, 121.64723));


}


void loop() {


}

/* static */
double distanceBetween(double lat1, double long1, double lat2, double long2){
  /*
  // returns distance in meters between two positions, both specified
  // as signed decimal-degrees latitude and longitude. Uses great-circle
  // distance computation for hypothetical sphere of radius 6372795 meters.
  // Because Earth is no exact sphere, rounding errors may be up to 0.5%.
  // Courtesy of Maarten Lamers
  //返回指定的兩個位置之間的距離(以米為單位)
     //作為帶符號的十進制度緯度和經度。 使用大圓
     //半徑為6372795米的假想球體的距離計算。
     //因為地球不是精確的球體,所以舍入誤差可能高達0.5%。
     //由Maarten Lamers提供
*/
  double delta = radians(long1 - long2);
  double sdlong = sin(delta);
  double cdlong = cos(delta);
  lat1 = radians(lat1);
  lat2 = radians(lat2);
  double slat1 = sin(lat1);
  double clat1 = cos(lat1);
  double slat2 = sin(lat2);
  double clat2 = cos(lat2);
  delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
  delta = sq(delta);
  delta += sq(clat2 * sdlong);
  delta = sqrt(delta);
  double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
  delta = atan2(delta, denom);
  return delta * 6372795;
}

double courseTo(double lat1, double long1, double lat2, double long2){
  /*
  // returns course in degrees (North=0, West=270) from position 1 to position 2,
  // both specified as signed decimal-degrees latitude and longitude.
  // Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
  // Courtesy of Maarten Lamers
  //從位置1到位置2以度數(北= 0,西= 270)返迴路線,
     //均指定為帶符號的十進制度緯度和經度。
     //因為地球不是精確的球體,計算過程可能會受到很小的影響。
     //由Maarten Lamers提供
*/
  double dlon = radians(long2 - long1);
  lat1 = radians(lat1);
  lat2 = radians(lat2);
  double a1 = sin(dlon) * cos(lat2);
  double a2 = sin(lat1) * cos(lat2) * cos(dlon);
  a2 = cos(lat1) * sin(lat2) - a2;
  a2 = atan2(a1, a2);
  if (a2 < 0.0)
  {
    a2 += TWO_PI;
  }
  return degrees(a2);
}