---
# System prepended metadata

title: 航電元件程式碼
tags: [Avionics]

---

# 航電元件程式碼
###### tags: `Avionics`
[toc]

## 財產表

麵包版短×2
麵包版長×1

Arduino UNO版×3
Lora 通訊元件×4 （損壞×1）

3dbi 天線×4
35dbi 天線×2


## 元件狀況註記列表

UNO 1：
UNO 2, 3: UCI電子材料行
UNO 4: 墾億電子

UNO 2b + Lora 3a：不明原因經常 Lora 啟動 failed，持續時間也不長（約2-3分鐘）
5/11 無法連接com


## BMP180
### 獨立使用
```
#include <SFE_BMP180.h>
#include <Wire.h>

SFE_BMP180 pressure;  // 建立一個物件名為 pressure
#define ALTITUDE 25   // 台灣西部海岸大約的海平面高度

void setup()
{
  Serial.begin(9600);
  Serial.println("REBOOT");
  
  // 初始設定
  if (pressure.begin())
    Serial.println("BMP180 init success");
  else
  {
    // 初始化錯誤，一般是連接問題
    Serial.println("BMP180 init fail\n\n");
    while(1);    // 永久停在這裡
  }
}

void loop()
{
  char status;
  double T,P,p0,a;

  Serial.println();

  status = pressure.startTemperature();
  if (status != 0)
  {
    // 等待感測完成
    delay(status);

    // 取得完整溫度測量，感測值存在變數T，函數回傳 1表示成功，0表示失敗

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // 顯示感測值
      Serial.print("temperature: ");
      Serial.print(T,2);
      Serial.print(" .C,        ");

      // 量測壓力
      // 參數設定從 0 到 3 (最高的解析度，等待較久)
      // 感測成功會傳回等待多少 ms，如果不成功會傳回 0

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // 等待感測完成
        delay(status);

        // 取得完整的壓力感測值，感測值存在變數 P，這個函數需要先前取得的溫度 T       
        // 假使溫度變化不大，可以只取得一次的值即可，函數執行成功會傳回 1，失敗傳回 0

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // 列出感測值
          Serial.print("absolute pressure: ");
          Serial.print(P,2);
          Serial.print(" mb,     ");

          // 壓力感測值傳回絕對壓力，會隨著高度而變化，要移除高度的影響，需使用 sealevel 函數在目前的高度，
          // 這個數字常被用在氣象報告中，參數 P = 絕對壓力(毫巴), 高度 = 目前高度(公尺/米）.
          // 傳回值 p0 = sealevel函數的補償壓力(毫巴)

          p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO)
          Serial.print("relative (sea-level) pressure: ");
          Serial.print(p0,2);
          Serial.print(" mb,     ");

          // 如果要從壓力感測值得知高度，需使用高度函數 altitude，以及先言算出的基準壓力.
          // 參數 P = 絕對壓力(毫巴）, p0 = 基準壓力(毫巴）. 傳回值 a = 高度(公尺/米)

          a = pressure.altitude(P,p0);
          Serial.print("computed altitude: ");
          Serial.print(a,0);
          Serial.print(" meters, ");

        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");

  delay(2000);  // 暫停5秒 
}

```

### with Lora Sender
```
#include <SFE_BMP180.h>
#include <Wire.h>
#include <SPI.h>
#include <LoRa.h>


SFE_BMP180 pressure;  // 建立一個物件名為 pressure
#define ALTITUDE 25   // 台灣西部海岸大約的海平面高度

void setup()
{
  Serial.begin(9600);
  Serial.println("LoRa Sender");
  if (!LoRa.begin(433E6)) 
  {
    Serial.println("Starting LoRa failed!");
    while(1);
  }
  while (pressure.begin() != true)  {
    Serial.println(F("BMP180 not connected...")); 
    delay(5000);
  }
  Serial.println(F("BMP180 initial OK"));    
}

void loop()
{
  char status;
  double T,P,p0,a;

  Serial.println();

  status = pressure.startTemperature();
  if (status != 0)
  {
    // 等待感測完成
    delay(status);

    // 取得完整溫度測量，感測值存在變數T，函數回傳 1表示成功，0表示失敗

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // 顯示感測值
      Serial.print("temperature: ");
      Serial.print(T,2);
      Serial.print(" .C,        ");

      // 量測壓力
      // 參數設定從 0 到 3 (最高的解析度，等待較久)
      // 感測成功會傳回等待多少 ms，如果不成功會傳回 0

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // 等待感測完成
        delay(status);

        // 取得完整的壓力感測值，感測值存在變數 P，這個函數需要先前取得的溫度 T       
        // 假使溫度變化不大，可以只取得一次的值即可，函數執行成功會傳回 1，失敗傳回 0

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // 列出感測值
          Serial.print("absolute pressure: ");
          Serial.print(P,2);
          Serial.print(" mb,     ");

          // 壓力感測值傳回絕對壓力，會隨著高度而變化，要移除高度的影響，需使用 sealevel 函數在目前的高度，
          // 這個數字常被用在氣象報告中，參數 P = 絕對壓力(毫巴), 高度 = 目前高度(公尺/米）.
          // 傳回值 p0 = sealevel函數的補償壓力(毫巴)

          p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO)
          Serial.print("relative (sea-level) pressure: ");
          Serial.print(p0,2);
          Serial.print(" mb,     ");

          // 如果要從壓力感測值得知高度，需使用高度函數 altitude，以及先言算出的基準壓力.
          // 參數 P = 絕對壓力(毫巴）, p0 = 基準壓力(毫巴）. 傳回值 a = 高度(公尺/米)

          a = pressure.altitude(P,p0);
          Serial.print("computed altitude: ");
          Serial.print(a,0);
          Serial.print(" meters, ");

        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");

  String msg = String(T,2)+" "+String(P,2)+" "+String(p0,2)+" "+String(a,0);
  Serial.println();
  Serial.print(msg);

  LoRa.beginPacket();
  LoRa.print(msg);
  LoRa.endPacket();
  delay(1000);
}

```

### with Lora Receiver
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  String str="";
  String t="";
  String P="";
  String p0="";
  String a="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    Serial.print("Received packet: ");
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }
    t = str.substring(0,5);
    P = str.substring(6,13);
    p0 = str.substring(14,21);
    a = str.substring(22,24);

    Serial.print("temperature:");
    Serial.print(t);
    Serial.print(" .C,  ");

    Serial.print("absolute pressure:");
    Serial.print(P);
    Serial.print(" mb,  ");

    Serial.print("relative (sea-level) pressure: ");
    Serial.print(p0);
    Serial.print(" mb,  ");

    Serial.print("computed altitude: ");
    Serial.print(a);
    Serial.print(" meters, ");
    
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }
//  delay(1000);     
}


```

![](https://i.imgur.com/8GKSx41.png)

![](https://i.imgur.com/drjEW6d.png)

### 獨立使用 with PLXDAQ
```
#include <SFE_BMP180.h>
#include <Wire.h>

SFE_BMP180 pressure;  // 建立一個物件名為 pressure
#define ALTITUDE 25   // 台灣西部海岸大約的海平面高度

void setup()
{
  Serial.begin(9600);
  Serial.println("REBOOT");
  
  // 初始設定
  if (pressure.begin())
    Serial.println("BMP180 init success");
  else
  {
    // 初始化錯誤，一般是連接問題
    Serial.println("BMP180 init fail\n\n");
    while(1);    // 永久停在這裡
  }
  Serial.println("CLEARSHEET");
  Serial.println("LABEL, Time,Timer, Temperature (C), Absolute Pressure (mb), Relative Pressure (mb), Altitude (m)");
}

void loop()
{
  

  char status;
  double T,P,p0,a;


  status = pressure.startTemperature();
  if (status != 0)
  {

    delay(status);

    status = pressure.getTemperature(T);
    if (status != 0)
    {

      // Serial.print("temperature: ");
      // Serial.print(T,2);
      // Serial.print(" .C,        ");

      status = pressure.startPressure(3);
      if (status != 0)
      {
        // 等待感測完成
        delay(status);


        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // 列出感測值
          // Serial.print("absolute pressure: ");
          // Serial.print(P,2);
          // Serial.print(" mb,     ");

          p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO)
          // Serial.print("relative (sea-level) pressure: ");
          // Serial.print(p0,2);
          // Serial.print(" mb,     ");

          a = pressure.altitude(P,p0);
          // Serial.print("computed altitude: ");
          // Serial.print(a,0);
          // Serial.print(" meters, ");

        }
        else; //Serial.println("error retrieving pressure measurement\n");
      }
      else; //Serial.println("error starting pressure measurement\n");
    }
    else; //Serial.println("error retrieving temperature measurement\n");
  }
  else; //Serial.println("error starting temperature measurement\n");

 
  Serial.print("DATA, TIME, TIMER,");
  Serial.print(T);
  Serial.print(",");
  Serial.print(P);
  Serial.print(",");
  Serial.print(p0);
  Serial.print(",");
  Serial.println(a);


  delay(2000);  // 暫停5秒 
}
```

### Lora Receiver with PLXDAQ
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
    
  }
  Serial.println("CLEARSHEET");
  Serial.println("LABEL, Time,Timer, Temperature (C), Absolute Pressure (mb), Relative Pressure (mb), Altitude (m), RSSI");
}

void loop() {
  String str="";
  String T="";
  String P="";
  String p0="";
  String a="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    Serial.print("Received packet: ");
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }
    T = str.substring(0,5);
    P = str.substring(6,13);
    p0 = str.substring(14,21);
    a = str.substring(22,24);

    Serial.print("DATA, TIME, TIMER,");
    Serial.print(T);
    Serial.print(",");
    Serial.print(P);
    Serial.print(",");
    Serial.print(p0);
    Serial.print(",");
    Serial.print(a);
    Serial.print(",");


    // Serial.print("temperature:");
    // Serial.print(t);
    // Serial.print(" .C,  ");

    // Serial.print("absolute pressure:");
    // Serial.print(P);
    // Serial.print(" mb,  ");

    // Serial.print("relative (sea-level) pressure: ");
    // Serial.print(p0);
    // Serial.print(" mb,  ");

    // Serial.print("computed altitude: ");
    // Serial.print(a);
    // Serial.print(" meters, ");
    
    //Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }
   delay(1000);     
}
```

