Microtube 文档
EN中文
开发者 / 指南 / 触发反馈

触发反馈

在恰当的时机,向正确的手指发出压力和振动。

反馈如何触发

反馈来自你发出的事件——触碰、抓取、松开——或场景中的物理碰撞体。请用其中之一来控制反馈的触发;切勿每帧轮询。

大多数 Unity 场景根本不需要调用 API:把 HexRInteractableHaptics 放在可交互组件旁边,抓取时即可感受到;或把 SpecialHaptics 放在触发碰撞体上,触碰时即可感受到。需要显式控制时,再使用下面的调用。

警告

切勿在密集循环中发送反馈。在 Quest 和 PICO 构建中,命令会被收集起来,最快每 100 ms 发送一次,手套断开连接期间收集的命令会被丢弃;在 Windows 上,每条命令都是一次单独的蓝牙写入。请在事件发生时发送,而不是每帧发送——参见延迟。

施加之后务必释放

手套会持续施加最后收到的压力,直到收到释放命令;手套上没有任何部件会自行松开。自 0.9.4 起,Unity 插件包会在应用退出、暂停或断开手套连接时释放所有通道,但如果应用崩溃或蓝牙连接中断,就没有任何办法释放;Python 库也不会替你释放任何通道。如果手套一直保持按压,请关闭手臂模块。

压力

在六个通道之一上施加持续挤压——五根手指和手掌。intensity 取值 0.1–1.0;speed 表示加压到该值的快慢。

csharp
// 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,确保释放命令总能送达。

python
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——且每个数组的长度都必须与手指列表相同。

csharp
// 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[] 用于选择要触发的通道,顺序同样固定。

python
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 即可停止某个通道。

csharp
// 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)。取值范围见反馈参数。

python
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)
Python 最高 2 Hz

该库只提供低频形式,因此 hexr_vibrations 会将频率限制在 0.1–2 Hz。如需嗡嗡振动而非脉冲,请通过 Unity 驱动手套。取值范围见 Python 参考。