搜索
bottom↓
回复: 0

《DNK210使用指南 -SDK版 V1.0》第十八章 六轴传感器

[复制链接]

出0入234汤圆

发表于 前天 11:10 | 显示全部楼层 |阅读模式
2.jpg
1)实验平台:正点原子DNK210开发板
2)购买链接:https://detail.tmall.com/item.htm?id=782801398750
3)全套实验源码+手册+视频下载地址:http://openedv.com/thread-348335-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子手把手教你学DNK210快速入门视频教程:https://www.bilibili.com/video/BV1kD421G7fu
6)正点原子FPGA交流群:132780729
1.png
3.png

第十八章 六轴传感器——姿态解算实验


       在上一章节中,介绍了板载六轴传感器的使用,仅需简单的使用提供的驱动,便可从六轴传感器上获取温度、加速度、陀螺仪等数据,本章将继续且更加深入地介绍板载六轴传感器的使用。通过本章地学习,读者将学习到通过板载六轴传感器获取加速度和角速度数据后进行姿态解算的使用。
       本章分为如下几个小节:
       18.1 SH3001驱动介绍及使用方法
       18.2 硬件设计
       18.3 程序设计
       18.4 运行验证

       18.1 SH3001驱动介绍及使用方法
       有关SH3001驱动的介绍及使用方法,请见第17.1小节《SH3001驱动介绍及使用方法》。

       18.2 硬件设计

       18.2.1 例程功能

       1. 初始化SH3001等外设后,在死循环里面不停读取:温度传感器、加速度传感器和陀螺仪,以及姿态解算后的欧拉角等数据,通过串口上报给上位机(温度不上报),利用上位机软件(ANO_TC匿名科创地面站v4.exe) ,可以实时显示SH3001的传感器状态曲线,并显示3D姿态。同时,在LCD模块上面显示温度和欧拉角等信息。

       18.2.2 硬件资源

       1. SH3001
              IIC_SCL - IO22
              IIC_SDA - IO23

       18.2.3 原理图
       本章实验内容,需要使用到板载的SH3001芯片,正点原子DNK210开发板上的SH3001芯片连接原理图,如下图所示:

第十八章 六轴传感器590.png
图18.2.3.1 SH3001连接原理图

       18.3 程序设计

       18.3.1 姿态解算库介绍
       有关SH3001驱动的介绍,请见第17.1小节《SH3001驱动介绍及使用方法》。
       我们来介绍一下如何使用这个姿态库,需要调用imu_get_eulerian_angle这个函数来获取欧拉角,然后将读取到的数据用一些变量传入姿态算法库。本次实验我们直接使用sh3001_get_imu_compdata函数读取补偿后的加速度和陀螺仪数据,然后调用imu_data_calibration函数对数据进行校准,再调用imu_get_eulerian_angles函数就能得到姿态解算后的欧拉角:俯仰角(pitch)、横滚角(roll)和航向角(yaw)。
       源码包括包括两个文件:imu.c和imu.h,imu.h文件只包含了函数的声明和两个结构体,我们这里不多介绍,下面的们介绍imu.c文件的内容。
  1. /**
  2. * @brief       数据转换
  3. * @note        对加速度数据做一阶低通滤波(参考匿名),对gyro转成弧度每秒(2000dps)
  4. * @param       gx, gy, gz  : 3轴陀螺仪数据指针
  5. * @param       ax, ay, az  : 3轴加速度数据指针
  6. * @retval      无
  7. */
  8. static void imu_data_transform(float *gx, float *gy, float *gz, float *ax, float *ay, float *az)
  9. {
  10.     static double lastax = 0;
  11.     static double lastay = 0;
  12.     static double lastaz = 0;

  13.     *ax = *ax * IMU_NEW_WEIGHT + lastax * IMU_OLD_WEIGHT;
  14.     *ay = *ay * IMU_NEW_WEIGHT + lastay * IMU_OLD_WEIGHT;
  15.     *az = *az * IMU_NEW_WEIGHT + lastaz * IMU_OLD_WEIGHT;

  16.     lastax = *ax;
  17.     lastay = *ay;
  18.     lastaz = *az;
  19.      
  20.     *gx = *gx * IMU_M_PI / 180 / 16.4f;
  21.     *gy = *gy * IMU_M_PI / 180 / 16.4f;
  22.     *gz = *gz * IMU_M_PI / 180 / 16.4f;
  23. }