## LoRa傳送空封包
### Sender
```
#include <SPI.h>
#include <LoRa.h>

//define the pins used by the transceiver module
#define ss 5
#define rst 14
#include <SPI.h>
#include <LoRa.h>

int counter=0;  //傳送次數計數器

void setup() {
  Serial.begin(9600);
  while (!Serial);  //等待序列埠起始完畢
  Serial.println("LoRa Sender");
  if (!LoRa.begin(433E6)) {  //起始 433MHz LoRa
    Serial.println("Starting LoRa failed!");
    while (1);
    }
  }

void loop() {
  Serial.print("Sending packet: ");
  Serial.println(counter);
  LoRa.beginPacket();  //封包傳送開始
  LoRa.print("hello ");  //封包內容
  LoRa.print(counter);  //封包內容
  LoRa.endPacket();  //封包傳送結束
  counter++;  //計數器增量 1
  delay(1000);
  }
```
  
  ### Receiver
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  String str="";
  String t="";
  String P="";
  String p0="";
  String a="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    Serial.print("Received packet: ");
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }
    t = str.substring(0,5);
    P = str.substring(6,13);
    p0 = str.substring(14,21);
    a = str.substring(22,24);

    Serial.print("temperature:");
    Serial.print(t);
    Serial.print(" .C,  ");

    Serial.print("absolute pressure:");
    Serial.print(P);
    Serial.print(" mb,  ");

    Serial.print("relative (sea-level) pressure: ");
    Serial.print(p0);
    Serial.print(" mb,  ");

    Serial.print("computed altitude: ");
    Serial.print(a);
    Serial.print(" meters, ");
    
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }
//  delay(1000);     
}
```

## CJMCU-8128
### 獨立使用
```
#include "Adafruit_CCS811.h"
#include <BMx280_EnvCalc.h>
#include <sSense-BMx280I2C.h>
#include <Wire.h>

#define SERIAL_SPEED 9600

Adafruit_CCS811 ccs;
BMx280I2C ssenseBMx280; 

void setup() {
    Serial.begin(9600);           // initialize the serial monitor 
  Serial.begin(SERIAL_SPEED);
  ccs.begin();

  DebugPort.begin(SERIAL_SPEED);

  while(!DebugPort) {} // Wait

  Wire.begin();

  while(!ssenseBMx280.begin())
  {
    DebugPort.println("Could not find BME280 sensor!");
    delay(50);
  }

  /*switch(ssenseBMx280.chipModel())
  {
     case BME280::ChipModel_BME280:
       DebugPort.println("Found BME280 sensor! Humidity available.");
       break;
     case BME280::ChipModel_BMP280:
       DebugPort.println("Found BMP280 sensor! No Humidity available.");
       break;
     default:
       DebugPort.println("Found UNKNOWN sensor! Error!");
  }*/
  Serial.println("CO2(ppm),Temp(C),Pressure(Pa),Altitude(m)");
}

void loop() {
  
  if(ccs.available()){
    if(!ccs.readData()){
      Serial.print(ccs.geteCO2());
      Serial.print(",");
    }
    else{
      Serial.println("ERROR!,ERROR!,");
    }
  }
   printBMx280Data(&DebugPort);
   

  delay(2000);
 
  

}

void printBMx280Data( Stream* client )
{
   float temp(NAN), hum(NAN), pres(NAN);

   BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
   BME280::PresUnit presUnit(BME280::PresUnit_Pa);

    ssenseBMx280.read(pres, temp, hum, tempUnit, presUnit);

   
   client->print(temp);
   client->print(",");
   
   client->print(pres);
   client->print(",");

   BMx280_EnvCalc::AltitudeUnit envAltUnit  =  BMx280_EnvCalc::AltitudeUnit_Meters;
   BMx280_EnvCalc::TempUnit     envTempUnit =  BMx280_EnvCalc::TempUnit_Celsius;

   float altitude = BMx280_EnvCalc::Altitude(pres, envAltUnit);
  // float dewPoint = BMx280_EnvCalc::DewPoint(temp, hum, envTempUnit);
   //float seaLevel = BMx280_EnvCalc::EquivalentSeaLevelPressure(altitude, temp, pres);
   
   client->print(altitude);
  
  Serial.println(" ");
   //delay(1000);
}
```
### With Lora Sender
```
#include <SPI.h>
#include <LoRa.h>
#include "Adafruit_CCS811.h"
#include <BMx280_EnvCalc.h>
#include <sSense-BMx280I2C.h>
#include <Wire.h>

#define SERIAL_SPEED 9600

Adafruit_CCS811 ccs;
BMx280I2C ssenseBMx280; 


void setup()
{
  Serial.begin(9600);
    Serial.println("LoRa Sender");
  if (!LoRa.begin(433E6)) 
  {
    Serial.println("Starting LoRa failed!");
    while(1);
  }
  Serial.begin(SERIAL_SPEED);
  ccs.begin();
  DebugPort.begin(SERIAL_SPEED);

  while(!DebugPort) {} // Wait

  Wire.begin();

  while(!ssenseBMx280.begin())
  {
    DebugPort.println("Could not find BME280 sensor!");
    delay(50);
  }
  
}

  void loop() {
    Serial.println();
    Serial.println("CO2(ppm),Temp(C),Pressure(Pa),Altitude(m)");
    
    if(ccs.available())
    {
      
    if(!ccs.readData()){
      Serial.print("CO2(ppm):");
      Serial.print(ccs.geteCO2());
      //Serial.print(",");
    }
    else{
      Serial.println("ERROR!,ERROR!,");
    }
  }
   printBMx280Data(&DebugPort);
   

  delay(2000);
 
  

}

