unity如何控制android陀螺仪(陀螺仪的移植)

一 背景

1.需求

   陀螺仪硬件并非接在android cpu上,所以不存在陀螺仪驱动,而陀螺仪数据是通过用户空间的一个c程序传过来。

2.思路

   修改陀螺仪hal层,在hal层构建socket客户端,在数据源的c程序上构建socket服务端。一旦有数据,c程序通过socket发送数据到陀螺仪hal层,并上报。

二 步骤

1.把device/samsung/crespo/libsensors目录拷贝到hardware/libhardware/modules目录下

2.修改sensors.cpp文件下的传感器数组定义。

因只用到陀螺仪传感器,把其他传感器定义删掉

  1. static const struct sensor_t sSensorList[] = {
  2. /*
  3.         { "KR3DM 3-axis Accelerometer",
  4.           "STMicroelectronics",
  5.           1, SENSORS_ACCELERATION_HANDLE,
  6.           SENSOR_TYPE_ACCELEROMETER, RANGE_A, CONVERT_A, 0.23f, 20000, { } },
  7.         { "AK8973 3-axis Magnetic field sensor",
  8.           "Asahi Kasei Microdevices",
  9.           1, SENSORS_MAGNETIC_FIELD_HANDLE,
  10.           SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, CONVERT_M, 6.8f, 16667, { } },
  11.         { "AK8973 Orientation sensor",
  12.           "Asahi Kasei Microdevices",
  13.           1, SENSORS_ORIENTATION_HANDLE,
  14.           SENSOR_TYPE_ORIENTATION, 360.0f, CONVERT_O, 7.8f, 16667, { } },
  15.         { "GP2A Light sensor",
  16.           "Sharp",
  17.           1, SENSORS_LIGHT_HANDLE,
  18.           SENSOR_TYPE_LIGHT, 3000.0f, 1.0f, 0.75f, 0, { } },
  19.         { "GP2A Proximity sensor",
  20.           "Sharp",
  21.           1, SENSORS_PROXIMITY_HANDLE,
  22.           SENSOR_TYPE_PROXIMITY, 5.0f, 5.0f, 0.75f, 0, { } },
  23. */
  24.         { "K3G Gyroscope sensor",
  25.           "STMicroelectronics",
  26.           1, SENSORS_GYROSCOPE_HANDLE,
  27.           SENSOR_TYPE_GYROSCOPE, RANGE_GYRO, CONVERT_GYRO, 6.1f, 1190, { } },
  28. };
3.修改sensors.cpp的sensors_poll_context_t结构体,删除其他的传感器定义

  1. struct sensors_poll_context_t {
  2.     struct sensors_poll_device_t device; // must be first

  3.         sensors_poll_context_t();
  4.         ~sensors_poll_context_t();
  5.     int activate(int handle, int enabled);
  6.     int setDelay(int handle, int64_t ns);
  7.     int pollEvents(sensors_event_t* data, int count);

  8. private:
  9.     enum {
  10.         //light           = 0,
  11.         //proximity       = 1,
  12.         //akm             = 2,
  13.         //gyro            = 3,
  14.         gyro = 0,
  15.         numSensorDrivers,
  16.         numFds,
  17.     };

  18.     static const size_t wake = numFds - 1; //wake = 1
  19.     static const char WAKE_MESSAGE = 'W';
  20.     struct pollfd mPollFds[numFds];//2
  21.     int mWritePipeFd;
  22.     SensorBase* mSensors[numSensorDrivers];// 2

  23.     int handleToDriver(int handle) const {
  24.         switch (handle) {
  25. /*
  26.             case ID_A:
  27.             case ID_M:
  28.             case ID_O:
  29.                 return akm;
  30.             case ID_P:
  31.                 return proximity;
  32.             case ID_L:
  33.                 return light;
  34. */
  35.             case ID_GY:
  36.                 return gyro;
  37.         }
  38.         return -EINVAL;
  39.     }
  40. };
