触发反馈
在恰当的时机,向正确的手指发出压力和振动。
反馈如何触发
反馈来自你发出的事件——触碰、抓取、松开——或场景中的物理碰撞体。请用其中之一来控制反馈的触发;切勿每帧轮询。
大多数 Unity 场景根本不需要调用 API:把 HexRInteractableHaptics 放在可交互组件旁边,抓取时即可感受到;或把 SpecialHaptics 放在触发碰撞体上,触碰时即可感受到。需要显式控制时,再使用下面的调用。
切勿在密集循环中发送反馈。在 Quest 和 PICO 构建中,命令会被收集起来,最快每 100 ms 发送一次,手套断开连接期间收集的命令会被丢弃;在 Windows 上,每条命令都是一次单独的蓝牙写入。请在事件发生时发送,而不是每帧发送——参见延迟。
手套会持续施加最后收到的压力,直到收到释放命令;手套上没有任何部件会自行松开。自 0.9.4 起,Unity 插件包会在应用退出、暂停或断开手套连接时释放所有通道,但如果应用崩溃或蓝牙连接中断,就没有任何办法释放;Python 库也不会替你释放任何通道。如果手套一直保持按压,请关闭手臂模块。
压力
在六个通道之一上施加持续挤压——五根手指和手掌。intensity 取值 0.1–1.0;speed 表示加压到该值的快慢。
// The Pressure Controller on each hand. finger, on/off,
// intensity 0.1-1.0, ramp speed 0.1-1.0, bypass the hand-near check.
hand.CustomSingleHaptics(Haptics.Finger.Index, true, 0.8f, 1f, false);
// Let go. Release with true as the last argument, or call RemoveIndexHaptics():
// a release that goes through the hand-near check is dropped if the hand has left.
hand.CustomSingleHaptics(Haptics.Finger.Index, false, 0f, 1f, true);施加压力时,将最后一个参数保持为 false,这样只有在手确实到了物体那里时才会触发挤压。释放时将其设为 true,确保释放命令总能送达。
F = Haptics.Finger
# finger, on/off, intensity 0.1-1.0, ramp speed 0.1-1.0
data = haptics.hexr_pressure(F.Index, True, 0.8, 1.0)
await client.write_gatt_char(CHAR_UUID, data)
# Let go.
data = haptics.hexr_pressure(F.Index, False, 0.0, 1.0)
await client.write_gatt_char(CHAR_UUID, data)每根手指,各自取值
为每个参数传入数组而非单个值,每个通道就能获得各自的设置,并合并为一次 BLE 写入。通道顺序是固定的——Thumb, Index, Middle, Ring, Pinky, Palm——且每个数组的长度都必须与手指列表相同。
// handler is a glove's HaptGloveHandler: HexRManager.Instance.rightHand, or leftHand.
// One entry per channel. The order is fixed:
// Thumb, Index, Middle, Ring, Pinky, Palm.
Haptics.Finger[] fingers = { Haptics.Finger.Thumb, Haptics.Finger.Index,
Haptics.Finger.Middle, Haptics.Finger.Ring,
Haptics.Finger.Pinky, Haptics.Finger.Palm };
bool[] states = { true, true, true, true, true, true };
float[] intensities = { 0.3f, 0.9f, 0.9f, 0.6f, 0.4f, 0.8f };
float[] speeds = { 1f, 1f, 1f, 1f, 1f, 1f };
handler.BTSend(handler.haptics.HEXRPressure(fingers, states, intensities, speeds));
// Vibration takes per-finger frequency as well as intensity. 0 Hz is not
// "off": it is clamped to 0.1 Hz. Leave a channel out with state false.
float[] freqs = { 3f, 12f, 12f, 6f, 3f, 3f };
handler.BTSend(handler.haptics.HEXRVibration(fingers, states, freqs, intensities));
// Release everything: the pair the HexR Tools "All OFF" button sends.
hand.RemoveAllHaptics();
hand.RemoveAllVibrations();想让所有通道使用相同的值?Pressure Controller(压力控制器)提供了快捷方法:TriggerAllHapticsIncrease(pressure)、TriggerCustomHapticsIncrease(bool[], pressure, speed)、TriggerAllVibrations(frequency) 和 TriggerCustomlVibrations(bool[], intensity, frequency)——注意其拼写。它们的 bool[] 用于选择要触发的通道,顺序同样固定。
F = Haptics.Finger
fingers = [F.Thumb, F.Index, F.Middle, F.Ring, F.Pinky, F.Palm]
# One entry per channel, same order as the list above.
data = haptics.hexr_pressure_multiple(
fingers,
[True] * 6,
[0.3, 0.9, 0.9, 0.6, 0.4, 0.8], # intensity
[1.0] * 6) # ramp speed
await client.write_gatt_char(CHAR_UUID, data)
# Vibration takes seven lists -- still 0.1-2 Hz only.
data = haptics.hexr_vibrations_multiple(
fingers, [True] * 6,
[1.5] * 6, [0.8] * 6, [0.5] * 6, [1.0] * 6, [0.0] * 6)
await client.write_gatt_char(CHAR_UUID, data)如果某个列表比手指数组短,会在帧中途抛出 IndexOutOfRangeException,而此时部分数据已经构建完成。请让所有数组都基于同一个数据源构建。
振动
同样的挤压,反复开启和关闭。frequency 决定切换的快慢。
低于 5 Hz 时,intensity 决定每个脉冲的按压力度。在 5 Hz 及以上,压力固定为最大值,intensity 改为决定占空比。
| 频率 | 手感 | intensity 的作用 |
|---|---|---|
| 0.1–1 Hz | 缓慢、间隔分明的脉冲 | 每个脉冲的压力 |
| 1–5 Hz | 清晰、可数的脉冲 | 每个脉冲的压力 |
| 5–40 Hz | 持续的嗡嗡振动 | 占空比 |
超出范围的值会被限制在范围内,而不会被拒绝。将状态参数传为 false 即可停止某个通道。
// handler is a glove's HaptGloveHandler: HexRManager.Instance.rightHand, or leftHand.
// hand is a Pressure Controller.
// finger, on/off, frequency 0.1-40 Hz, intensity 0.1-1.0
byte[] data = handler.haptics.HEXRVibration(Haptics.Finger.Index, true, 12f, 0.7f);
handler.BTSend(data);
// Or through the Pressure Controller -- note that intensity
// comes before frequency here, not after it.
hand.CustomSingleVibrations(Haptics.Finger.Palm, true, 0.7f, 12f, false);
hand.RemoveAllVibrations();低于 2 Hz 时,一个参数更多的重载可额外设置脉冲形状,以及振动停止后保持的压力——HEXRVibration(finger, state, frequency, intensity, peakRatio, speed, endIntensity)。取值范围见反馈参数。
F = Haptics.Finger
# finger, on/off, frequency, intensity, peak ratio,
# ramp speed, and the pressure to hold once it stops
data = haptics.hexr_vibrations(F.Index, True, 1.5, 0.8, 0.5, 1.0, 0.0)
await client.write_gatt_char(CHAR_UUID, data)该库只提供低频形式,因此 hexr_vibrations 会将频率限制在 0.1–2 Hz。如需嗡嗡振动而非脉冲,请通过 Unity 驱动手套。取值范围见 Python 参考。