void printBMx280Data( Stream* client )
{
   float temp(NAN), hum(NAN), pres(NAN);

   BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
   BME280::PresUnit presUnit(BME280::PresUnit_Pa);

    ssenseBMx280.read(pres, temp, hum, tempUnit, presUnit);

   
   //client->print(temp);
   //client->print(",");
   
   //client->print(pres);
   //client->print(",");

   BMx280_EnvCalc::AltitudeUnit envAltUnit  =  BMx280_EnvCalc::AltitudeUnit_Meters;
   BMx280_EnvCalc::TempUnit     envTempUnit =  BMx280_EnvCalc::TempUnit_Celsius;

   float altitude = BMx280_EnvCalc::Altitude(pres, envAltUnit);

   //client->print(altitude);
  //Serial.println(" ");
   //delay(1000);


 String msg = String(ccs.geteCO2())+" "+String(temp)+" "+String(pres)+" "+String(altitude);
  Serial.println();
  Serial.print(msg);

  LoRa.beginPacket();
  LoRa.print(msg);
  LoRa.endPacket();
  delay(1000);   // 每1秒鐘送一次資料
}
```

### With Lora Receiver
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  String str="";
  String ccsgeteCO2="";
  String temp="";
  String pres="";
  String altitude="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    Serial.print("Received packet: ");
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }
    ccsgeteCO2 = str.substring(0,5);
    temp = str.substring(5,11);
    pres = str.substring(11,21);
    altitude = str.substring(21,27);

    Serial.print("Co2:");
    Serial.print(ccsgeteCO2);
    Serial.print("ppm,  ");

    Serial.print("Temperature:");
    Serial.print(temp);
    Serial.print("C,  ");

    Serial.print("Pressure: ");
    Serial.print(pres);
    Serial.print("Pa,  ");

    Serial.print("Altitude: ");
    Serial.print(altitude);
    Serial.print(" m, ");
    
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }
//  delay(1000);     
}
```
## MPU9250
### 獨立使用
```
#include "Wire.h"

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
I2Cdev   I2C_M;

uint8_t buffer_m[6];


int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t   mx, my, mz;



float heading;
float tiltheading;

float Axyz[3];
float Gxyz[3];
float Mxyz[3];


#define sample_num_mdate  5000

volatile float mx_sample[3];
volatile float my_sample[3];
volatile float mz_sample[3];

static float mx_centre = 0;
static float my_centre = 0;
static float mz_centre = 0;

volatile int mx_max = 0;
volatile int my_max = 0;
volatile int mz_max = 0;

volatile int mx_min = 0;
volatile int my_min = 0;
volatile int mz_min = 0;


void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    Wire.begin();

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(38400);
    
    // initialize device
    while(!Serial);
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    delay(1000);
    Serial.println("     ");

    Mxyz_init_calibrated();

}

void loop() {

    getAccel_Data();
    getGyro_Data();
    getCompassDate_calibrated(); // compass data has been calibrated here
    getHeading();    //before we use this function we should run 'getCompassDate_calibrated()' frist, so that we can get calibrated data ,then we can get correct angle .
    getTiltHeading();

    Serial.println("calibration parameter: ");
    Serial.print(mx_centre);
    Serial.print("         ");
    Serial.print(my_centre);
    Serial.print("         ");
    Serial.println(mz_centre);
    Serial.println("     ");


    Serial.println("Acceleration(g) of X,Y,Z:");
    Serial.print(Axyz[0]);
    Serial.print(",");
    Serial.print(Axyz[1]);
    Serial.print(",");
    Serial.println(Axyz[2]);
    Serial.println("Gyro(degress/s) of X,Y,Z:");
    Serial.print(Gxyz[0]);
    Serial.print(",");
    Serial.print(Gxyz[1]);
    Serial.print(",");
    Serial.println(Gxyz[2]);
    Serial.println("Compass Value of X,Y,Z:");
    Serial.print(Mxyz[0]);
    Serial.print(",");
    Serial.print(Mxyz[1]);
    Serial.print(",");
    Serial.println(Mxyz[2]);
    Serial.println("The clockwise angle between the magnetic north and X-Axis:");
    Serial.print(heading);
    Serial.println(" ");
    Serial.println("The clockwise angle between the magnetic north and the projection of the positive X-Axis in the horizontal plane:");
    Serial.println(tiltheading);
    Serial.println("   ");
    Serial.println("   ");
    Serial.println("   ");



    delay(1000);





}


void getHeading(void) {
    heading = 180 * atan2(Mxyz[1], Mxyz[0]) / PI;
    if (heading < 0) {
        heading += 360;
    }
}

void getTiltHeading(void) {
    float pitch = asin(-Axyz[0]);
    float roll = asin(Axyz[1] / cos(pitch));

    float xh = Mxyz[0] * cos(pitch) + Mxyz[2] * sin(pitch);
    float yh = Mxyz[0] * sin(roll) * sin(pitch) + Mxyz[1] * cos(roll) - Mxyz[2] * sin(roll) * cos(pitch);
    float zh = -Mxyz[0] * cos(roll) * sin(pitch) + Mxyz[1] * sin(roll) + Mxyz[2] * cos(roll) * cos(pitch);
    tiltheading = 180 * atan2(yh, xh) / PI;
    if (yh < 0) {
        tiltheading += 360;
    }
}



void Mxyz_init_calibrated() {

    Serial.println(F("Before using 9DOF,we need to calibrate the compass frist,It will takes about 2 minutes."));
    Serial.print("  ");
    Serial.println(F("During  calibratting ,you should rotate and turn the 9DOF all the time within 2 minutes."));
    Serial.print("  ");
    Serial.println(F("If you are ready ,please sent a command data 'ready' to start sample and calibrate."));
    while (!Serial.find("ready"));
    Serial.println("  ");
    Serial.println("ready");
    Serial.println("Sample starting......");
    Serial.println("waiting ......");

    get_calibration_Data();

    Serial.println("     ");
    Serial.println("compass calibration parameter ");
    Serial.print(mx_centre);
    Serial.print("     ");
    Serial.print(my_centre);
    Serial.print("     ");
    Serial.println(mz_centre);
    Serial.println("    ");
}


void get_calibration_Data() {
    for (int i = 0; i < sample_num_mdate; i++) {
        get_one_sample_date_mxyz();
        /*
            Serial.print(mx_sample[2]);
            Serial.print(" ");
            Serial.print(my_sample[2]);                            //you can see the sample data here .
            Serial.print(" ");
            Serial.println(mz_sample[2]);
        */



        if (mx_sample[2] >= mx_sample[1]) {
            mx_sample[1] = mx_sample[2];
        }
        if (my_sample[2] >= my_sample[1]) {
            my_sample[1] = my_sample[2];    //find max value
        }
        if (mz_sample[2] >= mz_sample[1]) {
            mz_sample[1] = mz_sample[2];
        }

        if (mx_sample[2] <= mx_sample[0]) {
            mx_sample[0] = mx_sample[2];
        }
        if (my_sample[2] <= my_sample[0]) {
            my_sample[0] = my_sample[2];    //find min value
        }
        if (mz_sample[2] <= mz_sample[0]) {
            mz_sample[0] = mz_sample[2];
        }

    }

    mx_max = mx_sample[1];
    my_max = my_sample[1];
    mz_max = mz_sample[1];

    mx_min = mx_sample[0];
    my_min = my_sample[0];
    mz_min = mz_sample[0];



    mx_centre = (mx_max + mx_min) / 2;
    my_centre = (my_max + my_min) / 2;
    mz_centre = (mz_max + mz_min) / 2;

}






void get_one_sample_date_mxyz() {
    getCompass_Data();
    mx_sample[2] = Mxyz[0];
    my_sample[2] = Mxyz[1];
    mz_sample[2] = Mxyz[2];
}


void getAccel_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Axyz[0] = (double) ax / 16384;
    Axyz[1] = (double) ay / 16384;
    Axyz[2] = (double) az / 16384;
}

void getGyro_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Gxyz[0] = (double) gx * 250 / 32768;
    Gxyz[1] = (double) gy * 250 / 32768;
    Gxyz[2] = (double) gz * 250 / 32768;
}

void getCompass_Data(void) {
    I2C_M.writeByte(MPU9150_RA_MAG_ADDRESS, 0x0A, 0x01); //enable the magnetometer
    delay(10);
    I2C_M.readBytes(MPU9150_RA_MAG_ADDRESS, MPU9150_RA_MAG_XOUT_L, 6, buffer_m);

    mx = ((int16_t)(buffer_m[1]) << 8) | buffer_m[0] ;
    my = ((int16_t)(buffer_m[3]) << 8) | buffer_m[2] ;
    mz = ((int16_t)(buffer_m[5]) << 8) | buffer_m[4] ;

    Mxyz[0] = (double) mx * 1200 / 4096;
    Mxyz[1] = (double) my * 1200 / 4096;
    Mxyz[2] = (double) mz * 1200 / 4096;
}

void getCompassDate_calibrated() {
    getCompass_Data();
    Mxyz[0] = Mxyz[0] - mx_centre;
    Mxyz[1] = Mxyz[1] - my_centre;
    Mxyz[2] = Mxyz[2] - mz_centre;
}
```
### 用9600（可）
```
#include "Wire.h"

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
I2Cdev   I2C_M;

uint8_t buffer_m[6];


int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t   mx, my, mz;



float heading;
float tiltheading;

float Axyz[3];
float Gxyz[3];
float Mxyz[3];


#define sample_num_mdate  5000

volatile float mx_sample[3];
volatile float my_sample[3];
volatile float mz_sample[3];

static float mx_centre = 0;
static float my_centre = 0;
static float mz_centre = 0;

volatile int mx_max = 0;
volatile int my_max = 0;
volatile int mz_max = 0;

volatile int mx_min = 0;
volatile int my_min = 0;
volatile int mz_min = 0;


void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    Wire.begin();

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(9600);
    
    // initialize device
    while(!Serial);
    //Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    //Serial.println("Testing device connections...");
    //Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    delay(1000);
    //Serial.println("     ");

    Mxyz_init_calibrated();

}

void loop() {

    getAccel_Data();
    getGyro_Data();
    getCompassDate_calibrated(); // compass data has been calibrated here
    getHeading();    //before we use this function we should run 'getCompassDate_calibrated()' frist, so that we can get calibrated data ,then we can get correct angle .
    getTiltHeading();

    /*Serial.println("calibration parameter: ");
    Serial.print(mx_centre);
    Serial.print("         ");
    Serial.print(my_centre);
    Serial.print("         ");
    Serial.println(mz_centre);
    Serial.println("     ");*/


    Serial.println("Acceleration(g) of X,Y,Z:");
    Serial.print(Axyz[0]);
    Serial.print(",");
    Serial.print(Axyz[1]);
    Serial.print(",");
    Serial.println(Axyz[2]);
    Serial.println("Gyro(degress/s) of X,Y,Z:");
    Serial.print(Gxyz[0]);
    Serial.print(",");
    Serial.print(Gxyz[1]);
    Serial.print(",");
    Serial.println(Gxyz[2]);
    Serial.println("Compass Value of X,Y,Z:");
    Serial.print(Mxyz[0]);
    Serial.print(",");
    Serial.print(Mxyz[1]);
    Serial.print(",");
    Serial.println(Mxyz[2]);
    /*Serial.println("The clockwise angle between the magnetic north and X-Axis:");
    Serial.print(heading);
    Serial.println(" ");
    Serial.println("The clockwise angle between the magnetic north and the projection of the positive X-Axis in the horizontal plane:");
    Serial.println(tiltheading);
    Serial.println("   ");
    Serial.println("   ");
    Serial.println("   ");*/



    //delay(1000);





}


void getHeading(void) {
    heading = 180 * atan2(Mxyz[1], Mxyz[0]) / PI;
    if (heading < 0) {
        heading += 360;
    }
}

void getTiltHeading(void) {
    float pitch = asin(-Axyz[0]);
    float roll = asin(Axyz[1] / cos(pitch));

    float xh = Mxyz[0] * cos(pitch) + Mxyz[2] * sin(pitch);
    float yh = Mxyz[0] * sin(roll) * sin(pitch) + Mxyz[1] * cos(roll) - Mxyz[2] * sin(roll) * cos(pitch);
    float zh = -Mxyz[0] * cos(roll) * sin(pitch) + Mxyz[1] * sin(roll) + Mxyz[2] * cos(roll) * cos(pitch);
    tiltheading = 180 * atan2(yh, xh) / PI;
    if (yh < 0) {
        tiltheading += 360;
    }
}



void Mxyz_init_calibrated() {

    /*Serial.println(F("Before using 9DOF,we need to calibrate the compass frist,It will takes about 2 minutes."));
    Serial.print("  ");
    Serial.println(F("During  calibratting ,you should rotate and turn the 9DOF all the time within 2 minutes."));
    Serial.print("  ");
    Serial.println(F("If you are ready ,please sent a command data 'ready' to start sample and calibrate."));
    while (!Serial.find("ready"));
    Serial.println("  ");
    Serial.println("ready");
    Serial.println("Sample starting......");
    Serial.println("waiting ......");*/

    get_calibration_Data();

    Serial.println("     ");
    Serial.println("compass calibration parameter ");
    Serial.print(mx_centre);
    Serial.print("     ");
    Serial.print(my_centre);
    Serial.print("     ");
    Serial.println(mz_centre);
    Serial.println("    ");
}


void get_calibration_Data() {
    for (int i = 0; i < sample_num_mdate; i++) {
        get_one_sample_date_mxyz();
        /*
            Serial.print(mx_sample[2]);
            Serial.print(" ");
            Serial.print(my_sample[2]);                            //you can see the sample data here .
            Serial.print(" ");
            Serial.println(mz_sample[2]);
        */



        if (mx_sample[2] >= mx_sample[1]) {
            mx_sample[1] = mx_sample[2];
        }
        if (my_sample[2] >= my_sample[1]) {
            my_sample[1] = my_sample[2];    //find max value
        }
        if (mz_sample[2] >= mz_sample[1]) {
            mz_sample[1] = mz_sample[2];
        }

        if (mx_sample[2] <= mx_sample[0]) {
            mx_sample[0] = mx_sample[2];
        }
        if (my_sample[2] <= my_sample[0]) {
            my_sample[0] = my_sample[2];    //find min value
        }
        if (mz_sample[2] <= mz_sample[0]) {
            mz_sample[0] = mz_sample[2];
        }

    }

    mx_max = mx_sample[1];
    my_max = my_sample[1];
    mz_max = mz_sample[1];

    mx_min = mx_sample[0];
    my_min = my_sample[0];
    mz_min = mz_sample[0];



    mx_centre = (mx_max + mx_min) / 2;
    my_centre = (my_max + my_min) / 2;
    mz_centre = (mz_max + mz_min) / 2;

}






void get_one_sample_date_mxyz() {
    getCompass_Data();
    mx_sample[2] = Mxyz[0];
    my_sample[2] = Mxyz[1];
    mz_sample[2] = Mxyz[2];
}


void getAccel_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Axyz[0] = (double) ax / 16384;
    Axyz[1] = (double) ay / 16384;
    Axyz[2] = (double) az / 16384;
}

void getGyro_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Gxyz[0] = (double) gx * 250 / 32768;
    Gxyz[1] = (double) gy * 250 / 32768;
    Gxyz[2] = (double) gz * 250 / 32768;
}

void getCompass_Data(void) {
    I2C_M.writeByte(MPU9150_RA_MAG_ADDRESS, 0x0A, 0x01); //enable the magnetometer
    delay(10);
    I2C_M.readBytes(MPU9150_RA_MAG_ADDRESS, MPU9150_RA_MAG_XOUT_L, 6, buffer_m);

    mx = ((int16_t)(buffer_m[1]) << 8) | buffer_m[0] ;
    my = ((int16_t)(buffer_m[3]) << 8) | buffer_m[2] ;
    mz = ((int16_t)(buffer_m[5]) << 8) | buffer_m[4] ;

    Mxyz[0] = (double) mx * 1200 / 4096;
    Mxyz[1] = (double) my * 1200 / 4096;
    Mxyz[2] = (double) mz * 1200 / 4096;
}

void getCompassDate_calibrated() {
    getCompass_Data();
    Mxyz[0] = Mxyz[0] - mx_centre;
    Mxyz[1] = Mxyz[1] - my_centre;
    Mxyz[2] = Mxyz[2] - mz_centre;
}
```
### Sender
```
#include "I2Cdev.h"
#include "MPU6050.h"
#include <Wire.h>
#include <SPI.h>
#include <LoRa.h>


MPU6050 accelgyro;
I2Cdev   I2C_M;

uint8_t buffer_m[6];


int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t   mx, my, mz;



float heading;
float tiltheading;

float Axyz[3];
float Gxyz[3];
float Mxyz[3];


#define sample_num_mdate  5000

volatile float mx_sample[3];
volatile float my_sample[3];
volatile float mz_sample[3];

static float mx_centre = 0;
static float my_centre = 0;
static float mz_centre = 0;

volatile int mx_max = 0;
volatile int my_max = 0;
volatile int mz_max = 0;

volatile int mx_min = 0;
volatile int my_min = 0;
volatile int mz_min = 0;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.println("LoRa Sender");
  if (!LoRa.begin(433E6)) 
  {
    Serial.println("Starting LoRa failed!");
    while(1);
  }
  // initialize device
    while(!Serial);
    //Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    //Serial.println("Testing device connections...");
    //Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    delay(3000);
    //Serial.println("     ");

    Mxyz_init_calibrated();   
}

void loop()
{
  getAccel_Data();
    getGyro_Data();
    getCompassDate_calibrated(); // compass data has been calibrated here
    getHeading();				//before we use this function we should run 'getCompassDate_calibrated()' frist, so that we can get calibrated data ,then we can get correct angle .
    getTiltHeading();

    /*Serial.println("calibration parameter: ");
    Serial.print(mx_centre);
    Serial.print("         ");
    Serial.print(my_centre);
    Serial.print("         ");
    Serial.println(mz_centre);
    Serial.println("     ");*/


    Serial.println("Acceleration(g) of X,Y,Z:");
    Serial.print(Axyz[0]);
    Serial.print(",");
    Serial.print(Axyz[1]);
    Serial.print(",");
    Serial.println(Axyz[2]);
    Serial.println("Gyro(degress/s) of X,Y,Z:");
    Serial.print(Gxyz[0]);
    Serial.print(",");
    Serial.print(Gxyz[1]);
    Serial.print(",");
    Serial.println(Gxyz[2]);
    Serial.println("Compass Value of X,Y,Z:");
    Serial.print(Mxyz[0]);
    Serial.print(",");
    Serial.print(Mxyz[1]);
    Serial.print(",");
    Serial.println(Mxyz[2]);
    /*Serial.println("The clockwise angle between the magnetic north and X-Axis:");
    Serial.print(heading);
    Serial.println(" ");
    Serial.println("The clockwise angle between the magnetic north and the projection of the positive X-Axis in the horizontal plane:");
    Serial.println(tiltheading);
    Serial.println("   ");
    Serial.println("   ");
    Serial.println("   ");*/



    //delay(1000);
  
}

void getHeading(void) {
    heading = 180 * atan2(Mxyz[1], Mxyz[0]) / PI;
    if (heading < 0) {
        heading += 360;
    }
}

void getTiltHeading(void) {
    float pitch = asin(-Axyz[0]);
    float roll = asin(Axyz[1] / cos(pitch));

    float xh = Mxyz[0] * cos(pitch) + Mxyz[2] * sin(pitch);
    float yh = Mxyz[0] * sin(roll) * sin(pitch) + Mxyz[1] * cos(roll) - Mxyz[2] * sin(roll) * cos(pitch);
    float zh = -Mxyz[0] * cos(roll) * sin(pitch) + Mxyz[1] * sin(roll) + Mxyz[2] * cos(roll) * cos(pitch);
    tiltheading = 180 * atan2(yh, xh) / PI;
    if (yh < 0) {
        tiltheading += 360;
    }
}



void Mxyz_init_calibrated() {

    /*Serial.println(F("Before using 9DOF,we need to calibrate the compass frist,It will takes about 2 minutes."));
    Serial.print("  ");
    Serial.println(F("During  calibratting ,you should rotate and turn the 9DOF all the time within 2 minutes."));
    Serial.print("  ");
    Serial.println(F("If you are ready ,please sent a command data 'ready' to start sample and calibrate."));
    while (!Serial.find("ready"));
    Serial.println("  ");
    Serial.println("ready");
    Serial.println("Sample starting......");
    Serial.println("waiting ......");*/

    get_calibration_Data();

    Serial.println("     ");
    Serial.println("compass calibration parameter ");
    Serial.print(mx_centre);
    Serial.print("     ");
    Serial.print(my_centre);
    Serial.print("     ");
    Serial.println(mz_centre);
    Serial.println("    ");
}


void get_calibration_Data() {
    for (int i = 0; i < sample_num_mdate; i++) {
        get_one_sample_date_mxyz();
        /*
            Serial.print(mx_sample[2]);
            Serial.print(" ");
            Serial.print(my_sample[2]);                            //you can see the sample data here .
            Serial.print(" ");
            Serial.println(mz_sample[2]);
        */



        if (mx_sample[2] >= mx_sample[1]) {
            mx_sample[1] = mx_sample[2];
        }
        if (my_sample[2] >= my_sample[1]) {
            my_sample[1] = my_sample[2];    //find max value
        }
        if (mz_sample[2] >= mz_sample[1]) {
            mz_sample[1] = mz_sample[2];
        }

        if (mx_sample[2] <= mx_sample[0]) {
            mx_sample[0] = mx_sample[2];
        }
        if (my_sample[2] <= my_sample[0]) {
            my_sample[0] = my_sample[2];    //find min value
        }
        if (mz_sample[2] <= mz_sample[0]) {
            mz_sample[0] = mz_sample[2];
        }

    }

    mx_max = mx_sample[1];
    my_max = my_sample[1];
    mz_max = mz_sample[1];

    mx_min = mx_sample[0];
    my_min = my_sample[0];
    mz_min = mz_sample[0];



    mx_centre = (mx_max + mx_min) / 2;
    my_centre = (my_max + my_min) / 2;
    mz_centre = (mz_max + mz_min) / 2;

}






void get_one_sample_date_mxyz() {
    getCompass_Data();
    mx_sample[2] = Mxyz[0];
    my_sample[2] = Mxyz[1];
    mz_sample[2] = Mxyz[2];
}


void getAccel_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Axyz[0] = (double) ax / 16384;
    Axyz[1] = (double) ay / 16384;
    Axyz[2] = (double) az / 16384;
}

void getGyro_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Gxyz[0] = (double) gx * 250 / 32768;
    Gxyz[1] = (double) gy * 250 / 32768;
    Gxyz[2] = (double) gz * 250 / 32768;
}

void getCompass_Data(void) {
    I2C_M.writeByte(MPU9150_RA_MAG_ADDRESS, 0x0A, 0x01); //enable the magnetometer
    delay(10);
    I2C_M.readBytes(MPU9150_RA_MAG_ADDRESS, MPU9150_RA_MAG_XOUT_L, 6, buffer_m);

    mx = ((int16_t)(buffer_m[1]) << 8) | buffer_m[0] ;
    my = ((int16_t)(buffer_m[3]) << 8) | buffer_m[2] ;
    mz = ((int16_t)(buffer_m[5]) << 8) | buffer_m[4] ;

    Mxyz[0] = (double) mx * 1200 / 4096;
    Mxyz[1] = (double) my * 1200 / 4096;
    Mxyz[2] = (double) mz * 1200 / 4096;
}

void getCompassDate_calibrated() {
    getCompass_Data();
    Mxyz[0] = Mxyz[0] - mx_centre;
    Mxyz[1] = Mxyz[1] - my_centre;
    Mxyz[2] = Mxyz[2] - mz_centre;

    String msg = String(Axyz[0]+500)+" "+String(Axyz[1]+500)+" "+String(Axyz[2]+500)+" "+String(Gxyz[0]+500)+" "+String(Gxyz[1]+500)+" "+String(Gxyz[2]+500)+" "+String(Mxyz[0]+500)+" "+String(Mxyz[1]+500)+" "+String(Mxyz[2]+500);
  
  Serial.println();
  Serial.println();
  Serial.println(msg);
  
  
  
  LoRa.beginPacket();
  LoRa.print(msg);
  LoRa.endPacket();
  delay(1000);
}
```

