# 航電元件程式碼 ###### 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 數值讀取不穩定、吹氣測試數值變低,且後維持在降低後的範圍。