包括构造函数:

  1. sensors_poll_context_t::sensors_poll_context_t()
  2. {
  3. /*
  4.     mSensors[light] = new LightSensor();
  5.     mPollFds[light].fd = mSensors[light]->getFd();
  6.     mPollFds[light].events = POLLIN;
  7.     mPollFds[light].revents = 0;

  8.     mSensors[proximity] = new ProximitySensor();
  9.     mPollFds[proximity].fd = mSensors[proximity]->getFd();
  10.     mPollFds[proximity].events = POLLIN;
  11.     mPollFds[proximity].revents = 0;

  12.     mSensors[akm] = new AkmSensor();
  13.     mPollFds[akm].fd = mSensors[akm]->getFd();
  14.     mPollFds[akm].events = POLLIN;
  15.     mPollFds[akm].revents = 0;

  16. */
  17. //LOGD("sensors_poll_context_t");
  18.     mSensors[gyro] = new GyroSensor();
  19.     mPollFds[gyro].fd = mSensors[gyro]->getFd();
  20.     mPollFds[gyro].events = POLLIN;
  21.     mPollFds[gyro].revents = 0;

  22.     int wakeFds[2];
  23.     int result = pipe(wakeFds);
  24.     LOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));
  25.     fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
  26.     fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
  27.     mWritePipeFd = wakeFds[1];

  28. //wake equals 1
  29.     mPollFds[wake].fd = wakeFds[0];//store the reading fd of the pipe
  30.     mPollFds[wake].events = POLLIN;
  31.     mPollFds[wake].revents = 0;
  32. }
4.修改GyroSensor.cpp的getFd()函数,把原来的返回gyro设备驱动的文件描述符,改为返回socket的文件描述符。

  1.  int GyroSensor::getFd()
  2. {
  3. if(mSocketFd == -1){
  4. socket_connect();
  5. }

  6. return mSocketFd;
  7. }
其中,mSocketFd是在GyroSensor.h中新定义的socket文件描述符,socket_connect()函数实现连接socket服务端。

我们回过头看sensors.cpp文件的sensors_poll_context_t构造函数:
  1. mSensors[gyro] = new GyroSensor();
  2.     mPollFds[gyro].fd = mSensors[gyro]->getFd();
  3.     mPollFds[gyro].events = POLLIN;
  4.     mPollFds[gyro].revents = 0;
这里初始化gyro类后,通过getFd()获取socket文件描述符,然后就可以通过poll函数对文件描述符进行读取数据,poll的读取在sensors_poll_context_t::pollEvents函数中,代码都不用改变,像这样:

  1. int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
  2. {
  3. //what does parameter count mean ? fuck 
  4.     int nbEvents = 0;
  5.     int n = 0;
  6. //LOGD("sensors_poll_context_t::pollEvents");
  7. //LOGD("count=%d",count);

  8.     do {
  9.         // see if we have some leftover from the last poll()
  10.         for (int i=0 ; count && i<numSensorDrivers ; i++) {
  11.             SensorBase* const sensor(mSensors[i]);
  12.             if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
  13.                 int nb = sensor->readEvents(data, count);
  14.                 if (nb < count) {
  15.                     // no more data for this sensor
  16.                     mPollFds[i].revents = 0;
  17.                 }
  18.                 count -= nb;
  19.                 nbEvents += nb;
  20.                 data += nb;
  21.             }
  22.         }

  23.         if (count) {
  24.             // we still have some room, so try to see if we can get
  25.             // some events immediately or just wait if we don't have
  26.             // anything to return
  27.             n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
  28.             if (n<0) {
  29.                 LOGE("poll() failed (%s)", strerror(errno));
  30.                 return -errno;
  31.             }
  32. //read data from pipe
  33.             if (mPollFds[wake].revents & POLLIN) {
  34.                 char msg;
  35.                 int result = read(mPollFds[wake].fd, &msg, 1);
  36.                 LOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
  37.                 LOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));
  38.                 mPollFds[wake].revents = 0;
  39.             }
  40.         }
  41.         // if we have events and space, go read them
  42.     } while (n && count);



  43.     return nbEvents;
  44. }
