如何把MPU6050輸出的加速度和角速度換算成角度

1 介紹

自己在研究一個題目,就是如何把MPU6050輸出的加速度和角速度換算成角度吴汪。所以我想在市面上找一個MPU6050蜈亩,可以自己輸出的角度的,這樣我就能做一個對比了修赞。同時婶恼,能夠把IIC引腳留出來的方便我自己開發(fā)MPU6050芯片桑阶。我在淘寶上找到了一款JY61模塊。它內(nèi)置的是MPU6050芯片勾邦。串口直接輸出的很簡單蚣录。給大家看下圖片:

JY61

2 MPU6050的工作過程

MPU6050 IMU在單芯片上集成了一個3軸加速度計和一個3軸陀螺儀。陀螺儀沿X眷篇、Y和Z軸測量角位置隨時間的旋轉(zhuǎn)速度或變化率萎河。它使用MEMS技術(shù)和科里奧利效應(yīng)進(jìn)行測量。陀螺儀的輸出以每秒度數(shù)為單位蕉饼,因此為了獲得角度位置虐杯,我們只需要對角速度進(jìn)行積分。另一方面昧港,MPU6050加速度計測量加速度的方式與ADXL345加速度傳感器相同擎椰。簡而言之,它可以測量沿3個軸的重力加速度创肥,并使用一些三角學(xué)數(shù)學(xué)达舒,我們可以計算傳感器定位的角度。因此叹侄,如果我們?nèi)诤匣蚪M合加速度計和陀螺儀數(shù)據(jù)休弃,我們可以獲得有關(guān)傳感器方向的非常準(zhǔn)確的信息。MPU6050 IMU也稱為六軸運(yùn)動跟蹤設(shè)備或6 DoF(六自由度)設(shè)備圈膏,因為它有6個輸出,即3個加速度計輸出和3個陀螺儀輸出篙骡。

3 Arduino和MPU6050的連接方法

我們來看看如何使用Arduino連接和讀取MPU6050傳感器的數(shù)據(jù)稽坤。我們使用I2C協(xié)議與Arduino進(jìn)行通信,因此只需要兩條線進(jìn)行連接糯俗,另外還有兩條線用于供電尿褪。

4 MPU6050的Arduino代碼

以下是用于從MPU6050傳感器讀取數(shù)據(jù)的Arduino代碼。這個代碼可以直接復(fù)制使用的得湘。在代碼下方杖玲,您可以找到它的詳細(xì)說明。

/*

? Arduino and MPU6050 Accelerometer and Gyroscope Sensor Tutorial

*/#include <Wire.h>const int MPU = 0x68; // MPU6050 I2C addressfloat AccX, AccY, AccZ;float GyroX, GyroY, GyroZ;float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;float roll, pitch, yaw;float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY, GyroErrorZ;float elapsedTime, currentTime, previousTime;int c = 0;void setup() {? Serial.begin(19200);? Wire.begin();? ? ? ? ? ? ? ? ? ? ? // Initialize comunication? Wire.beginTransmission(MPU);? ? ? // Start communication with MPU6050 // MPU=0x68? Wire.write(0x6B);? ? ? ? ? ? ? ? ? // Talk to the register 6B? Wire.write(0x00);? ? ? ? ? ? ? ? ? // Make reset - place a 0 into the 6B register? Wire.endTransmission(true);? ? ? ? //end the transmission? /*

? // Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)

? Wire.beginTransmission(MPU);

? Wire.write(0x1C);? ? ? ? ? ? ? ? ? //Talk to the ACCEL_CONFIG register (1C hex)

? Wire.write(0x10);? ? ? ? ? ? ? ? ? //Set the register bits as 00010000 (+/- 8g full scale range)

? Wire.endTransmission(true);

? // Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)

? Wire.beginTransmission(MPU);

? Wire.write(0x1B);? ? ? ? ? ? ? ? ? // Talk to the GYRO_CONFIG register (1B hex)

? Wire.write(0x10);? ? ? ? ? ? ? ? ? // Set the register bits as 00010000 (1000deg/s full scale)

? Wire.endTransmission(true);

? delay(20);

