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文件下的传感器数组定义。
因只用到陀螺仪传感器,把其他传感器定义删掉
- static const struct sensor_t sSensorList[] = {
- /*
- { "KR3DM 3-axis Accelerometer",
- "STMicroelectronics",
- 1, SENSORS_ACCELERATION_HANDLE,
- SENSOR_TYPE_ACCELEROMETER, RANGE_A, CONVERT_A, 0.23f, 20000, { } },
- { "AK8973 3-axis Magnetic field sensor",
- "Asahi Kasei Microdevices",
- 1, SENSORS_MAGNETIC_FIELD_HANDLE,
- SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, CONVERT_M, 6.8f, 16667, { } },
- { "AK8973 Orientation sensor",
- "Asahi Kasei Microdevices",
- 1, SENSORS_ORIENTATION_HANDLE,
- SENSOR_TYPE_ORIENTATION, 360.0f, CONVERT_O, 7.8f, 16667, { } },
- { "GP2A Light sensor",
- "Sharp",
- 1, SENSORS_LIGHT_HANDLE,
- SENSOR_TYPE_LIGHT, 3000.0f, 1.0f, 0.75f, 0, { } },
- { "GP2A Proximity sensor",
- "Sharp",
- 1, SENSORS_PROXIMITY_HANDLE,
- SENSOR_TYPE_PROXIMITY, 5.0f, 5.0f, 0.75f, 0, { } },
- */
- { "K3G Gyroscope sensor",
- "STMicroelectronics",
- 1, SENSORS_GYROSCOPE_HANDLE,
- SENSOR_TYPE_GYROSCOPE, RANGE_GYRO, CONVERT_GYRO, 6.1f, 1190, { } },
- };
- struct sensors_poll_context_t {
- struct sensors_poll_device_t device; // must be first
-
- sensors_poll_context_t();
- ~sensors_poll_context_t();
- int activate(int handle, int enabled);
- int setDelay(int handle, int64_t ns);
- int pollEvents(sensors_event_t* data, int count);
-
- private:
- enum {
- //light = 0,
- //proximity = 1,
- //akm = 2,
- //gyro = 3,
- gyro = 0,
- numSensorDrivers,
- numFds,
- };
-
- static const size_t wake = numFds - 1; //wake = 1
- static const char WAKE_MESSAGE = 'W';
- struct pollfd mPollFds[numFds];//2
- int mWritePipeFd;
- SensorBase* mSensors[numSensorDrivers];// 2
-
- int handleToDriver(int handle) const {
- switch (handle) {
- /*
- case ID_A:
- case ID_M:
- case ID_O:
- return akm;
- case ID_P:
- return proximity;
- case ID_L:
- return light;
- */
- case ID_GY:
- return gyro;
- }
- return -EINVAL;
- }
- };
- sensors_poll_context_t::sensors_poll_context_t()
- {
- /*
- mSensors[light] = new LightSensor();
- mPollFds[light].fd = mSensors[light]->getFd();
- mPollFds[light].events = POLLIN;
- mPollFds[light].revents = 0;
-
- mSensors[proximity] = new ProximitySensor();
- mPollFds[proximity].fd = mSensors[proximity]->getFd();
- mPollFds[proximity].events = POLLIN;
- mPollFds[proximity].revents = 0;
-
- mSensors[akm] = new AkmSensor();
- mPollFds[akm].fd = mSensors[akm]->getFd();
- mPollFds[akm].events = POLLIN;
- mPollFds[akm].revents = 0;
-
- */
- //LOGD("sensors_poll_context_t");
- mSensors[gyro] = new GyroSensor();
- mPollFds[gyro].fd = mSensors[gyro]->getFd();
- mPollFds[gyro].events = POLLIN;
- mPollFds[gyro].revents = 0;
-
- int wakeFds[2];
- int result = pipe(wakeFds);
- LOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));
- fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
- fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
- mWritePipeFd = wakeFds[1];
-
- //wake equals 1
- mPollFds[wake].fd = wakeFds[0];//store the reading fd of the pipe
- mPollFds[wake].events = POLLIN;
- mPollFds[wake].revents = 0;
- }
- int GyroSensor::getFd()
- {
- if(mSocketFd == -1){
- socket_connect();
- }
-
- return mSocketFd;
- }
我们回过头看sensors.cpp文件的sensors_poll_context_t构造函数:
- mSensors[gyro] = new GyroSensor();
- mPollFds[gyro].fd = mSensors[gyro]->getFd();
- mPollFds[gyro].events = POLLIN;
- mPollFds[gyro].revents = 0;
- int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
- {
- //what does parameter count mean ? fuck
- int nbEvents = 0;
- int n = 0;
- //LOGD("sensors_poll_context_t::pollEvents");
- //LOGD("count=%d",count);
-
- do {
- // see if we have some leftover from the last poll()
- for (int i=0 ; count && i<numSensorDrivers ; i++) {
- SensorBase* const sensor(mSensors[i]);
- if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
- int nb = sensor->readEvents(data, count);
- if (nb < count) {
- // no more data for this sensor
- mPollFds[i].revents = 0;
- }
- count -= nb;
- nbEvents += nb;
- data += nb;
- }
- }
-
- if (count) {
- // we still have some room, so try to see if we can get
- // some events immediately or just wait if we don't have
- // anything to return
- n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
- if (n<0) {
- LOGE("poll() failed (%s)", strerror(errno));
- return -errno;
- }
- //read data from pipe
- if (mPollFds[wake].revents & POLLIN) {
- char msg;
- int result = read(mPollFds[wake].fd, &msg, 1);
- LOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
- LOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));
- mPollFds[wake].revents = 0;
- }
- }
- // if we have events and space, go read them
- } while (n && count);
-
-
-
- return nbEvents;
- }
- GyroSensor::GyroSensor()
- : SensorBase(NULL, "gyro"),
- mEnabled(0),
- mInputReader(4),
- mHasPendingEvent(false),
- mEnabledTime(0),
- mSocketFd(-1)
- {
- //LOGD("GyroSensor::GyroSensor");
- mPendingEvent.version = sizeof(sensors_event_t);
- mPendingEvent.sensor = ID_GY;
- mPendingEvent.type = SENSOR_TYPE_GYROSCOPE;
- memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
-
-
- /*
- if (data_fd) {
- strcpy(input_sysfs_path, "/sys/class/input/");
- strcat(input_sysfs_path, input_name);
- strcat(input_sysfs_path, "/device/");
- input_sysfs_path_len = strlen(input_sysfs_path);
- enable(0, 1);
- }
-
- */
- }
- int GyroSensor::setInitialState() {
-
- /*
- struct input_absinfo absinfo_x;
- struct input_absinfo absinfo_y;
- struct input_absinfo absinfo_z;
- float value;
- if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_x) &&
- !ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_y) &&
- !ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_z)) {
- value = absinfo_x.value;
- mPendingEvent.data[0] = value * CONVERT_GYRO_X;
- value = absinfo_x.value;
- mPendingEvent.data[1] = value * CONVERT_GYRO_Y;
- value = absinfo_x.value;
- mPendingEvent.data[2] = value * CONVERT_GYRO_Z;
- mHasPendingEvent = true;
- }
-
-
- */
-
- //LOGD("GyroSensor::setInitialState");
- return 0;
- }
- int GyroSensor::enable(int32_t, int en) {
- /*
- int flags = en ? 1 : 0;
- if (flags != mEnabled) {
- int fd;
- strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
- fd = open(input_sysfs_path, O_RDWR);
- if (fd >= 0) {
- char buf[2];
- int err;
- buf[1] = 0;
- if (flags) {
- buf[0] = '1';
- mEnabledTime = getTimestamp() + IGNORE_EVENT_TIME;
- } else {
- buf[0] = '0';
- }
- err = write(fd, buf, sizeof(buf));
- close(fd);
- mEnabled = flags;
- setInitialState();
- return 0;
- }
- return -1;
- }
- */
-
- //LOGD("GyroSensor::enable");
- return 0;
- }
- int GyroSensor::setDelay(int32_t handle, int64_t delay_ns)
- {
- /*
- int fd;
- strcpy(&input_sysfs_path[input_sysfs_path_len], "poll_delay");
- fd = open(input_sysfs_path, O_RDWR);
- if (fd >= 0) {
- char buf[80];
- sprintf(buf, "%lld", delay_ns);
- write(fd, buf, strlen(buf)+1);
- close(fd);
- return 0;
- }
- return -1;
- */
- //LOGD("GyroSensor::setDelay");
- return 0;
- }
6.修改gyro类的readEvents函数,这个函数是最重要的函数,要从socket中读取gyro数据:
- float value = 0;
- char buf[2];
- int nread = 0;
-
- nread = read(mSocketFd, buf, 2);
- if(nread <= 0){
- LOGE("GyroSensor::readEvents read error.");
- return 0;
- }
-
- float value = (float)((buf[0] << 8) + buf[1]);
- //LOGD("gyro_msg_handle, value=%f",value);
- value *= CONVERT_GYRO_X;
-
-
- mPendingEvent.data[0] = value;
- mPendingEvent.data[1] = value;
- mPendingEvent.data[2] = value;
-
- *data = *mPendingEvent;
-
- return 1;
7.修改libsensors下的Android.mk文件的:
- LOCAL_MODULE := sensors.default
- package com.hase.ng102.sensors;
-
- import android.R.string;
- import android.app.Activity;
- import android.content.Context;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.util.Log;
- import android.widget.TextView;
-
- public class SensorDemoActivity extends Activity {
- //设置LOG标签
- private static final String TAG = "sensors";
- private SensorManager sm;
- private TextView tv1;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- tv1 = (TextView)this.findViewById(R.id.tv1);
- sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
- Log.d(String.format("getSystemService %s", sm == null ? "sucess":"fail"), TAG);
- int sensorType = Sensor.TYPE_GYROSCOPE;
- sm.registerListener(myAccelerometerListener,sm.getDefaultSensor(sensorType),SensorManager.SENSOR_DELAY_NORMAL);
- }
- /*
- * SensorEventListener接口的实现,需要实现两个方法
- * 方法1 onSensorChanged 当数据变化的时候被触发调用
- * 方法2 onAccuracyChanged 当获得数据的精度发生变化的时候被调用,比如突然无法获得数据时
- * */
- final SensorEventListener myAccelerometerListener = new SensorEventListener(){
- //复写onSensorChanged方法//
- public void onSensorChanged(SensorEvent sensorEvent){
- if(sensorEvent.sensor.getType() == Sensor.TYPE_GYROSCOPE){
- Log.i(TAG,"onSensorChanged");
- //图解中已经解释三个值的含义
- float x = sensorEvent.values[0];
- float y = sensorEvent.values[1];
- float z = sensorEvent.values[2];
- String msg = String.format("x=%f\n y=%f\n z=%f\n",x,y,z);
- tv1.setText(msg);
- Log.i(TAG, msg);
- }
- else {
- String msg = "other sensors data changed";
- tv1.setText(msg);
- Log.i(TAG, msg);
- }
- }
- //复写onAccuracyChanged方法
- public void onAccuracyChanged(Sensor sensor , int accuracy){
- Log.i(TAG, "onAccuracyChanged");
- }
- };
- public void onPause(){
- /*
- * 很关键的部分:注意,说明文档中提到,即使activity不可见的时候,感应器依然会继续的工作,测试的时候可以发现,没有正常的刷新频率
- * 也会非常高,所以一定要在onPause方法中关闭触发器,否则讲耗费用户大量电量,很不负责。
- * */
- sm.unregisterListener(myAccelerometerListener);
- super.onPause();
- }
- }