复制代码
       imu_data_transform函数用来数据转换,对校正后的原始数据ax(ay、az)进行低通滤波,对gx(gy、gz)转换成弧度每秒(2000°/s)。
  1. /**
  2. * @brief       姿态解算融合, 核心算法
  3. * @note        使用的是互补滤波算法,没有使用Kalman滤波算法
  4. *              尽量保证该函数的调用频率为: IMU_DELTA_T , 否则YAW会相应的偏大/偏小
  5. * @param       gx, gy, gz  : 3轴陀螺仪数据
  6. * @param       ax, ay, az  : 3轴加速度数据
  7. * @retval      无
  8. */
  9. static void imu_ahrsupdate_nomagnetic(float gx, float gy, float gz, float ax, float ay, float az)
  10. {
  11.     static float i_ex, i_ey, i_ez;    /* 误差积分 */

  12.     float half_t = 0.5f * IMU_DELTA_T;
  13.     float vx, vy, vz;      /* 当前的机体坐标系上的重力单位向量 */
  14.     float ex, ey, ez;      /* 四元数计算值与加速度计测量值的误差 */
  15.     float q0 = g_q_info.q0;
  16.     float q1 = g_q_info.q1;
  17.     float q2 = g_q_info.q2;
  18.     float q3 = g_q_info.q3;
  19.     float q0q0 = q0 * q0;
  20.     float q0q1 = q0 * q1;
  21.     float q0q2 = q0 * q2;
  22.    // float q0q3 = q0 * q3;
  23.     float q1q1 = q1 * q1;
  24.    // float q1q2 = q1 * q2;
  25.     float q1q3 = q1 * q3;
  26.     float q2q2 = q2 * q2;
  27.     float q2q3 = q2 * q3;
  28.     float q3q3 = q3 * q3;
  29.     float delta_2 = 0;

  30.     /* 对加速度数据进行归一化 得到单位加速度 */
  31.     float norm = imu_inv_sqrt(ax * ax + ay * ay + az * az);
  32.     ax = ax * norm;
  33.     ay = ay * norm;
  34.     az = az * norm;
  35.     vx = 2 * (q1q3 - q0q2);
  36.     vy = 2 * (q0q1 + q2q3);
  37.     vz = q0q0 - q1q1 - q2q2 + q3q3;

  38.     ex = ay * vz - az * vy;
  39.     ey = az * vx - ax * vz;
  40.     ez = ax * vy - ay * vx;

  41.     /* 用差乘误差来做PI修正陀螺仪零偏,
  42.      * 通过调节 g_param_kp,g_param_ki 两个参数,
  43.      * 可以控制加速度计修正陀螺仪积分姿态的速度。*/
  44.     i_ex += IMU_DELTA_T * ex;   /* integral error scaled by Ki */
  45.     i_ey += IMU_DELTA_T * ey;
  46.     i_ez += IMU_DELTA_T * ez;

  47.     gx = gx + g_param_kp * ex + g_param_ki * i_ex;
  48.     gy = gy + g_param_kp * ey + g_param_ki * i_ey;
  49.     gz = gz + g_param_kp * ez + g_param_ki * i_ez;


  50.     /*数据修正完成,下面是四元数微分方程*/

  51.     /* 四元数微分方程,其中half_t为测量周期的1/4,gx gy gz为陀螺仪角速度,
  52.        以下都是已知量,这里使用了一阶龙哥库塔求解四元数微分方程 */
  53.    /* q0 = q0 + (-q1 * gx - q2 * gy - q3 * gz) * half_t;
  54.       q1 = q1 + ( q0 * gx + q2 * gz - q3 * gy) * half_t;
  55.       q2 = q2 + ( q0 * gy - q1 * gz + q3 * gx) * half_t;
  56.       q3 = q3 + ( q0 * gz + q1 * gy - q2 * gx) * half_t; */
  57.     delta_2 = (2 * half_t * gx) * (2 * half_t * gx) + (2 * half_t * gy) * (2 * half_t * gy) + (2 * half_t * gz) * (2 * half_t * gz);

  58.     /* 整合四元数率    四元数微分方程  四元数更新算法,二阶毕卡法 */
  59.     q0 = (1 - delta_2 / 8) * q0 + (-q1 * gx - q2 * gy - q3 * gz) * half_t;
  60.     q1 = (1 - delta_2 / 8) * q1 + (q0 * gx + q2 * gz - q3 * gy) * half_t;
  61.     q2 = (1 - delta_2 / 8) * q2 + (q0 * gy - q1 * gz + q3 * gx) * half_t;
  62.     q3 = (1 - delta_2 / 8) * q3 + (q0 * gz + q1 * gy - q2 * gx) * half_t;

  63.     /* normalise quaternion */
  64.     norm = imu_inv_sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
  65.     g_q_info.q0 = q0 * norm;
  66.     g_q_info.q1 = q1 * norm;
  67.     g_q_info.q2 = q2 * norm;
  68.     g_q_info.q3 = q3 * norm;
  69. }
