在HoloLens上还是Daydream之外使用Daydream Controller? [英] Use Daydream Controller on HoloLens or outside Daydream?

查看:89
本文介绍了在HoloLens上还是Daydream之外使用Daydream Controller?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

白日梦控制器很棒,我们希望能够在我的AR应用程序中使用它.它可以通过蓝牙与HoloLens配对,但还不确定我是否可以在Unity中查看它.

The daydream controller is awesome and we want to be able to use it in my AR app. It pairs via bluetooth to the HoloLens just fine, but not sure if I can view it in Unity.

HoloLens和白日梦都需要他们自己的Unity技术预览. gvr控制器代码处于在线状态,但似乎直接与GVR C API对话.

Both HoloLens and daydream require their own Unity technical previews. The gvr Controller code is online but seems to speak directly to GVR C api.

有没有想到是否甚至可以在Unity中使用Daydream技术预览功能访问Daydream控制器?

Any thoughts on if accessing daydream controller in Unity outside the daydream tech preview is even possible?

推荐答案

在没有GVR服务的情况下访问白日梦控制器非常有可能.我实际上是在为此工作,并且可以分享我所知道的东西.

It is very possible to access the daydream controller without the GVR services. I am in fact working on that myself and can share what I know.

使用蓝牙适配器,您可以查看所有可用数据并订阅所需的ID.我不知道您将如何在Hololens/Unity中做到这一点.基本上,您想:

Using bluetooth gatt you can view all the data available and subscribe to the ID you want. I don't know how you would do this within Hololens/Unity specifically. Basically you want to:

  1. 连接到设备
  2. 选择服务(0000fe55-0000-1000-8000-00805f9b34fb)
  3. 选择特征(00000001-1000-1000-8000-00805f9b34fb)
  4. 请求通知(00002902-0000-1000-8000-00805f9b34fb)
  1. Connect to the device
  2. Choose the service (0000fe55-0000-1000-8000-00805f9b34fb)
  3. Choose the characteristic (00000001-1000-1000-8000-00805f9b34fb)
  4. Request notifications for it (00002902-0000-1000-8000-00805f9b34fb)

Android示例:

Android Example:

static final UUID DAYDREAM_CUSTOM_SERVICE = UUID.fromString("0000fe55-0000-1000-8000-00805f9b34fb");
static final UUID DAYDREAM_CHARACTERISTIC = UUID.fromString("00000001-1000-1000-8000-00805f9b34fb");
static final UUID CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
...
BluetoothGattService service = gatt.getService(DAYDREAM_CUSTOM_SERVICE);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(DAYDREAM_CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID);
descriptor.setValue( BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);

我建议查找Bluetooth Gatt以了解有关服务和特性的更多信息.在从代码开始之前,我还使用了Playstore上的BLE扫描仪应用程序来查看很多此类信息.

I suggest looking up Bluetooth Gatt to understand more about services and characteristics. I also used the BLE Scanner app on the playstore to view a lot of this information before starting with code.

设备会提供20字节的数据供您使用.它由时间,方向,加速度,原始陀螺仪,触摸位置和按钮标志组成.

The device gives 20 bytes of data to work with. It is comprised of time, orientation, acceleration, raw gyro, touch position, and button flags.

示例(平放在桌子上):

Example (laying flat on a table):

5BEBFFB825FDB000041000B00000000000000000
63EFFFB825FDB000041000B00000000000000008
6C73FFB825FDB000041000B00000000000000038

示例(使用触摸板):

480BFE87EB00E801841000B00000000191FBA008
4F8FFE47EB00E800441000B0000003FEB1FBA038
5893FE27EB00EFFF041000B0000003FF51FBA000

字节定义如下:

Bytes:

  - 1: TTTT TTTT * T for time, loops
  - 2: TNNN NNKK * N is sequence number
  - 3: KKKK KKKK * IJK is orientation
  - 4: KKKI IIII
  - 5: IIII IIII
  - 6: JJJJ JJJJ
  - 7: JJJJ JOOO * MNO is acceleration
  - 8: OOOO OOOO
  - 9: OONN NNNN
  -10: NNNN NNNM
  -11: MMMM MMMM
  -12: MMMM CCCC * CDE for raw gyro
  -13: CCCC CCCC
  -14: CDDD DDDD
  -15: DDDD DDEE
  -16: EEEE EEEE
  -17: EEEX XXXX * All the X is the X touch position (8 bits)
  -18: XXXY YYYY * Y the Y touch position (8 bits)
  -19: YYYB BBBB * B the buttons (5 bits | [+][-][App][Home][Click])
  -20: Values vary

有了这个,我有了触摸板和按钮,它们可以与我可以为其构建应用程序的任何蓝牙设备一起使用.此外,您还需要添加一些功能来重置设备位置,控制音频等.

With this I have the touch pad and buttons able to work with any bluetooth device I can build apps for. In addition, you would need to add back functionality to reset the device position, control audio, etc.

在Android上使用以下定义:

Using this definition on Android:

static final int CLICK_BTN = 0x1;
static final int HOME_BTN = 0x2;
static final int APP_BTN = 0x4;
static final int VOL_DOWN_BTN = 0x8;
static final int VOL_UP_BTN = 0x10;
float xTouch=0, yTouch=0;
...
final boolean isClickDown = (data[18] & CLICK_BTN) > 0;
final boolean isHomeDown = (data[18] & HOME_BTN) > 0;
final boolean isAppDown = (data[18] & APP_BTN) > 0;
final boolean isVolMinusDown = (data[18] & VOL_DOWN_BTN) > 0;
final boolean isVolPlusDown = (data[18] & VOL_UP_BTN) > 0;

final int time = ((data[0] & 0xFF) << 1 | (data[1] & 0x80) >> 7 );

final int seq = (data[1] & 0x7C) >> 2;

int xOri = (data[1] & 0x03) << 11 | (data[2] & 0xFF) << 3 | (data[3] & 0xE0) >> 5;
xOri = (xOri << 19) >> 19;

int yOri = (data[3] & 0x1F) << 8 | (data[4] & 0xFF);
yOri = (yOri << 19) >> 19;

int zOri = (data[5] & 0xFF) << 5 | (data[6] & 0xF8) >> 3;
zOri = (zOri << 19) >> 19;

int xAcc = (data[6] & 0x07) << 10 | (data[7] & 0xFF) << 2 | (data[8] & 0xC0) >> 6;
xAcc = (xAcc << 19) >> 19;

int yAcc = (data[8] & 0x3F) << 7 | (data[9] & 0xFE) >>> 1;
yAcc = (yAcc << 19) >> 19;

int zAcc = (data[9] & 0x01) << 12 | (data[10] & 0xFF) << 4 | (data[11] & 0xF0) >> 4;
zAcc = (zAcc << 19) >> 19;

int xGyro = ((data[11] & 0x0F) << 9 | (data[12] & 0xFF) << 1 | (data[13] & 0x80) >> 7);
xGyro = (xGyro << 19) >> 19;

int yGyro = ((data[13] & 0x7F) << 6 | (data[14] & 0xFC) >> 2 );
yGyro = (yGyro << 19) >> 19;

int zGyro = ((data[14] & 0x03) << 11 | (data[15] & 0xFF) << 3 | (data[16] & 0xE0) >> 5);
zGyro = (zGyro << 19) >> 19;

xTouch = ((data[16] & 0x1F) << 3 | (data[17] & 0xE0) >> 5) / 255.0f;
yTouch = ((data[17] & 0x1F) << 3 | (data[18] & 0xE0) >> 5) / 255.0f;

可以对其进行优化,但是会分配除最后一个字节以外的所有位.代码value = (value << 19) >> 19也可以是value = (value >> 12) == 0 ? value : ~0x1FFF | value.只是将有符号的位扩展为32位的有符号的int.

This could be optimized but it assigns all the bits except for the last byte. The code value = (value << 19) >> 19 can also be value = (value >> 12) == 0 ? value : ~0x1FFF | value. It is just to extend the signed bit to a 32bit signed int.

我希望这会有所帮助,并期待其他答案.

I hope this helps and look forward to additional answers.