? */? // Call this function if you need to get the IMU error values for your module? calculate_IMU_error();? delay(20);}void loop() {? // === Read acceleromter data === //? Wire.beginTransmission(MPU);? Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)? Wire.endTransmission(false);? Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers? //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet? AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value? AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value? AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value? // Calculating Roll and Pitch from the accelerometer data? accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details? accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)? // === Read gyroscope data === //? previousTime = currentTime;? ? ? ? // Previous time is stored before the actual time read? currentTime = millis();? ? ? ? ? ? // Current time actual time read? elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds? Wire.beginTransmission(MPU);? Wire.write(0x43); // Gyro data first register address 0x43? Wire.endTransmission(false);? Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers? GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet? GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;? GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;? // Correct the outputs with the calculated error values? GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)? GyroY = GyroY - 2; // GyroErrorY ~(2)? GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)? // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees? gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg? gyroAngleY = gyroAngleY + GyroY * elapsedTime;? yaw =? yaw + GyroZ * elapsedTime;? // Complementary filter - combine acceleromter and gyro angle values? roll = 0.96 * gyroAngleX + 0.04 * accAngleX;? pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;

? // Print the values on the serial monitor? Serial.print(roll);? Serial.print("/");? Serial.print(pitch);? Serial.print("/");? Serial.println(yaw);}void calculate_IMU_error() {? // We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor.? // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values? // Read accelerometer values 200 times? while (c < 200) {? ? Wire.beginTransmission(MPU);? ? Wire.write(0x3B);? ? Wire.endTransmission(false);? ? Wire.requestFrom(MPU, 6, true);? ? AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;? ? AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;? ? AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;? ? // Sum all readings? ? AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));? ? AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));? ? c++;? }? //Divide the sum by 200 to get the error value? AccErrorX = AccErrorX / 200;? AccErrorY = AccErrorY / 200;? c = 0;? // Read gyro values 200 times? while (c < 200) {? ? Wire.beginTransmission(MPU);? ? Wire.write(0x43);? ? Wire.endTransmission(false);? ? Wire.requestFrom(MPU, 6, true);? ? GyroX = Wire.read() << 8 | Wire.read();? ? GyroY = Wire.read() << 8 | Wire.read();? ? GyroZ = Wire.read() << 8 | Wire.read();? ? // Sum all readings? ? GyroErrorX = GyroErrorX + (GyroX / 131.0);? ? GyroErrorY = GyroErrorY + (GyroY / 131.0);? ? GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);? ? c++;? }? //Divide the sum by 200 to get the error value? GyroErrorX = GyroErrorX / 200;? GyroErrorY = GyroErrorY / 200;? GyroErrorZ = GyroErrorZ / 200;? // Print the error values on the Serial Monitor? Serial.print("AccErrorX: ");? Serial.println(AccErrorX);? Serial.print("AccErrorY: ");? Serial.println(AccErrorY);? Serial.print("GyroErrorX: ");? Serial.println(GyroErrorX);? Serial.print("GyroErrorY: ");? Serial.println(GyroErrorY);? Serial.print("GyroErrorZ: ");? Serial.println(GyroErrorZ);}復(fù)制代碼

代碼描述:首先我們需要包含用于I2C通信的Wire.h庫淘正,并定義一些存儲數(shù)據(jù)所需的變量摆马。

在setup()函數(shù)部分,我們需要初始化wire庫并通過電源管理寄存器復(fù)位傳感器鸿吆。 為此囤采,我們需要查看傳感器的數(shù)據(jù)手冊,從中我們可以看到寄存器地址惩淳。

MPU6050電源管理寄存器0x6B

此外蕉毯,如果需要,我們可以使用配置寄存器為加速度計和陀螺儀選擇滿量程范圍。 對于這個例子代虾,我們將使用加速度計的默認(rèn)±2g范圍和陀螺儀的250度/秒范圍进肯。

// Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)? Wire.beginTransmission(MPU);? Wire.write(0x1C);? ? ? ? ? ? ? ? ? //Talk to the ACCEL_CONFIG register (1C hex)? Wire.write(0x10);? ? ? ? ? ? ? ? ? //Set the register bits as 00010000 (+/- 8g full scale range)? Wire.endTransmission(true);? // Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)? Wire.beginTransmission(MPU);? Wire.write(0x1B);? ? ? ? ? ? ? ? ? // Talk to the GYRO_CONFIG register (1B hex)? Wire.write(0x10);? ? ? ? ? ? ? ? ? // Set the register bits as 00010000 (1000deg/s full scale)? Wire.endTransmission(true);? */復(fù)制代碼