复制代码
       imu_ahrsupdate_nomagnetic函数是姿态解算融合,是crazepony的核心算法,使用了互补滤波算法。在姿态解算中运用了四元数来计算。首先对加速度数据进行归一化,得到单位加速度,再修正陀螺仪的偏差。修正完成后,使用二阶毕卡法更新四元数。
  1. /**
  2. * @brief       得到姿态解算后的欧拉角
  3. * @param       gx, gy, gz  : 3轴陀螺仪数据
  4. * @param       ax, ay, az  : 3轴加速度数据
  5. * @retval      返回值 : 欧拉角
  6. */
  7. eulerian_angles_t imu_get_eulerian_angles(float gx, float gy, float gz, float ax, float ay, float az)
  8. {
  9.     eulerian_angles_t eulerangle;

  10.     imu_data_transform(&gx, &gy, &gz, &ax, &ay, &az);       /* 数据转换 */
  11.     imu_ahrsupdate_nomagnetic(gx, gy, gz, ax, ay, az);      /* 姿态解算 */
  12.    
  13.     float q0 = g_q_info.q0;
  14.     float q1 = g_q_info.q1;
  15.     float q2 = g_q_info.q2;
  16.     float q3 = g_q_info.q3;

  17.     eulerangle.pitch = - asin(-2 * q1 * q3 + 2 * q0 * q2) * 190 / IMU_M_PI;
  18.     eulerangle.roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2 * q2 + 1) * 180 / IMU_M_PI;
  19.     eulerangle.yaw = - atan2(2 * q1 * q2 + 2 * q0 * q3, -2 * q2 * q2 - 2 * q3 * q3 + 1) * 180 / IMU_M_PI;

  20.     /* 可以不用作姿态限度的限制 */
  21. //    if (eulerangle.roll > 90 || eulerangle.roll < -90)
  22. //    {
  23. //        if (eulerangle.pitch > 0)
  24. //        {
  25. //            eulerangle.pitch = 180 - eulerangle.pitch;
  26. //        }

  27. //        if (eulerangle.pitch < 0)
  28. //        {
  29. //            eulerangle.pitch = -(180 + eulerangle.pitch);
  30. //        }
  31. //    }

  32.     if (eulerangle.yaw > 180)
  33.     {
  34.         eulerangle.yaw -= 360;
  35.     }
  36.     else if (eulerangle.yaw < -180)
  37.     {
  38.         eulerangle.yaw += 360;
  39.     }
  40.    
  41.     return eulerangle;
  42. }