4.修改gyro类的构造函数,把与设备驱动相关的那一段代码删除:

  1. GyroSensor::GyroSensor()
  2.     : SensorBase(NULL, "gyro"),
  3.       mEnabled(0),
  4.       mInputReader(4),
  5.       mHasPendingEvent(false),
  6.       mEnabledTime(0),
  7.       mSocketFd(-1)
  8. {
  9. //LOGD("GyroSensor::GyroSensor");
  10.     mPendingEvent.version = sizeof(sensors_event_t);
  11.     mPendingEvent.sensor = ID_GY;
  12.     mPendingEvent.type = SENSOR_TYPE_GYROSCOPE;
  13.     memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));


  14. /*
  15.     if (data_fd) {
  16.         strcpy(input_sysfs_path, "/sys/class/input/");
  17.         strcat(input_sysfs_path, input_name);
  18.         strcat(input_sysfs_path, "/device/");
  19.         input_sysfs_path_len = strlen(input_sysfs_path);
  20.         enable(0, 1);
  21.     }

  22. */
  23. }
5.修改gyro类的其他成员函数,包括setDelay,enable,setInitialState等函数里面的代码去全部删除:

  1. int GyroSensor::setInitialState() {

  2. /*
  3.     struct input_absinfo absinfo_x;
  4.     struct input_absinfo absinfo_y;
  5.     struct input_absinfo absinfo_z;
  6.     float value;
  7.     if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_x) &&
  8.         !ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_y) &&
  9.         !ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_z)) {
  10.         value = absinfo_x.value;
  11.         mPendingEvent.data[0] = value * CONVERT_GYRO_X;
  12.         value = absinfo_x.value;
  13.         mPendingEvent.data[1] = value * CONVERT_GYRO_Y;
  14.         value = absinfo_x.value;
  15.         mPendingEvent.data[2] = value * CONVERT_GYRO_Z;
  16.         mHasPendingEvent = true;
  17.     }


  18. */

  19. //LOGD("GyroSensor::setInitialState");
  20.     return 0;
  21. }

  1. int GyroSensor::enable(int32_t, int en) {
  2. /*
  3.     int flags = en ? 1 : 0;
  4.     if (flags != mEnabled) {
  5.         int fd;
  6.         strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
  7.         fd = open(input_sysfs_path, O_RDWR);
  8.         if (fd >= 0) {
  9.             char buf[2];
  10.             int err;
  11.             buf[1] = 0;
  12.             if (flags) {
  13.                 buf[0] = '1';
  14.                 mEnabledTime = getTimestamp() + IGNORE_EVENT_TIME;
  15.             } else {
  16.                 buf[0] = '0';
  17.             }
  18.             err = write(fd, buf, sizeof(buf));
  19.             close(fd);
  20.             mEnabled = flags;
  21.             setInitialState();
  22.             return 0;
  23.         }
  24.         return -1;
  25.     }
  26. */

  27. //LOGD("GyroSensor::enable");
  28.     return 0;
  29. }

  1. int GyroSensor::setDelay(int32_t handle, int64_t delay_ns)
  2. {
  3. /*
  4.     int fd;
  5.     strcpy(&input_sysfs_path[input_sysfs_path_len], "poll_delay");
  6.     fd = open(input_sysfs_path, O_RDWR);
  7.     if (fd >= 0) {
  8.         char buf[80];
  9.         sprintf(buf, "%lld", delay_ns);
  10.         write(fd, buf, strlen(buf)+1);
  11.         close(fd);
  12.         return 0;
  13.     }
  14. return -1;
  15. */
  16. //LOGD("GyroSensor::setDelay");
  17. return 0;
  18.     
  19. }

6.修改gyro类的readEvents函数,这个函数是最重要的函数,要从socket中读取gyro数据:

  1. float value = 0;
  2. char buf[2];
  3. int nread = 0;

  4. nread = read(mSocketFd, buf, 2);
  5. if(nread <= 0){
  6. LOGE("GyroSensor::readEvents read error.");
  7. return 0;
  8. }

  9. float value = (float)((buf[0] << 8) + buf[1]);
  10. //LOGD("gyro_msg_handle, value=%f",value);
  11. value *= CONVERT_GYRO_X;


  12. mPendingEvent.data[0] = value;
  13. mPendingEvent.data[1] = value;
  14. mPendingEvent.data[2] = value;

  15. *data = *mPendingEvent;

  16. return 1;