在loop()函數(shù)部分,我們首先讀取加速度計的數(shù)據(jù)棉磨。 每個軸的數(shù)據(jù)存儲在兩個字節(jié)或寄存器中江掩,我們可以從傳感器的數(shù)據(jù)手冊中看到這些寄存器的地址。

MPU6050 imu加速度計數(shù)據(jù)寄存器

為了全部讀取它們含蓉,我們從第一個寄存器開始频敛,然后使用requiestFrom()函數(shù),我們請求讀取X馅扣、Y和Z軸的所有6個寄存器斟赚。 然后我們從每個寄存器讀取數(shù)據(jù),并且由于輸出是二進(jìn)制補(bǔ)碼差油,我們將它們相應(yīng)地組合以獲得正確的值拗军。

// === Read acceleromter data === //? Wire.beginTransmission(MPU);? Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)? Wire.endTransmission(false);? Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers? //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet? AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value 16384.0就是靈敏度如下圖? AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value? AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value

為了獲得-1g到+ 1g的輸出值,適合計算角度蓄喇,我們將輸出除以先前選擇的靈敏度发侵。

mpu6050加速度計靈敏度滿量程范圍

最后,使用這兩個公式妆偏,我們從加速度計數(shù)據(jù)計算滾轉(zhuǎn)角和俯仰角刃鳄。

? accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details? accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)

接下來,使用相同的方法我們得到陀螺儀數(shù)據(jù)钱骂。

我們讀取了六個陀螺儀寄存器叔锐,適當(dāng)?shù)亟M合它們的數(shù)據(jù)并將其除以先前選擇的靈敏度,以便以每秒的度數(shù)獲得輸出见秽。

// === Read gyroscope data === //? previousTime = currentTime;? ? ? ? // Previous time is stored before the actual time read? currentTime = millis();? ? ? ? ? ? // Current time actual time read? elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds? Wire.beginTransmission(MPU);? Wire.write(0x43); // Gyro data first register address 0x43? Wire.endTransmission(false);? Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers? GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet? GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;? GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;

在這里你可以注意到我用一些小的計算誤差值來校正輸出值愉烙,我將在接下來解釋它們是如何得到它們的。 因此解取,當(dāng)輸出以度/秒為單位時步责,現(xiàn)在我們需要將它們與時間相乘以得到度數(shù)。 使用millis()函數(shù)在每次讀取迭代之前捕獲時間值禀苦。

// Correct the outputs with the calculated error values? GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)? GyroY = GyroY - 2; // GyroErrorY ~(2)? GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)? // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees? gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg? gyroAngleY = gyroAngleY + GyroY * elapsedTime;? yaw =? yaw + GyroZ * elapsedTime;

最后蔓肯,我們使用互補(bǔ)濾波器融合加速度計和陀螺儀數(shù)據(jù)。在這里伦忠,我們采用96%的陀螺儀數(shù)據(jù)省核,因為它非常準(zhǔn)確,不會受到外力的影響昆码。陀螺儀的缺點是存在漂移气忠,或者隨著時間的推移在輸出中引入誤差邻储。因此,從長遠(yuǎn)來看旧噪,我們使用來自加速度計的數(shù)據(jù)吨娜,本例為4%,足以消除陀螺儀的漂移誤差淘钟。

// Complementary filter - combine acceleromter and gyro angle values? roll = 0.96 * gyroAngleX + 0.04 * accAngleX;? pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;

但是宦赠,由于我們無法從加速度計數(shù)據(jù)計算偏航,我們無法在其上實現(xiàn)互補(bǔ)濾波器米母。