### Receiver
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  String str="";
  String Axyz0="";
  String Axyz1="";
  String Axyz2="";
  String Gxyz0="";
  String Gxyz1="";
  String Gxyz2="";
  String Mxyz0="";
  String Mxyz1="";
  String Mxyz2="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize)
   
   {
    Serial.println("Received packet: ");
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }

    Axyz0 = str.substring(0,6);
    Axyz1 = str.substring(7,13);
    Axyz2 = str.substring(14,20);
    Gxyz0 = str.substring(21,27);
    Gxyz1 = str.substring(28,34);
    Gxyz2 = str.substring(35,41);
    Mxyz0 = str.substring(42,48);
    Mxyz1 = str.substring(49,55);
    Mxyz2 = str.substring(56,62);

    Serial.println("Acceleration(g) of X,Y,Z:");
    Serial.print(Axyz0);
    Serial.print(",");
    Serial.print(Axyz1);
    Serial.print(",");
    Serial.println(Axyz2);
    Serial.println("Gyro(degress/s) of X,Y,Z:");
    Serial.print(Gxyz0);
    Serial.print(",");
    Serial.print(Gxyz1);
    Serial.print(",");
    Serial.println(Gxyz2);
    Serial.println("Compass Value of X,Y,Z:");
    Serial.print(Mxyz0);
    Serial.print(",");
    Serial.print(Mxyz1);
    Serial.print(",");
    Serial.println(Mxyz2);
    
    Serial.print("RSSI: ");
    Serial.println(LoRa.packetRssi());
    Serial.println();
  }