复制代码
       imu_get_eulerian_angles函数把四元数转换成欧拉角,并且对欧拉角的角度姿态范围做了限制。

       18.3.2 main.c代码
       main.c中的代码如下所示:
  1. /**
  2. * @brief       显示角度
  3. *  @note       以图片显示的方式更快  
  4. * @param       x, y : 坐标
  5. * @param       title: 标题
  6. * @param       angle: 角度
  7. * @retval      无
  8. */
  9. void user_show_data(uint16_t x, uint16_t y, char * title, float angle)
  10. {
  11.     char buf[15];

  12.     sprintf(buf,"%s%3.1fC", title, angle);          /* 格式化输出 */
  13.     draw_fill_rectangle_image(lcd_gram, 320, x, y, x + 120, y + 16, WHITE);
  14.     draw_string_rgb565_image(lcd_gram, 320, 240, x, y, buf, BLUE);

  15. // lcd_draw_fill_rectangle(x, y, x + 120, y + 16, WHITE);         
  16. /* 清除上次数据(最多显示15个字符,15*8=120) */
  17.     // lcd_draw_string(x, y, buf, BLUE);  /* 显示字符串 */
  18. }

  19. /**
  20. * @brief       USB串口发送1个字符
  21. * @param       c:要发送的字符
  22. * @retval      无
  23. */
  24. void usart1_send_char(const uint8_t *c, size_t len)
  25. {
  26.     uarths_send_data(c, len);
  27. }

  28. /**
  29. * @brief       传送数据给 ANO_TC匿名科创地面站v4.exe
  30. * @param       fun:功能字. 0XA0~0XAF
  31. * @param       data:数据缓存区,最多28字节!!
  32. * @param       len:data区有效数据个数
  33. * @retval      无
  34. */
  35. void usart1_niming_report(uint8_t fun, uint8_t *data, uint8_t len)
  36. {
  37.     uint8_t send_buf[32];
  38.     uint8_t i;

  39.     if (len > 28)
  40.     {
  41.         return;    /* 最多28字节数据 */
  42.     }

  43.     send_buf[len + 4] = 0;  /* 校验数置零 */
  44.     send_buf[0] = 0XAA;     /* 帧头 */
  45.     send_buf[1] = 0XAA;     /* 帧头 */
  46.     send_buf[2] = fun;      /* 功能字 */
  47.     send_buf[3] = len;      /* 数据长度 */

  48.     for (i = 0; i < len; i++)
  49.     {
  50.         send_buf[4 + i] = data;             /* 复制数据 */
  51.     }
  52.    
  53.     for (i = 0; i < len + 4; i++)
  54.     {
  55. <span style="font-style: italic;"><span style="font-style: normal;">        send_buf[len + 4] += send_buf;      /* 计算校验和 */
  56.     }
  57.    
  58.     usart1_send_char((const uint8_t *)send_buf, (len + 5));  /* 发送数据到串口 */
  59. }

  60. /**
  61. * @brief       发送加速度传感器数据和陀螺仪数据
  62. * @param       aacx,aacy,aacz:x,y,z三个方向上面的加速度值
  63. * @param       gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值
  64. * @retval      无
  65. */
  66. void sh3001_send_data(short aacx, short aacy, short aacz, short gyrox, short gyroy, short gyroz)
  67. {
  68.     uint8_t tbuf[18];
  69.     tbuf[0] = (aacx >> 8) & 0XFF;
  70.     tbuf[1] = aacx & 0XFF;
  71.     tbuf[2] = (aacy >> 8) & 0XFF;
  72.     tbuf[3] = aacy & 0XFF;
  73.     tbuf[4] = (aacz >> 8) & 0XFF;
  74.     tbuf[5] = aacz & 0XFF;
  75.     tbuf[6] = (gyrox >> 8) & 0XFF;
  76.     tbuf[7] = gyrox & 0XFF;
  77.     tbuf[8] = (gyroy >> 8) & 0XFF;
  78.     tbuf[9] = gyroy & 0XFF;
  79.     tbuf[10] = (gyroz >> 8) & 0XFF;
  80.     tbuf[11] = gyroz & 0XFF;
  81.     tbuf[12]=0;  /* 因为开启MPL后,无法直接读取磁力计数据,所以这里直接屏蔽掉.用0替代. */
  82.     tbuf[13]=0;
  83.     tbuf[14]=0;
  84.     tbuf[15]=0;
  85.     tbuf[16]=0;
  86.     tbuf[17]=0;
  87.     usart1_niming_report(0X02, tbuf, 18);             /* 自定义帧,0X02 */
  88. }

  89. /**
  90. * @brief       通过USB串口上报结算后的姿态数据给电脑
  91. * @param       roll:横滚角.单位0.1度。 -9000 -> 9000 对应 -90.00  ->  90.00度
  92. * @param       pitch:俯仰角.单位 0.1度。-18000 - 18000 对应 -180.00 -> 180.00 度
  93. * @param       yaw:航向角.单位为0.1度 -18000 -> 18000  对应 -180.00 -> 180.00 度
  94. * @param       prs:气压计高度,单位:cm
  95. * @param       fly_mode:飞行模式
  96. * @param       armed:锁定状态
  97. * @retval      无
  98. */
  99. void usart1_report_imu(short roll,short pitch,short yaw,int prs, uint8_t fly_mode, uint8_t armed)
  100. {
  101.     uint8_t tbuf[12];
  102.   
  103.     tbuf[0] = (roll >> 8) & 0XFF;
  104.     tbuf[1] = roll & 0XFF;
  105.     tbuf[2] = (pitch >> 8) & 0XFF;
  106.     tbuf[3] = pitch & 0XFF;
  107.     tbuf[4] = (yaw >> 8) & 0XFF;
  108.     tbuf[5] = yaw & 0XFF;
  109.     tbuf[6] = (prs >> 24) & 0XFF;
  110.     tbuf[7] = (prs >> 16) & 0XFF;
  111.     tbuf[8] = (prs >> 8) & 0XFF;
  112.     tbuf[9] = prs & 0XFF;
  113.     tbuf[10] = fly_mode;
  114.     tbuf[11] = armed;
  115.     usart1_niming_report(0X01, tbuf, 12); /* 状态帧,0X01 */
  116. }

  117. /**
  118. * @brief       硬件初始化,绑定GPIO口
  119. * @param       无
  120. * @retval      无
  121. */
  122. void hardware_init(void)
  123. {
  124.     fpioa_set_function(PIN_UART_USB_RX, FUNC_UART_USB_RX);
  125.     fpioa_set_function(PIN_UART_USB_TX, FUNC_UART_USB_TX);
  126. }

  127. int main(void)
  128. {
  129.     uint8_t t = 0;
  130.     float temperature;                          /* 温度值 */
  131.     short acc_data[3];                          /* 加速度传感器原始数据 */
  132.     short gyro_data[3];                         /* 陀螺仪原始数据 */
  133.     eulerian_angles_t e_angles;

  134.     sysctl_pll_set_freq(SYSCTL_PLL0, 800000000);
  135.     sysctl_pll_set_freq(SYSCTL_PLL1, 400000000);
  136.     sysctl_pll_set_freq(SYSCTL_PLL2, 45158400);
  137.     sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
  138.     sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
  139.     sysctl_set_spi0_dvp_data(1);

  140.     lcd_init();
  141.     lcd_set_direction(DIR_YX_LRUD);

  142.     // 硬件引脚初始化
  143.     hardware_init();

  144.     uarths_init();
  145.     uarths_config(500000,UARTHS_STOP_1);

  146.     /* 初始化 IMU */
  147.     while (sh3001_init())     /* 检测不到SH3001 */
  148.     {
  149.         msleep(10);
  150.     }
  151.     msleep(500);

  152.     imu_init();   
  153.     for (size_t i = 0; i < 320 * 240; i++)
  154.     {
  155.         lcd_gram</span><span style="font-style: normal;"> = 0xFFFF;
  156.     }
  157.                               
  158.     while (1)
  159.     {
  160.         usleep(3100);    /* 调节延时,矫正YAW角 */
  161.         t++;
  162.         
  163.         sh3001_get_imu_compdata(acc_data, gyro_data);

  164.         /* 数据校准 */
  165.         imu_data_calibration(&gyro_data[0], &gyro_data[1], &gyro_data[2],
  166.                             &acc_data[0],  &acc_data[1],  &acc_data[2]);

  167.         /* 获取欧拉角 */
  168.         e_angles = imu_get_eulerian_angles(gyro_data[0], gyro_data[1], gyro_data[2],
  169.                                         acc_data[0],  acc_data[1],  acc_data[2]);

  170.         sh3001_send_data(acc_data[0], acc_data[1], acc_data[2], gyro_data[0], gyro_data[1], gyro_data[2]);  /* 发送加速度+陀螺仪原始数据 */
  171.         usart1_report_imu((int)(e_angles.roll * 100), (int)(e_angles.pitch * 100), (int)(e_angles.yaw * 100), 0, 0, 0);

  172.         if (t == 50)
  173.         {        
  174.             temperature = sh3001_get_tempdata();    /* 读取温度值 */
  175.             // printf("temp=%.2f\n", temperature);
  176.             user_show_data(30, 30, "Temp :", temperature);
  177.             user_show_data(30, 50, "Pitch:", e_angles.pitch);
  178.             user_show_data(30, 70, "Roll :", e_angles.roll);
  179.             user_show_data(30, 90, "Yaw  :", e_angles.yaw);
  180.             
  181.             lcd_draw_picture(0, 0, 320, 240, (uint16_t *)lcd_gram);
  182.             t = 0;
  183.         }
  184.     }
  185. }</span></span>