在我們看一下結(jié)果之前勾扭,讓我快速解釋一下如何獲得糾錯值。為了計算這些錯誤铁瞒,我們可以在傳感器處于平坦靜止位置時調(diào)用calculate_IMU_error()自定義函數(shù)妙色。在這里,我們?yōu)樗休敵鲎隽?00個讀數(shù)慧耍,我們將它們相加并將它們除以200身辨。由于我們將傳感器保持在平坦靜止位置,因此預(yù)期輸出值應(yīng)為0芍碧。因此煌珊,通過此計算,我們可以得到傳感器的平均誤差泌豆。

void calculate_IMU_error() {? // We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor.? // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values? // Read accelerometer values 200 times? while (c < 200) {? ? Wire.beginTransmission(MPU);? ? Wire.write(0x3B);? ? Wire.endTransmission(false);? ? Wire.requestFrom(MPU, 6, true);? ? AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;? ? AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;? ? AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;? ? // Sum all readings? ? AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));? ? AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));? ? c++;? }? //Divide the sum by 200 to get the error value? AccErrorX = AccErrorX / 200;? AccErrorY = AccErrorY / 200;? c = 0;? // Read gyro values 200 times? while (c < 200) {? ? Wire.beginTransmission(MPU);? ? Wire.write(0x43);? ? Wire.endTransmission(false);? ? Wire.requestFrom(MPU, 6, true);? ? GyroX = Wire.read() << 8 | Wire.read();? ? GyroY = Wire.read() << 8 | Wire.read();? ? GyroZ = Wire.read() << 8 | Wire.read();? ? // Sum all readings? ? GyroErrorX = GyroErrorX + (GyroX / 131.0);? ? GyroErrorY = GyroErrorY + (GyroY / 131.0);? ? GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);? ? c++;? }? //Divide the sum by 200 to get the error value? GyroErrorX = GyroErrorX / 200;? GyroErrorY = GyroErrorY / 200;? GyroErrorZ = GyroErrorZ / 200;? // Print the error values on the Serial Monitor? Serial.print("AccErrorX: ");? Serial.println(AccErrorX);? Serial.print("AccErrorY: ");? Serial.println(AccErrorY);? Serial.print("GyroErrorX: ");? Serial.println(GyroErrorX);? Serial.print("GyroErrorY: ");? Serial.println(GyroErrorY);? Serial.print("GyroErrorZ: ");? Serial.println(GyroErrorZ);}

輸出結(jié)果

我們只需在串行監(jiān)視器上打印這些值定庵,一旦我們知道它們,我們就可以在前面所示的代碼中實現(xiàn)它們踪危,用于滾動和俯仰計算洗贰,以及3個陀螺儀輸出。

最后陨倡,使用Serial.print函數(shù),我們可以在串行監(jiān)視器上打印Roll许布、Pitch和Yaw值兴革,看看傳感器是否正常工作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜜唾,一起剝皮案震驚了整個濱河市杂曲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌袁余,老刑警劉巖擎勘,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颖榜,居然都是意外死亡棚饵,警方通過查閱死者的電腦和手機(jī)煤裙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來噪漾,“玉大人硼砰,你說我怎么就攤上這事⌒琅穑” “怎么了题翰?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長诈胜。 經(jīng)常有香客問我豹障,道長,這世上最難降的妖魔是什么焦匈? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任血公,我火速辦了婚禮,結(jié)果婚禮上括授,老公的妹妹穿的比我還像新娘坞笙。我一直安慰自己,他們只是感情好荚虚,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布薛夜。 她就那樣靜靜地躺著,像睡著了一般版述。 火紅的嫁衣襯著肌膚如雪梯澜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天渴析,我揣著相機(jī)與錄音晚伙,去河邊找鬼。 笑死俭茧,一個胖子當(dāng)著我的面吹牛咆疗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播母债,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼午磁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毡们?” 一聲冷哼從身側(cè)響起迅皇,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衙熔,沒想到半個月后登颓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡红氯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年框咙,在試婚紗的時候發(fā)現(xiàn)自己被綠了咕痛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡扁耐,死狀恐怖暇检,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婉称,我是刑警寧澤块仆,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站王暗,受9級特大地震影響悔据,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俗壹,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一科汗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绷雏,春花似錦头滔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至期吓,卻和暖如春早歇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背讨勤。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工箭跳, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人潭千。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓谱姓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親刨晴。 傳聞我的和親對象是個殘疾皇子逝段,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容