//  delay(1000);     
}
```
## CJMCU-8128+MPU9250
### Sender
```
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Adafruit_CCS811.h"
#include <BMx280_EnvCalc.h>
#include <sSense-BMx280I2C.h>
#include <Wire.h>
#include <SPI.h>
#include <LoRa.h>

#define SERIAL_SPEED 9600

Adafruit_CCS811 ccs;
BMx280I2C ssenseBMx280;

MPU6050 accelgyro;
I2Cdev   I2C_M;

uint8_t buffer_m[6];


int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t   mx, my, mz;



float heading;
float tiltheading;

float Axyz[3];
float Gxyz[3];
float Mxyz[3];


#define sample_num_mdate  5000

volatile float mx_sample[3];
volatile float my_sample[3];
volatile float mz_sample[3];

static float mx_centre = 0;
static float my_centre = 0;
static float mz_centre = 0;

volatile int mx_max = 0;
volatile int my_max = 0;
volatile int mz_max = 0;

volatile int mx_min = 0;
volatile int my_min = 0;
volatile int mz_min = 0;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.println("LoRa Sender");
  if (!LoRa.begin(433E6)) 
  {
    Serial.println("Starting LoRa failed!");
    while(1);
  }

  Serial.begin(SERIAL_SPEED);
  ccs.begin();
  DebugPort.begin(SERIAL_SPEED);

  while(!DebugPort) {} // Wait

  Wire.begin();

  while(!ssenseBMx280.begin())
  {
    DebugPort.println("Could not find BME280 sensor!");
    delay(50);
  }

  // initialize device
    while(!Serial);
    
    accelgyro.initialize();
    delay(3000);
    Mxyz_init_calibrated();   
}

void loop()
{
  Serial.println();
    
    if(ccs.available())
    {
      
    if(!ccs.readData()){
      //Serial.print("CO2(ppm):");
      //Serial.print(ccs.geteCO2());
    }
    else{
      Serial.println("ERROR!,ERROR!,");
    }
  }
   printBMx280Data(&DebugPort);
   

  delay(2000);

  getAccel_Data();
    getGyro_Data();
    getCompassDate_calibrated(); // compass data has been calibrated here
    getHeading();    //before we use this function we should run 'getCompassDate_calibrated()' frist, so that we can get calibrated data ,then we can get correct angle .
    getTiltHeading();

    Serial.print("Acceleration(g) of X,Y,Z : ");
    Serial.print(Axyz[0]);
    Serial.print(" , ");
    Serial.print(Axyz[1]);
    Serial.print(" , ");
    Serial.println(Axyz[2]);
    Serial.print("Gyro(degress/s) of X,Y,Z : ");
    Serial.print(Gxyz[0]);
    Serial.print(" , ");
    Serial.print(Gxyz[1]);
    Serial.print(" , ");
    Serial.println(Gxyz[2]);
    Serial.print("Compass Value   of X,Y,Z : ");
    Serial.print(Mxyz[0]);
    Serial.print(" , ");
    Serial.print(Mxyz[1]);
    Serial.print(" , ");
    Serial.println(Mxyz[2]);
  
    
}

void getHeading(void) {
    heading = 180 * atan2(Mxyz[1], Mxyz[0]) / PI;
    if (heading < 0) {
        heading += 360;
    }
}



void getTiltHeading(void) {
    float pitch = asin(-Axyz[0]);
    float roll = asin(Axyz[1] / cos(pitch));

    float xh = Mxyz[0] * cos(pitch) + Mxyz[2] * sin(pitch);
    float yh = Mxyz[0] * sin(roll) * sin(pitch) + Mxyz[1] * cos(roll) - Mxyz[2] * sin(roll) * cos(pitch);
    float zh = -Mxyz[0] * cos(roll) * sin(pitch) + Mxyz[1] * sin(roll) + Mxyz[2] * cos(roll) * cos(pitch);
    tiltheading = 180 * atan2(yh, xh) / PI;
    if (yh < 0) {
        tiltheading += 360;
    }
}



void Mxyz_init_calibrated() {

    get_calibration_Data();

    Serial.println("     ");
    Serial.println("compass calibration parameter ");
    Serial.print(mx_centre);
    Serial.print("     ");
    Serial.print(my_centre);
    Serial.print("     ");
    Serial.println(mz_centre);
    Serial.println("    ");
}


