Haptics in Unity
Haptics inside the Unity Plugin are sent through the IHandFeedbackDevice
interface. This Interfacte is, by default, implemented by the following scripts:
SG_HapticGlove - Which passes the commands on to the SenseGlove ‘Core API’; SGCore.dll, where they will be sent to SenseGlove Devices.
SG_DeviceSelector - Passes commands to the currently connected IHandFeedbackDevice.
SG_TrackedHand - Passes commands to its SG_DeviceSelector
SG_Interactable - Passes commands to the SG_TrackedHand of all SG_GrabScripts that are holding on to the object.
SG_HandDetector - Passes commands to the SG_TrackedHand detected inside the zone.
Force-Feedback
Force-Feedback allows one to feel ‘stiffness’ on their fingers, using the cables running along the back of the hand.
The force feedback ‘level’ is set to a value between [0.0f … 1.0f], where 0.0f indicates ‘no force-feedback’, and 1.0f indicates full force feedback that the glove can provide.
During runtime, Force-Feedback commands are collected in a queue and sent out at the end of each frame. They can be ‘Queued’ as many times as needed by many different scripts, using the following functions:
1 2 3 4 5 6 7 8 | /// <summary> Tell the device to queue up a Force-Feedback command to this particular finger </summary>
/// <param name="finger"></param>
/// <param name="value01"></param>
void QueueFFBCmd(SGCore.Finger finger, float value01);
/// <summary> Tell the device to queue up Force-Feedback to several fingers. Levels 0...1 from Thumb = 0 to Pinky = 4. </summary>
/// <param name="values01"></param>
void QueueFFBCmd(float[] values01);
|
The main difference between these two functions is that QueueFFBCmd(SGCore.Finger finger, float value01)
will keep the other finger force-feedback values at the same level, while QueueFFBCmd(float[] values01)
has you set the level for each finger at once.
If a glove does not support force-feedback on the chosen finger (e.g. the Pinky finger on the Nova 2.0), the command is ignored.
Note
Sending a large amount of haptic commands to the glove may cause the Bluetooth connection to drop! To save bandwidth; the SenseGlove API only sends out new commands to the glove if a change in any Force-Feedback or Active Strap variables occur.
Built-In components
The SenseGlove Unity Plugin comes with an SG_Material
Script, that can be added to any Unity Collider.
Inside of the SenseGlove Hand Prefabs, there is a “Feedback Layer” that registers when such a collider is touched.
Based on the finger’s distance inside the collider, you can vary the force applied to the finger, creating the impression of a ‘hard’, ‘soft’, or ‘squishy’ object.
By default, the SG_Material sets the force-feedback on each finger to 1.0f (100%) when they touch its Collider.
However, it also has a materialProperties
variable. This is a SG_MaterialProperties
ScriptableObject that can be created inside your assets folder.
“Right Click > Create > SenseGlove > Material”.
In the inspector, you can edit the following variables:
Force Response - A Unity AnimationCurve that represents how the force-feedback signal increases as your finger enters further into the material. The X-axis represents the ‘distance inside the collider’, while the Y-Axis represents the ‘amount of force on said finger’.
Max Force Dist - Disance, in meters. Scales the X-axis of the “Force-Response” curve.
MaxForce - The maximum force-feebback signal this material provides. Scales the Y-axis of the “Force-Response” curve.
Wrist Squeeze (Active Strap)
The Nova 2.0’s front strap, also called the ‘Active Strap’, has a motor attached to it. It is possible to indirectly control this motor’s position, resulting on a pressure on the palm and/or on the sides of the hand.
The SenseGlove Unity Plugin allows you to control the ‘active strap’ pressure, using a value of 0.0f (no squeezing) and 1.0f (full squeeze). Similar to the Force-Feedback, Wrist Squeeze commands are collected in a queue and sent out at the end of each frame.
You can set the ‘Wrist Squeeze Level’ using the following command(s):
1 2 3 4 5 6 | /// <summary> Set the amount of squeeze feedback desired on the wrist. Where 0 is no squeeze, and 1 is full squeeze force. </summary>
/// <param name="squeezeLevel01"></param>
void QueueWristSqueeze(float squeezeLevel01);
/// <summary> Stops any active squeeze effects on the wrist. </summary>
void StopWristSqueeze();
|
If your device does not support “Wrist Squeeze” feedback (for example, your Nova 1), the command is ignored.
Note
Sending a large amount of haptic commands to the glove may cause the Bluetooth connection to drop! To save bandwidth; the SenseGlove API only sends out new commands to the glove if a change in any Force-Feedback or Active Strap variables occur.
Vibrotactile Feedback
The most versatile and recommended method to send vibrotactile feedback to the Nova is to use the SG_CustomWaveform
.
This component offers the greatest flexibility in parameters, and is compatible with both Nova 1 and Nova 2 gloves.
It also has a button where you can ‘preview’ your vibration(s) within the editor.
These “Custom Waveforms” are meant to be sent to the glove once, where they will play according to their parameters. Once the waveform ends, it will stop playing until a new command is received.
Note
Vibrations are generated on the Nova Glove itself by sending it a command containing various parameters. This allows us to create consistent vibrations without the need to compromise the sensor data and other haptic commands that run over the same connection.
Sending a large amount of haptic commands to the glove may cause the Bluetooth connection to drop! Try to avoid sending new vibration commands each frame.
The SG_CustomWaveform
is a ScriptableObject, and can be created inside your asset folder using “Right Click > Create > SenseGlove > Custom Waveform”.
The following paramaters can be tweaked:
intendedMotor - Indicates a generic VibrationLocation to play the effect. This can be changed when calling the ‘SendCustomWaveform’ function.
Amplitude - A value between 0.0f and 1.0f that represents the instensity of the signal.
WaveformType - An SGCore.WaveformType that indicates the type of vibration; e.g. Sine Wave, Square Wave, etc.
AttackTime - Time, in seconds, where the waveform ‘ramps up’ from 0.0f to the desired amplitude. Leave the other signals at 0.0f to create a ‘ramping up’ vibration.
SustainTime - Time, in seconds, where the waveform stays at the desired amplitude. Leave the other signals at 0.0f to create a ‘ramping up’ vibration.
DecayTime - Time, in seconds, where the amplitude of the signal ‘ramps down’ from the desire amplitude to 0.0f. Leave the other signals at 0.0f to create a ‘ramping down’ vibration.
RepeatAmount - How many times the vibration is repeated.
RepeatInfinite - If set to true, the vibration will be infinitely repeated until another vibration is recevied on the same motor ‘channel’. RepeatAmount is therefore ignored.
StartFrequency - The Starting Frequency of the vibration signal across a single vibration duration (attack + sustain + decay time). The Nova Glove Vibration motors work best at the default value of 180Hz. Though the Nova 1.0’s larger motor works better at 60-80Hz.
EndFrequency - The End Frequency of the vibration signal. Usually the same as StartFrequency.
FrequencySwitchTime - A value between 0.0f and 1.0f that indicates where on the timeline of attack + sustain + decay time we multiply the frequency with FrequencySwitchMultiplier. We reccomend leaving this variable alone.
FrequencySwitchMultiplier - The factor with which to multiply the current frequency at FrequencySwitchTime. We reccomend leaving this variable alone.
Supported VibrationLocations
VibrationLocation.Thumb_Tip - Activates the vibration motor on the thumb.
VibrationLocation.Index_Tip - Activates the vibration motor on the index finger.
VibrationLocation.Palm_IndexSide - Activates the vibration motor on the active strap, the one closest to the index finger.
VibrationLocation.Palm_PinkySide - Activates the vibration motor on the active strap, the one closest to the pinky finger.
VibrationLocation.WholeHand - Activates the Palm_IndexSide motor.
VibrationLocation.Thumb_Tip - Activates the vibration motor on the thumb.
VibrationLocation.Index_Tip - Activates the vibration motor on the index finger.
VibrationLocation.WholeHand - Vibrates the large vibration motor on the back of the hand.
Sending a CustomWaveform
We don’t have a nice way to send waveforms ‘on touch’ in the same way we do for our Force-Feedback. To send a SG_CustomWaveform
, you will need to call the following function on any script that implements the IHandFeedbackDevice
interface:
1 2 3 4 | /// <summary> Sends a custom waveform to the device, if it is a Nova Glove. </summary>
/// <param name="customWaveform"></param>
/// <param name="location"></param>
void SendCustomWaveform(SG_CustomWaveform customWaveform, VibrationLocation location);
|
This function will send the Custom Waveforms to the glove. The second parameter, the VibrationLocation
indicates where to play it. You can use the one you’ve defined in the waveform through vibration.intendedMotor
, or choose any other location. It’s also possible to send the same Waveform to multiple motors, for example.
To send a Custom Waveform, you’ll need a reference to your IHandFeedbackDevice
, and to your SG_CustomWaveform
scriptableObject. You can use the example Script below:
1 2 3 4 5 6 7 8 9 10 11 12 | using UnityEngine;
public class SendCustomWaveForm : MonoBehaviour
{
public SG.SG_CustomWaveform vibration;
public SG.SG_TrackedHand sendToHand;
public void SendVibration()
{
sendToHand.SendCustomWaveform(vibration, vibration.intendedMotor);
}
}
|
Note that sending multiple waveforms each frame means only one of them will likely be sent!
Modulating Effects
With the current firmware implementation, it is not possible to modulate (change) an effect that is already playing on the glove. Every waveform that is sent to the glove causes a new vibration to be generated and played from the beginning.
Legacy Commands
Within the Unity Plugin, there is a ‘Legacy Waveform’ component called SG_Waveform
. This one allows you to define an ‘amplitude over time’ using an AnimationCurve, as well as an ‘amplitude’ and ‘duration in seconds’. These are compatible with the DK1.0 Exoskeleton and the Nova 1 glove, but not with the Nova 2.0.
We strongly advise you to use the SG_CustomWaveform
if needed.