查看gvr代码后,我发现我以前的假设存在一些问题.实际上是方向/加速度/陀螺仪.另外,序列的位数增加了1位,时间的位数减少了1位.我已经更新了字节定义和android示例.

After looking at the gvr code I found I had some issues with my previous assumptions. It's actually Orientation/Acceleration/Gyro. Also there was 1 more bit for sequence and 1 less for time. I've updated the byte definition and android example.

此外,X,Y,Z值需要缩放为浮点数.对于Unity,您可以将int放入Vector3s,然后使用以下代码.对于Unity,我还否定了oriVector中的x和y.

In addition the X,Y,Z values need to be scaled to floats. For Unity you could put the ints into Vector3s and then use the following. I also negated the x and y in oriVector, for Unity.

Vector3 oriVector = new Vector3 (-xOri, -yOri, zOri);
...
oriVector *= (2 * Mathf.PI / 4095.0);
accVector *= (8 * 9.8 / 4095.0);
gyroVector *= (2048 / 180 * Mathf.PI / 4095.0);

然后要获得旋转,您只需要oriVector.实际上是存储为:单位矢量*角度的轴角.

Then to get the rotation you just need the oriVector. Which is actually an axis-angle stored as: unit vector * angle.

public Quaternion orientation = Quaternion.identity;
private Quaternion controllerPoseInSensorSpace = Quaternion.identity;
private Quaternion startFromSensorTransformation = Quaternion.identity;
...
// do this bit after getting the data and scaling it
float sqrMagnitude = oriVector.sqrMagnitude;
if (sqrMagnitude > 0) {
    // extract radian angle
    float w = Mathf.Sqrt (sqrMagnitude);
    // normalize vector
    oriVector /= w;
    // set orientation space
    setOrientationInSensorSpace (w,oriVector);
}
...
// then assign to a Transform
controller.localRotation = this.orientation;
...
// sets orientation with rotation offset
void setOrientationInSensorSpace(float angle, Vector3 axis) {
    // set orientation space
    this.controllerPoseInSensorSpace = Quaternion.AngleAxis(angle*Mathf.Rad2Deg,axis);
    // rotate based on centered offset
    this.orientation = this.startFromSensorTransformation * this.controllerPoseInSensorSpace;
}
...
// after holding home for 600 milliseconds
private void setStartFromSensorTransformation() {
    Vector3 angles = this.controllerPoseInSensorSpace.eulerAngles;
    // reset rotation on Y
    this.startFromSensorTransformation.Set(0,Mathf.Sin(-angles.y * Mathf.Deg2Rad / 2f), 0, Mathf.Cos(angles.y * Mathf.Deg2Rad / 2f));
    // could also reset all, easier to work with
    //this.startFromSensorTransformation = Quaternion.Inverse (this.controllerPoseInSensorSpace);
}

这与在常规蓝牙设备上进行白日梦有关.我还在Unity3D中使用了上面的C#代码.

That is everything related to getting daydream working with regular bluetooth devices. I also used the above C# code within Unity3D.

添加了更完整的字节定义.之前缺少的值是陀螺仪,磁力计和加速度数据.它们每个都有三个13bit带符号的整数.似乎还有一个与时间位有关的序列号.

Added a more complete byte definition. The values missing before were the gyro, magnetometer, and acceleration data. They each have three 13bit signed ints. There also seems to be a sequence number tucked in with the time bits.

为了在其他平台上使用设备数据,您需要通过用于9DoF/IMU设备的类似方程式来放置数据.我不知道如何解决这个问题.

In order to use the device data with other platforms you would need to put the data through similar equations used for 9DoF/IMU devices. I don't have knowledge of exactly how to address this.

这可能是标志专用的,我不确定其含义,但我有一些发现要列出.版本号是控制器的固件版本.

This is likely reserved for flags and I'm not sure on the meaning but I have some findings to list. Version number is the firmware version of the controller.

1.0.10 (out of the box): 0xF0/0xF8
1.0.10 (previously used with gvr): 0x00/0x08/0x38/0x51
1.0.15: 0x00/0x70

这篇关于在HoloLens上还是Daydream之外使用Daydream Controller?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