sokcet服务端每次发送2个字节数据,因是单轴陀螺仪,所以只有1个数据,把mPendingEvent的data数据3个字节都填充同一数据,然后赋值给*data,最后返回1,表述读到1个数据。



7.修改libsensors下的Android.mk文件的:
  1. LOCAL_MODULE := sensors.default
8.编译后,生成sensors.default.so文件到lib/hw目录,把hw目录下其他有sensors文字的so文件删除,只留sensors.default.so文件,然后就可以在模拟器或设备上进行测试了,App层的Java测试程序如下:

  1. package com.hase.ng102.sensors;

  2. import android.R.string;
  3. import android.app.Activity;
  4. import android.content.Context;
  5. import android.hardware.Sensor;
  6. import android.hardware.SensorEvent;
  7. import android.hardware.SensorEventListener;
  8. import android.hardware.SensorManager;
  9. import android.os.Bundle;
  10. import android.util.Log;
  11. import android.widget.TextView;

  12. public class SensorDemoActivity extends Activity {
  13. //设置LOG标签
  14.     private static final String TAG = "sensors";
  15. private  SensorManager sm;
  16. private TextView tv1;

  17.     /** Called when the activity is first created. */
  18.     @Override
  19.     public void onCreate(Bundle savedInstanceState) {
  20.         super.onCreate(savedInstanceState);
  21.         setContentView(R.layout.main);
  22.         
  23.         tv1 = (TextView)this.findViewById(R.id.tv1); 
  24.         sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
  25.         Log.d(String.format("getSystemService %s", sm == null ? "sucess":"fail"), TAG);
  26.         int sensorType = Sensor.TYPE_GYROSCOPE;
  27.         sm.registerListener(myAccelerometerListener,sm.getDefaultSensor(sensorType),SensorManager.SENSOR_DELAY_NORMAL);
  28.     }
  29.     
  30.     /*
  31.      * SensorEventListener接口的实现,需要实现两个方法
  32.      * 方法1 onSensorChanged 当数据变化的时候被触发调用
  33.      * 方法2 onAccuracyChanged 当获得数据的精度发生变化的时候被调用,比如突然无法获得数据时
  34.      * */
  35.     final SensorEventListener myAccelerometerListener = new SensorEventListener(){
  36.         
  37.         //复写onSensorChanged方法//
  38.         public void onSensorChanged(SensorEvent sensorEvent){
  39.             if(sensorEvent.sensor.getType() == Sensor.TYPE_GYROSCOPE){
  40.                 Log.i(TAG,"onSensorChanged");
  41.                 
  42.                 //图解中已经解释三个值的含义
  43.                 float x = sensorEvent.values[0];
  44.                 float y = sensorEvent.values[1];
  45.                 float z = sensorEvent.values[2];
  46.                 
  47.                 String msg = String.format("x=%f\n y=%f\n z=%f\n",x,y,z);
  48.                 tv1.setText(msg);
  49.                 Log.i(TAG, msg);
  50.             }
  51.             else {
  52.              String msg = "other sensors data changed";
  53.              tv1.setText(msg);
  54. Log.i(TAG, msg);
  55. }
  56.         }
  57.         //复写onAccuracyChanged方法
  58.         public void onAccuracyChanged(Sensor sensor , int accuracy){
  59.             Log.i(TAG, "onAccuracyChanged");
  60.         }
  61.     };
  62.     
  63.     public void onPause(){
  64.         /*
  65.          * 很关键的部分:注意,说明文档中提到,即使activity不可见的时候,感应器依然会继续的工作,测试的时候可以发现,没有正常的刷新频率
  66.          * 也会非常高,所以一定要在onPause方法中关闭触发器,否则讲耗费用户大量电量,很不负责。
  67.          * */
  68.         sm.unregisterListener(myAccelerometerListener);
  69.         super.onPause();
  70.     }
  71.     
  72.     
  73.     
  74. }