Android是智能手机等便携式设备最受欢迎的操作系统(OS)之一。它为各种传感器提供了标准API包括加速度计速度计。加速度计的标准API坐标系统定义了原始加速度数据。用户必须将从传感器中读取的原始数据转换为标准单元,并使其符合系统定义的坐标方向。本文介绍了Android坐标系统是如何定义的,以及如何在中间Android在系统的驱动代码中转换三轴加速度计数据的方向和坐标。本文讨论的示例代码基于飞思卡尔Android2.2和2.3驱动程序,飞思卡尔的加速度计MMA8452Q以加速传感器为例。
智能手机或便携设备应具备Wi-Fi还有互联网功能,可以运行应用软件等诸多特点,肯定会有内置传感器。高端智能手机可集成接近传感器、环境光传感器、3轴加速度计、磁力计等传感器。Android2.3添加了一些支持各种新传感器的传感器API,包括陀螺仪、旋转向量、线性加速度、重力和气压传感器。这些新型传感器可用于应用软件的组合,实现高精度的高级运动检测功能。
3轴加速度计或低g值传感器AndroidAPI支持特定坐标系统的支持传感器之一可以为应用程序提供标准的接口数据。坐标空间的定义与手机屏幕的默认方向有关,如图1所示。
在Android坐标系统中,坐标原点位于屏幕左下角,X轴水平指向右侧,Y轴垂直指向顶部,Z轴向屏幕前方。屏幕后面的坐标在系统中具有负Z轴值。
Android加速度计数据定义为:
Sensor.TYPE_ACCELEROMETER
所有数值都采用SI标准单位(m/s2)测量手机的加速度值,减去重力加速度重量。
values[0]:x减去轴上的加速度值Gx
values[1]:y减去轴上的加速度值Gy
values[2]:z减去轴上的加速度值Gz
例如,当设备平放在桌子上,并将其推向左向右移动时,x轴加速度值为正。当设备平放在桌子上时,加速度值为 9.81这是设备的加速度值(0m/s2)减去重力加速度值(-9.81m/s2)得到的。
当设备平放在桌子上并加速时Am/s当2朝向天空时,加速度值等于A 9.用设备加速度值( Am/s减去重力加速度值(-9).81m/s2)得到的。
表1列出了与设备各位置对应的传感器的加速度读数。用户可以使用下表检查加速度计的方向是否与系统坐标一致。
表1. 各轴在不同位置的加速度值
位置
x
y
z
朝上:
0
9.81m/s2
0
朝左:
9.81m/s2
0
0
朝下:
0
-9.81m/s2
0
朝右:
-9.81m/s2
0
0
正面朝上:
0
0
9.81m/s2
背面朝上:
0
0
-9.81m/s2
当通过加速度传感器读取3轴加速度值时,需要假设传感器的3轴方向与系统坐标一致。但在实际产品中,不同的传感器芯片或安装方向可能会使用,因此数据方向会有所不同。图2显示了飞思卡尔MMA8452Q三轴加速度传感器的方向定义。
在图2中,我们可以看到,当安装芯片时,引脚1必须位于右下角(PD),并安装在PCB前面,这样才能和Android默认位置与坐标系统一致。安装后,用户可以确定数据方向与系统坐标定义一致。在任何其他情况下,数据都不能与系统定义完全一致,因此需要更改数据方向和坐标。在某些情况下,X必须与Y轴交换,或改变方向或交换X-Y轴。
判断是否需要改变方向或交换X-Y轴的方法如下:
1.朝上放置设备(UP)如表1所示。
2.从传感器中读取3轴数据。如果Y轴上的数据是±1g(±9.81m/s2)其他两个轴上的数据约为0,无需交换X-Y轴。否则,需要交换X和Y轴,请转到步骤3。
2.1.在这个位置上,如果Y轴上读取的数据是 1g( 9.81m/s2),Y轴的方向不需要改变,如果数据为负,则需要改变Y轴的方向。
2.2.朝左放置设备(LEFT)如表1所示。X轴上读取的数据应为±1g(±9.81m/s2)其他两个轴上的数据应为0左右。如果X轴上的数据为正,则不需要改变方向;否则,X轴的方向需要改变。然后,执行第四步来判断Z轴的方向。
3.设备仍然朝上(UP)从传感器中读取三个轴的数据。此时,X轴上的数据应该是±1g(±9.81m/s2)其他两个轴上的数据约为0,需要X-Y交换。
3.1.如果X轴的数据读取到这个位置 1g( 9.81m/s2)X轴的方向不需要改变;否则需要改变。
3.2.把设备放在左边(LEFT)位置如表1所示。Y轴上读取的数据应为±1g(±9.81m/s2)其他两个轴上的数据应该在0左右。如果Y轴上的数据是正的,方向不需要改变;否则需要改变。然后执行第四步来判断Z轴的方向。
4.将设备放置在正面朝上(FRONT-UP)三轴数据从传感器中读取。如果Z轴上的数据是 1g( 9.81m/s2)如果其他两个轴上的数据约为0,则Z轴的方向不需要改变;如果Z轴数据为-1g(-9.81m/s2),Z轴的方向需要改变。
在Android在系统中,传感器数据来自核心空间Linux然后由驱动读取HAL层驱动发送到API。分层结构如图3所示。Linux驱动层或在HAL转换层。
在AndroidHAL文件中改变X、Y以及Z轴的方向
在HAL在文件中,将从传感器中读取的加速度数据转换为标准单位(m/s2)。如下代码:
//conversionofaccelerationdatatoSIunits(m/s^2)
#defineCONVERT_A(GRAVITY_EARTH/LSG)
#defineCONVERT_A_X(-CONVERT_A)
#defineCONVERT_A_Y(CONVERT_A)
#defineCONVERT_A_Z(CONVERT_A)
在这个宏定义中,常量GRAVITY_EARTH是标准重力加速度值,即9.81m/s2,LSG例如,MMA正常模式下8452的读数为1024。CONVERT_A用于把从加速度传感器中读取的数据,从数字读数转换为标准重力加速度单位。
单独修改CONVERT_A_X、CONVERT_A_Y和CONVERT_A_Z,我们可以易改变X、YZ轴的方向。如果轴的方向与系统定义相反,则可以使用(-CONVERT_A)改变它的方向。如果方向一致,则使用(CONVERT_A),保持方向不变。
位于这个宏定义FSLAndroid9(Android2.2)驱动程序HAL文件sensor.c中。对于FSLAndroid10(Android2.3)你可以在那里libsensors’文件夹的HAL文件Sensor.h中找到它。
在Android2.2HALX轴和Y轴在文件中交换
在某些情况下,X必须与Y轴交换,以保持传感器数据的坐标与系统坐标一致。
对于FSLAndroid9(Android2.2)驱动程序,X轴与Y轴的交换非常简单。首先,在HAL文件sensor.c中,在函数sensor_poll()找到以下代码:
switch(event.code){
caseABS_X:
sSensors.acceleration.x=event.value&nsp;* CONVERT_A_X;
break;
case ABS_Y:
sSensors.acceleration.y = event.value * CONVERT_A_Y;
break;
case ABS_Z:
sSensors.acceleration.z = event.value * CONVERT_A_Z;
break;
}
然后,根据如下所示修改代码:
switch (event.code) {
case ABS_X:
sSensors.acceleration.y = event.value * CONVERT_A_Y;
break;
case ABS_Y:
sSensors.acceleration.x = event.value * CONVERT_A_X;
break;
case ABS_Z:
sSensors.acceleration.z = event.value * CONVERT_A_Z;
break;
}
在Android 2.3的HAL文件中交换X轴和Y轴
在Android 2.3的HAL文件中交换X轴和Y轴会更加复杂些,因为它具有更复杂的HAL文件结构。所有HAL文件都位于文件夹‘libsensors’中。文件AccelSensor.cpp中的两个函数需要修改。
首先,修改函数AccelSensor()的代码,如下所示:
if (accel_is_sensor_enabled(SENSOR_TYPE_ACCELEROMETER)) {
mEnabled |= 1<
if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X), &absinfo)) {
mPendingEvents[Accelerometer].acceleration.y = absinfo.value * CONVERT_A_Y;
}
if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo)) {
mPendingEvents[Accelerometer].acceleration.x = absinfo.value * CONVERT_A_X;
}
if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo)) {
mPendingEvents[Accelerometer].acceleration.z = absinfo.value * CONVERT_A_Z;
}
}
然后,修改函数processEvent()的代码,如下所示:
void AccelSensor::processEvent(int code, int value)
{
switch (code) {
case EVENT_TYPE_ACCEL_X:
mPendingMask |= 1<
mPendingEvents[Accelerometer].acceleration.y = value * CONVERT_A_Y;
break;
case EVENT_TYPE_ACCEL_Y:
mPendingMask |= 1<
mPendingEvents[Accelerometer].acceleration.x = value * CONVERT_A_X;
break;
case EVENT_TYPE_ACCEL_Z:
mPendingMask |= 1<
mPendingEvents[Accelerometer].acceleration.z = value * CONVERT_A_Z;
break;
}
}
完成后,X轴和Y轴的数据就互相交换了。
在Kernel驱动文件中交换X轴和Y轴
X轴和Y轴的数据交换可以在底层的Linux驱动中,在刚开始读取传感器数据时实施。 通过这种方法,无论传感器芯片以何种方式安装在PCB中,或者使用各种不同类型的传感器,HAL文件都可以保持一致。
对于Android 2.2和2.3来说,执行该操作的最便捷的方式是修改函数report_abs()中的代码。在该函数中,传感器数据通过调用函数 mma8452_read_data()读取,如下所示(当使用的传感器为MMA8452Q时):
if (mma8452_read_data(&x,&y,&z) != 0) {
//DBG("mma8452 data read failed\n");
return; }
X轴和Y轴可以通过以下方式轻松交换:
if (mma8452_read_data(&y,&x,&z) != 0) {
//DBG("mma8452 data read failed\n");
return; }
对于Android 2.2,MMA8452的Kernel驱动文件为mma8452.c;对于Android 2.3,驱动文件是‘hwmon’文件夹中的mxc_mma8452.c。
在Kernel驱动文件中改变 X、Y和Z轴的方向
传感器数据的方向也可以在Kernel驱动文件中更改。以下带有注释的语句可以添加到函数report_abs()中,从而改变数据方向:
if (mma8452_read_data(&y,&x,&z) != 0) {
//DBG("mma8452 data read failed\n");
return;
}
x *= -1; //Reverse X direction
y *= -1; //Reverse Y direction
z *= -1; //Reverse Z direction
input_report_abs(mma8452_idev->input, ABS_X, x);
input_report_abs(mma8452_idev->input, ABS_Y, y);
input_report_abs(mma8452_idev->input, ABS_Z, z);
input_sync(mma8452_idev->input);
总结
Android系统已经为加速度计定义了坐标系统,因此用户必须转换从实际传感器中读取的数据,从而与其保持一致。无论是否需要转换,都应检查X、Y和Z轴的方向以及X-Y轴坐标。我们可以更改HAL文件或Kernel驱动文件来改变轴的方向,或交换X和Y轴,但是不要同时修改HAL文件和Kernel驱动。