复制代码
       此部分代码除了main函数,还有几个函数,用于上报数据给上位机软件,可以通过上位机软件显示六轴传感器波形,以及3D姿态显示,有助于更好的调试SH3001。上位机软件使用ANO_TC匿名科创地面站v4.exe,该软件在:A盘软件资料软件匿名科创地面站文件夹里可以找到,该软件的使用方法,见该文件夹下的:飞控通信协议v1.3-0720.pdf,这里我们不做介绍。其中,usart1_niming_report函数用于将数据打包、计算校验和,然后上报给匿名地面站上位机软件。sh3001_send_data函数用于上报加速度和陀螺仪的原始数据,可用于波形显示传感器数据,通过传感器帧(0X02)发送。而usart1_report_imu函数,则用于上报飞控显示帧,可以实时3D显示SH3001的姿态,传感器数据等,通过状态帧(0X01)发送。
       下面我们来看main函数,利用上位机软件(ANO_TC匿名科创地面站v4.exe),可以实时显示SH3001的传感器状态曲线,并显示3D姿态。同时,在LCD模块上面显示温度和欧拉角等信息。

       18.4 运行验证
       将DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中,可以看到LCD显示的内容如图所示:

第十八章 六轴传感器12391.png
图18.4.1  程序运行效果

       屏幕显示了SH3001的温度、俯仰角(Pitch)、横滚角(Roll)和航向角(Yaw)的数值。然后,我们可以晃动开发板,看看各角度的变化。
       另外,数据会通过USB串口实时上报,我们可以打开:ANO_TC匿名科创地面站v4.exe这个软件,接收DNK210上传的数据,从而图形化显示传感器数据以及飞行姿态,如图18.4.2和18.4.3所示:

第十八章 六轴传感器12581.png
图18.4.2 传感器数据波形显示

第十八章 六轴传感器12601.png
图18.4.3 飞控状态显示

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-16 16:05

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表