void get_calibration_Data() {
    for (int i = 0; i < sample_num_mdate; i++) {
        get_one_sample_date_mxyz();
        
        if (mx_sample[2] >= mx_sample[1]) {
            mx_sample[1] = mx_sample[2];
        }
        if (my_sample[2] >= my_sample[1]) {
            my_sample[1] = my_sample[2];    //find max value
        }
        if (mz_sample[2] >= mz_sample[1]) {
            mz_sample[1] = mz_sample[2];
        }

        if (mx_sample[2] <= mx_sample[0]) {
            mx_sample[0] = mx_sample[2];
        }
        if (my_sample[2] <= my_sample[0]) {
            my_sample[0] = my_sample[2];    //find min value
        }
        if (mz_sample[2] <= mz_sample[0]) {
            mz_sample[0] = mz_sample[2];
        }

    }

    mx_max = mx_sample[1];
    my_max = my_sample[1];
    mz_max = mz_sample[1];

    mx_min = mx_sample[0];
    my_min = my_sample[0];
    mz_min = mz_sample[0];



    mx_centre = (mx_max + mx_min) / 2;
    my_centre = (my_max + my_min) / 2;
    mz_centre = (mz_max + mz_min) / 2;

}








void get_one_sample_date_mxyz() {
    getCompass_Data();
    mx_sample[2] = Mxyz[0];
    my_sample[2] = Mxyz[1];
    mz_sample[2] = Mxyz[2];
}


void getAccel_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Axyz[0] = (double) ax / 16384;
    Axyz[1] = (double) ay / 16384;
    Axyz[2] = (double) az / 16384;
}

void getGyro_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Gxyz[0] = (double) gx * 250 / 32768;
    Gxyz[1] = (double) gy * 250 / 32768;
    Gxyz[2] = (double) gz * 250 / 32768;
}

void getCompass_Data(void) {
    I2C_M.writeByte(MPU9150_RA_MAG_ADDRESS, 0x0A, 0x01); //enable the magnetometer
    delay(10);
    I2C_M.readBytes(MPU9150_RA_MAG_ADDRESS, MPU9150_RA_MAG_XOUT_L, 6, buffer_m);

    mx = ((int16_t)(buffer_m[1]) << 8) | buffer_m[0] ;
    my = ((int16_t)(buffer_m[3]) << 8) | buffer_m[2] ;
    mz = ((int16_t)(buffer_m[5]) << 8) | buffer_m[4] ;

    Mxyz[0] = (double) mx * 1200 / 4096;
    Mxyz[1] = (double) my * 1200 / 4096;
    Mxyz[2] = (double) mz * 1200 / 4096;
}



void getCompassDate_calibrated() {
    getCompass_Data();
    Mxyz[0] = Mxyz[0] - mx_centre;
    Mxyz[1] = Mxyz[1] - my_centre;
    Mxyz[2] = Mxyz[2] - mz_centre;

}

void printBMx280Data( Stream* client )
{
   float temp(NAN), hum(NAN), pres(NAN);

   BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
   BME280::PresUnit presUnit(BME280::PresUnit_Pa);

  /* client->print(temp);
   client->print(",");
   
   client->print(pres);
   client->print(",");*/

    ssenseBMx280.read(pres, temp, hum, tempUnit, presUnit);
   BMx280_EnvCalc::AltitudeUnit envAltUnit  =  BMx280_EnvCalc::AltitudeUnit_Meters;
   BMx280_EnvCalc::TempUnit     envTempUnit =  BMx280_EnvCalc::TempUnit_Celsius;

   float altitude = BMx280_EnvCalc::Altitude(pres, envAltUnit);
    
    Serial.print("Co2  : ");
    Serial.print(ccs.geteCO2());
    Serial.println(" ppm");
    Serial.print("Temp : ");
    Serial.print(temp);
    Serial.println(" C");
    Serial.print("Pres : ");
    Serial.print(pres);
    Serial.println(" Pa");
    Serial.print("Alti : ");
    Serial.print(altitude);
    Serial.println(" m");
    Serial.println();
    Serial.println("=============================================");
    String msg = String(Axyz[0]+500)+" "+String(Axyz[1]+500)+" "+String(Axyz[2]+500)+" "+String(Gxyz[0]+500)+" "+String(Gxyz[1]+500)+" "+String(Gxyz[2]+500)+" "+String(Mxyz[0]+500)+" "+String(Mxyz[1]+500)+" "+String(Mxyz[2]+500)+" "+String(ccs.geteCO2()+1000)+" "+String(temp)+" "+String(pres)+" "+String(altitude);
  

  Serial.print("Send packet:");
  Serial.println(msg);
  Serial.println();
  
  LoRa.beginPacket();
  LoRa.print(msg);
  LoRa.endPacket();
  delay(1000);
}
```
### Receiver
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  String str="";
  String Axyz0="";
  String Axyz1="";
  String Axyz2="";
  String Gxyz0="";
  String Gxyz1="";
  String Gxyz2="";
  String Mxyz0="";
  String Mxyz1="";
  String Mxyz2="";
  String ccsgeteCO2="";
  String temp="";
  String pres="";
  String altitude="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize)
   
   {
    Serial.println("Received packet: ");
    Serial.println();
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }

    Axyz0 = str.substring(0,6);
    Axyz1 = str.substring(7,13);
    Axyz2 = str.substring(14,20);
    Gxyz0 = str.substring(21,27);
    Gxyz1 = str.substring(28,34);
    Gxyz2 = str.substring(35,41);
    Mxyz0 = str.substring(42,48);
    Mxyz1 = str.substring(49,55);
    Mxyz2 = str.substring(56,62);
    ccsgeteCO2 = str.substring(63,67);
    temp = str.substring(68,73);
    pres = str.substring(74,83);
    altitude = str.substring(84,89);


    Serial.print("Acceleration(g) of X,Y,Z : ");
    Serial.print(Axyz0);
    Serial.print(" , ");
    Serial.print(Axyz1);
    Serial.print(" , ");
    Serial.println(Axyz2);
    Serial.print("Gyro(degress/s) of X,Y,Z : ");
    Serial.print(Gxyz0);
    Serial.print(" , ");
    Serial.print(Gxyz1);
    Serial.print(" , ");
    Serial.println(Gxyz2);
    Serial.print("Compass Value   of X,Y,Z : ");
    Serial.print(Mxyz0);
    Serial.print(" , ");
    Serial.print(Mxyz1);
    Serial.print(" , ");
    Serial.println(Mxyz2);
    Serial.println();

    Serial.print("Co2  : ");
    Serial.print(ccsgeteCO2);
    Serial.println(" ppm");
    Serial.print("Temp : ");
    Serial.print(temp);
    Serial.println(" C");
    Serial.print("Pres : ");
    Serial.print(pres);
    Serial.println(" Pa");
    Serial.print("Alti : ");
    Serial.print(altitude);
    Serial.println(" m");
    Serial.println();
    
    Serial.print("RSSI : ");
    Serial.println(LoRa.packetRssi());
    Serial.println("=============================================");
  }
//  delay(1000);     
}

```

### Receiver with PLXDAQ
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
  Serial.println("CLEARSHEET");
  Serial.println("LABEL,Time,Timer,Acc X,Acc Y,Acc Z,Gyro X,Gyro Y,Gyro Z,Mag X,Mag Y,Mag Z,Co2(ppm),Temp(c),Pressure(Pa),Altitude(m),RSSI");
}

void loop() {
  String str="";
  String Axyz0="";
  String Axyz1="";
  String Axyz2="";
  String Gxyz0="";
  String Gxyz1="";
  String Gxyz2="";
  String Mxyz0="";
  String Mxyz1="";
  String Mxyz2="";
  String ccsgeteCO2="";
  String temp="";
  String pres="";
  String altitude="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize)
   
   {
    //Serial.println("Received packet: ");
    Serial.println();
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }

    Axyz0 = str.substring(0,6);
    Axyz1 = str.substring(7,13);
    Axyz2 = str.substring(14,20);
    Gxyz0 = str.substring(21,27);
    Gxyz1 = str.substring(28,34);
    Gxyz2 = str.substring(35,41);
    Mxyz0 = str.substring(42,48);
    Mxyz1 = str.substring(49,55);
    Mxyz2 = str.substring(56,62);
    ccsgeteCO2 = str.substring(63,67);
    temp = str.substring(68,73);
    pres = str.substring(74,83);
    altitude = str.substring(84,89);

    Serial.print("DATA, TIME, TIMER,");
    Serial.print(Axyz0);
    Serial.print(",");
    Serial.print(Axyz1);
    Serial.print(",");
    Serial.print(Axyz2);
    Serial.print(",");
    Serial.print(Gxyz0);
    Serial.print(",");
    Serial.print(Gxyz1);
    Serial.print(",");
    Serial.print(Gxyz2);
    Serial.print(",");
    Serial.print(Mxyz0);
    Serial.print(",");
    Serial.print(Mxyz1);
    Serial.print(",");
    Serial.print(Mxyz2);
    Serial.print(",");
    Serial.print(ccsgeteCO2);
    Serial.print(",");
    Serial.print(temp);
    Serial.print(",");
    Serial.print(pres);
    Serial.print(",");
    Serial.print(altitude);
    Serial.print(",");

    /*
    Serial.print("Acceleration(g) of X,Y,Z : ");
    Serial.print(Axyz0);
    Serial.print(" , ");
    Serial.print(Axyz1);
    Serial.print(" , ");
    Serial.println(Axyz2);
    Serial.print("Gyro(degress/s) of X,Y,Z : ");
    Serial.print(Gxyz0);
    Serial.print(" , ");
    Serial.print(Gxyz1);
    Serial.print(" , ");
    Serial.println(Gxyz2);
    Serial.print("Compass Value   of X,Y,Z : ");
    Serial.print(Mxyz0);
    Serial.print(" , ");
    Serial.print(Mxyz1);
    Serial.print(" , ");
    Serial.println(Mxyz2);
    Serial.println();

    Serial.print("Co2  : ");
    Serial.print(ccsgeteCO2);
    Serial.println(" ppm");
    Serial.print("Temp : ");
    Serial.print(temp);
    Serial.println(" C");
    Serial.print("Pres : ");
    Serial.print(pres);
    Serial.println(" Pa");
    Serial.print("Alti : ");
    Serial.print(altitude);
    Serial.println(" m");
    Serial.println();
    
    Serial.print("RSSI : ");
    Serial.println(LoRa.packetRssi());
    Serial.println("=============================================");
    */

    Serial.print(LoRa.packetRssi());
  }
//  delay(1000);     
}
```
## TX RX
### 接收端
```
void setup() {

  Serial.begin(9600);  //設定通訊速率

}

 

void loop() {

  while (!Serial.available()) {}   //直到暫存器出現訊號才跳出迴圈

  Serial.write(Serial.read());  //傳輸讀取的訊號

  while (Serial.available()>0) {   //如果暫存器有訊號則不斷讀取直到沒有

    Serial.read();

  }  

}
```

### 上段航電（下段上傳尚未成功，其餘傳送地面站OK）
5/22 二氧化碳無讀取（其餘正常）
```
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Adafruit_CCS811.h"
#include <BMx280_EnvCalc.h>
#include <sSense-BMx280I2C.h>
#include <BMP180.h>


#include <Wire.h>
#include <SPI.h>
#include <LoRa.h>

#define SERIAL_SPEED 9600
BMP180 bmp180;
Adafruit_CCS811 ccs;
BMx280I2C ssenseBMx280;

MPU6050 accelgyro;
I2Cdev   I2C_M;

uint8_t buffer_m[6];


int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t   mx, my, mz;



float heading;
float tiltheading;

float Axyz[3];
float Gxyz[3];
float Mxyz[3];


#define sample_num_mdate  5000

volatile float mx_sample[3];
volatile float my_sample[3];
volatile float mz_sample[3];

static float mx_centre = 0;
static float my_centre = 0;
static float mz_centre = 0;

volatile int mx_max = 0;
volatile int my_max = 0;
volatile int mz_max = 0;

volatile int mx_min = 0;
volatile int my_min = 0;
volatile int mz_min = 0;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.println("LoRa Sender");
  if (!LoRa.begin(433E6)) 
  {
    Serial.println("Starting LoRa failed!");
    while(1);
  }

  Serial.begin(SERIAL_SPEED);
  ccs.begin();
  DebugPort.begin(SERIAL_SPEED);

  while(!DebugPort) {} // Wait

  Wire.begin();

  while(!ssenseBMx280.begin())
  {
    DebugPort.println("Could not find BME280 sensor!");
    delay(50);
  }

  // initialize device
    while(!Serial);
    
    accelgyro.initialize();
    delay(3000);
    Mxyz_init_calibrated();   
}

void loop()
{
  Serial.println();
    
    if(ccs.available())
    {
      
    if(!ccs.readData()){
      //Serial.print("CO2(ppm):");
      //Serial.print(ccs.geteCO2());
    }
    else{
      Serial.println("ERROR!,ERROR!,");
    }
  }
   printBMx280Data(&DebugPort);
   

  delay(2000);

  getAccel_Data();
    getGyro_Data();
    getCompassDate_calibrated(); // compass data has been calibrated here
    getHeading();    //before we use this function we should run 'getCompassDate_calibrated()' frist, so that we can get calibrated data ,then we can get correct angle .
    getTiltHeading();

    Serial.print("Acceleration(g) of X,Y,Z : ");
    Serial.print(Axyz[0]);
    Serial.print(" , ");
    Serial.print(Axyz[1]);
    Serial.print(" , ");
    Serial.println(Axyz[2]);
    Serial.print("Gyro(degress/s) of X,Y,Z : ");
    Serial.print(Gxyz[0]);
    Serial.print(" , ");
    Serial.print(Gxyz[1]);
    Serial.print(" , ");
    Serial.println(Gxyz[2]);
    Serial.print("Compass Value   of X,Y,Z : ");
    Serial.print(Mxyz[0]);
    Serial.print(" , ");
    Serial.print(Mxyz[1]);
    Serial.print(" , ");
    Serial.println(Mxyz[2]);
  
    
}

void getHeading(void) {
    heading = 180 * atan2(Mxyz[1], Mxyz[0]) / PI;
    if (heading < 0) {
        heading += 360;
    }
}



void getTiltHeading(void) {
    float pitch = asin(-Axyz[0]);
    float roll = asin(Axyz[1] / cos(pitch));

    float xh = Mxyz[0] * cos(pitch) + Mxyz[2] * sin(pitch);
    float yh = Mxyz[0] * sin(roll) * sin(pitch) + Mxyz[1] * cos(roll) - Mxyz[2] * sin(roll) * cos(pitch);
    float zh = -Mxyz[0] * cos(roll) * sin(pitch) + Mxyz[1] * sin(roll) + Mxyz[2] * cos(roll) * cos(pitch);
    tiltheading = 180 * atan2(yh, xh) / PI;
    if (yh < 0) {
        tiltheading += 360;
    }
}



void Mxyz_init_calibrated() {

    get_calibration_Data();

    Serial.println("     ");
    Serial.println("compass calibration parameter ");
    Serial.print(mx_centre);
    Serial.print("     ");
    Serial.print(my_centre);
    Serial.print("     ");
    Serial.println(mz_centre);
    Serial.println("    ");
}


void get_calibration_Data() {
    for (int i = 0; i < sample_num_mdate; i++) {
        get_one_sample_date_mxyz();
        
        if (mx_sample[2] >= mx_sample[1]) {
            mx_sample[1] = mx_sample[2];
        }
        if (my_sample[2] >= my_sample[1]) {
            my_sample[1] = my_sample[2];    //find max value
        }
        if (mz_sample[2] >= mz_sample[1]) {
            mz_sample[1] = mz_sample[2];
        }

        if (mx_sample[2] <= mx_sample[0]) {
            mx_sample[0] = mx_sample[2];
        }
        if (my_sample[2] <= my_sample[0]) {
            my_sample[0] = my_sample[2];    //find min value
        }
        if (mz_sample[2] <= mz_sample[0]) {
            mz_sample[0] = mz_sample[2];
        }

    }

    mx_max = mx_sample[1];
    my_max = my_sample[1];
    mz_max = mz_sample[1];

    mx_min = mx_sample[0];
    my_min = my_sample[0];
    mz_min = mz_sample[0];



    mx_centre = (mx_max + mx_min) / 2;
    my_centre = (my_max + my_min) / 2;
    mz_centre = (mz_max + mz_min) / 2;

}








void get_one_sample_date_mxyz() {
    getCompass_Data();
    mx_sample[2] = Mxyz[0];
    my_sample[2] = Mxyz[1];
    mz_sample[2] = Mxyz[2];
}


void getAccel_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Axyz[0] = (double) ax / 16384;
    Axyz[1] = (double) ay / 16384;
    Axyz[2] = (double) az / 16384;
}

void getGyro_Data(void) {
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Gxyz[0] = (double) gx * 250 / 32768;
    Gxyz[1] = (double) gy * 250 / 32768;
    Gxyz[2] = (double) gz * 250 / 32768;
}

void getCompass_Data(void) {
    I2C_M.writeByte(MPU9150_RA_MAG_ADDRESS, 0x0A, 0x01); //enable the magnetometer
    delay(10);
    I2C_M.readBytes(MPU9150_RA_MAG_ADDRESS, MPU9150_RA_MAG_XOUT_L, 6, buffer_m);

    mx = ((int16_t)(buffer_m[1]) << 8) | buffer_m[0] ;
    my = ((int16_t)(buffer_m[3]) << 8) | buffer_m[2] ;
    mz = ((int16_t)(buffer_m[5]) << 8) | buffer_m[4] ;

    Mxyz[0] = (double) mx * 1200 / 4096;
    Mxyz[1] = (double) my * 1200 / 4096;
    Mxyz[2] = (double) mz * 1200 / 4096;
}



void getCompassDate_calibrated() {
    getCompass_Data();
    Mxyz[0] = Mxyz[0] - mx_centre;
    Mxyz[1] = Mxyz[1] - my_centre;
    Mxyz[2] = Mxyz[2] - mz_centre;

}

void printBMx280Data( Stream* client )
{
   float temp(NAN), hum(NAN), pres(NAN);

   BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
   BME280::PresUnit presUnit(BME280::PresUnit_Pa);

  /* client->print(temp);
   client->print(",");
   
   client->print(pres);
   client->print(",");*/

    ssenseBMx280.read(pres, temp, hum, tempUnit, presUnit);
   BMx280_EnvCalc::AltitudeUnit envAltUnit  =  BMx280_EnvCalc::AltitudeUnit_Meters;
   BMx280_EnvCalc::TempUnit     envTempUnit =  BMx280_EnvCalc::TempUnit_Celsius;

   float altitude = BMx280_EnvCalc::Altitude(pres, envAltUnit);
    
    Serial.print("Co2  : ");
    Serial.print(ccs.geteCO2());
    Serial.println(" ppm");
    Serial.print("Temp : ");
    Serial.print(temp);
    Serial.println(" C");
    Serial.print("Pres : ");
    Serial.print(pres);
    Serial.println(" Pa");
    Serial.print("Alti : ");
    Serial.print(altitude);
    Serial.println(" m");
    Serial.println();

   while (!Serial.available()) {}   //直到暫存器出現訊號才跳出迴圈

  Serial.write(Serial.read());  //傳輸讀取的訊號

  while (Serial.available()>0) {   //如果暫存器有訊號則不斷讀取直到沒有

    Serial.read();

  }

    Serial.println("=============================================");
    String msg = String(Axyz[0]+500)+" "+String(Axyz[1]+500)+" "+String(Axyz[2]+500)+" "+String(Gxyz[0]+500)+" "+String(Gxyz[1]+500)+" "+String(Gxyz[2]+500)+" "+String(Mxyz[0]+500)+" "+String(Mxyz[1]+500)+" "+String(Mxyz[2]+500)+" "+String(ccs.geteCO2()+1000)+" "+String(temp)+" "+String(pres)+" "+String(altitude)+" "+String(bmp180.getTemperature());
  

  Serial.print("Send packet:");
  Serial.println(msg);
  Serial.println();
  
  LoRa.beginPacket();
  LoRa.print(msg);
  LoRa.endPacket();
  delay(1000);
}
```
### 下段航電（BMP180測試中）
*上傳上段尚未成功
```
#include <Wire.h>
#include <BMP180.h>

BMP180 bmp180;

void setup()
{
  // init
  bmp180.init();

  // welcome
  Serial.begin(9600);
  Serial.println("BMP180 Demo");
  if (!bmp180.hasValidID())
    Serial.println("Error - please check the BMP180 board!");
}

void loop() {

  Serial.print("Temp2: ");
  Serial.print(bmp180.getTemperature());
  Serial.println(" C");

  delay(1000);
}

```

### 地面站
運作ok（下段航電上傳還沒成功，未能讀取下段資料）
```
#include <SPI.h>
#include <LoRa.h>
#include <string.h>

void setup() {
  Serial.begin(9600);
  Serial.println("LoRa Receiver");
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
  Serial.println("CLEARSHEET");
  Serial.println("LABEL,Time,Timer,Acc X,Acc Y,Acc Z,Gyro X,Gyro Y,Gyro Z,Mag X,Mag Y,Mag Z,Co2(ppm),Temp(c),Pressure(Pa),Altitude(m),Temp2(c),RSSI");
}

void loop() {
  String str="";
  String Axyz0="";
  String Axyz1="";
  String Axyz2="";
  String Gxyz0="";
  String Gxyz1="";
  String Gxyz2="";
  String Mxyz0="";
  String Mxyz1="";
  String Mxyz2="";
  String ccsgeteCO2="";
  String temp="";
  String pres="";
  String altitude="";
  String temp2="";
  
  int packetSize = LoRa.parsePacket();
  if (packetSize)
   
   {
    //Serial.println("Received packet: ");
    Serial.println();
    // 讀取封包
    while (LoRa.available())  {
      str=str+((char)LoRa.read());    
    }

    Axyz0 = str.substring(0,6);
    Axyz1 = str.substring(7,13);
    Axyz2 = str.substring(14,20);
    Gxyz0 = str.substring(21,27);
    Gxyz1 = str.substring(28,34);
    Gxyz2 = str.substring(35,41);
    Mxyz0 = str.substring(42,48);
    Mxyz1 = str.substring(49,55);
    Mxyz2 = str.substring(56,62);
    ccsgeteCO2 = str.substring(63,67);
    temp = str.substring(68,73);
    pres = str.substring(74,83);
    altitude = str.substring(84,89);
    temp2 = str.substring(90,94);

    Serial.print("DATA, TIME, TIMER,");
    Serial.print(Axyz0);
    Serial.print(",");
    Serial.print(Axyz1);
    Serial.print(",");
    Serial.print(Axyz2);
    Serial.print(",");
    Serial.print(Gxyz0);
    Serial.print(",");
    Serial.print(Gxyz1);
    Serial.print(",");
    Serial.print(Gxyz2);
    Serial.print(",");
    Serial.print(Mxyz0);
    Serial.print(",");
    Serial.print(Mxyz1);
    Serial.print(",");
    Serial.print(Mxyz2);
    Serial.print(",");
    Serial.print(ccsgeteCO2);
    Serial.print(",");
    Serial.print(temp);
    Serial.print(",");
    Serial.print(pres);
    Serial.print(",");
    Serial.print(altitude);
    Serial.print(",");
     Serial.print(temp2);
    Serial.print(",");
    

    /*
    Serial.print("Acceleration(g) of X,Y,Z : ");
    Serial.print(Axyz0);
    Serial.print(" , ");
    Serial.print(Axyz1);
    Serial.print(" , ");
    Serial.println(Axyz2);
    Serial.print("Gyro(degress/s) of X,Y,Z : ");
    Serial.print(Gxyz0);
    Serial.print(" , ");
    Serial.print(Gxyz1);
    Serial.print(" , ");
    Serial.println(Gxyz2);
    Serial.print("Compass Value   of X,Y,Z : ");
    Serial.print(Mxyz0);
    Serial.print(" , ");
    Serial.print(Mxyz1);
    Serial.print(" , ");
    Serial.println(Mxyz2);
    Serial.println();

    Serial.print("Co2  : ");
    Serial.print(ccsgeteCO2);
    Serial.println(" ppm");
    Serial.print("Temp : ");
    Serial.print(temp);
    Serial.println(" C");
    Serial.print("Pres : ");
    Serial.print(pres);
    Serial.println(" Pa");
    Serial.print("Alti : ");
    Serial.print(altitude);
    Serial.println(" m");
    Serial.println();
    
    Serial.print("RSSI : ");
    Serial.println(LoRa.packetRssi());
    Serial.println("=============================================");
    */

    Serial.print(LoRa.packetRssi());
  }
//  delay(1000);     
}
```

## Servo控制
測試功能
```
#include <Servo.h> 

Servo servo; // servo object representing the MG 996R servo

void setup() {
  servo.attach(3); // servo is wired to Arduino on digital pin 3
}

void loop() {
  servo.write(0); // move MG996R's shaft to angle 0°
  delay(3000); // wait for one second
  servo.write(90); // move MG996R's shaft to angle 90°
  delay(3000); // wait for one second 
  servo.write(180); // move MG996R's shaft to angle 180°
  delay(3000); // wait for one second
}
```
5/29: 0是OFF；1是ON（開閥關閥）*還沒試過
```
#include <Servo.h>

Servo servo; // 代表 MG996R 伺服馬達的 servo 物件
int servoPin = 3; // 伺服馬達連接至 Arduino 的數位腳位

void setup() {
  servo.attach(servoPin);
}

void loop() {
  int input = readInput(); // 讀取使用者輸入的數值
  if (input == 1) {
    servo.write(90); // 將 MG996R 伺服馬達的角度設定為 90°
  } else if (input == 0) {
    servo.write(0); // 將 MG996R 伺服馬達的角度設定為 0°
  }
  delay(100); // 延遲一段時間等待馬達轉動到指定角度
}

int readInput() {
  while (true) {
    if (Serial.available() > 0) {
      int value = Serial.parseInt();
      // 消耗掉 Serial 緩衝區中的所有字符
      while (Serial.available() > 0) {
        Serial.read();
      }
      return value;
    }
  }
}
```


## Pressure Sensor
https://www.youtube.com/watch?v=UrqPxwsPWGk&t=153s&ab_channel=OvensGarage
```
/* This example demonstrates how to take a standard 3-wire pressure transducer
 *  and read the analog signal, then convert the signal to a readable output and
 *  display it onto an LCD screen.
 *  
 *  Contact Tyler at tylerovens@me.com if you have any questions
 */

const int pressureInput = A0; //select the analog input pin for the pressure transducer
const int pressureZero = 102.4; //analog reading of pressure transducer at 0psi
const int pressureMax = 921.6; //analog reading of pressure transducer at 100psi
const int pressuretransducermaxPSI = 100; //psi value of transducer being used
const int baudRate = 9600; //constant integer to set the baud rate for serial monitor
const int sensorreadDelay = 250; //constant integer to set the sensor read delay in milliseconds

float pressureValue = 0; //variable to store the value coming from the pressure transducer

void setup() //setup routine, runs once when system turned on or reset
{
  Serial.begin(baudRate); //initializes serial communication at set baud rate bits per second
}

void loop() //loop routine runs over and over again forever
{
  pressureValue = analogRead(pressureInput); //reads value from input pin and assigns to variable
  pressureValue = ((pressureValue-pressureZero)*pressuretransducermaxPSI)/(pressureMax-pressureZero); //conversion equation to convert analog reading to psi
  Serial.print(pressureValue, 1); //prints value from previous line to serial
  Serial.println("psi"); //prints label to serial
  delay(sensorreadDelay); //delay in milliseconds between read values
}


```
*5/28 數值讀取不穩定、吹氣測試數值變低，且後維持在降低後的範圍。