Vizard 7 » Reference » Input Devices » Other devices » SensAble Haptic Devices
7.2.1

SensAble Haptic Devices

This plug-in provides support for SensAble haptic devices through the use of the OpenHaptics 2.0 or 3.0 toolkit.

Note: The OpenHaptics 2.0 version of the plug-in is not supported on 64-bit versions of Vizard

Initialization

The SensAble plug-in is implemented as a Vizard extension. In order to use the plug-in you must first install and license the OpenHaptics toolkit on your computer. The following table lists which sensable plug-in to use for the corresponding OpenHaptics version:

OpenHaptics version

Vizard plug-in

2.0

sensable.dle

3.0

sensable3.dle

If you do not have OpenHaptics installed on your system, you will receive the following error message when attempting to use the extension:

** ERROR: Failed to load plug-in: 'sensable.dle'

If OpenHaptics is installed, but not licensed, you will receive the following error message when attempting to connect to a haptic device:

** ERROR: Failed to connect to haptic device (The required license is invalid or missing.)

The SensAble extension object has the following methods/constants:

Method

Description

<sensable>.addHapticDevice(name='')

Connect to a haptic device with the specified name. If the name is empty or unspecified, then the default device will be connected to. This command returns a haptic device object (see below for more details).

<sensable>.TOUCH_EVENT

Event ID triggered when a haptic device touches a node. The event passes a single event structure e with the following attributes:

  • e.device: The haptic device that touched the node
  • e.node: The node that was touched by the device

<sensable>.UNTOUCH_EVENT

Event ID triggered when a haptic device stops touching a node. The event passes a single event structure e with the following attributes:

  • e.device: The haptic device that has stopped touching the node
  • e.node: The node that is no longer being touched by the device

<sensable>.EFFECT_LOCAL

<sensable>.EFFECT_GLOBAL

Constants for specifying the reference frame of effect position/direction properties.

<sensable>.BUTTON_1

<sensable>.BUTTON_2

<sensable>.BUTTON_INKWELL

<sensable>.BUTTON_SAFETY

Button IDs for various haptic device buttons.

The following table describes all the flags that can be used with the device enable/disable commands:

Flag

Description

<sensable>.FORCE_OUTPUT

Enables or disables force output for the device. All motors are turned on or off.

<sensable>.MAX_FORCE_CLAMPING

Enables or disables max force clamping for the device. If enabled, this will clamp the overall force output magnitude to the maximum achievable.

<sensable>.FORCE_RAMPING

Enables or disables force ramping, i.e. whether the device ramps up forces when the scheduler is turned on.

<sensable>.SOFTWARE_FORCE_LIMIT

Enables or disables the software maximum force check, which returns an error if the force magnitude commanded to the device exceeds the maximum force limit. This is primarily to disable force kicking. Disable this at your own risk!

<sensable>.SOFTWARE_VELOCITY_LIMIT

Enables or disables the software maximum velocity check, which returns an error if the velocity magnitude commanded to the device exceeds the maximum velocity limit. This is primarily to disable force kicking. Disable this at your own risk!

<sensable>.SOFTWARE_FORCE_IMPULSE_LIMIT

Enables or disables the software maximum force impulse check, which prevents changes in force impulse and direction that exceed the change of impulse limit. This is primarily to prevent device kicking. Disable this at your own risk!

<sensable>.ONE_FRAME_LIMIT

Enables or disables the one frame limit check, which restricts the application to one haptics frame per scheduler tick This should only be disabled if the developer is running his own scheduler.

<sensable>.USER_STATUS_LIGHT

Enables or disables user specified setting of the LED status light on the device.

The haptic device objects have the following methods in addition to the standard extension sensor methods:

Method

Description

<device>.workspace

A linkable object used for setting/getting the workspace transformation of the device.

<device>.addNode(node)

Add the specified node to the list of nodes that can be touched by the device. You can access the haptic properties of the node by using the node.haptics interface object of the node (see below for more details).

<device>.removeNode(node)

Remove the specified node from the list of nodes that can be touched by the device.

<device>.addConstantEffect( magnitude=None

                                       ,direction=None

                                       ,referenceFrame=None )

Adds a constant force vector to the total force sent to the haptic device. The direction property specifies the direction of the force vector. The magnitude property specifies the magnitude of the force vector. Returns a haptic effect object (see table below).

<device>.addSpringEffect( gain=None

                                   ,magnitude=None

                                   ,position=None

                                   ,referenceFrame=None )

Adds a spring force to the total force sent to the haptic device. The spring force pulls the haptic device towards the effect position and is proportional to the product of the gain and the distance between the effect position and the device position. Specifically, the spring force is calculated using the expression F = k(P-X) where F is the spring force, P is the effect position, X is the current haptic device position and k is the gain. The magnitude of the effect force is capped at the value of the magnitude property. Returns a haptic effect object (see table below).

<device>.addFrictionEffect( gain=None

                                     ,magnitude=None )

Adds a friction force to the total force sent to the haptic device. Unlike friction specified via haptic node settings, this is friction both while touching objects and in free space. The gain of the friction force is specified by the gain property. The magnitude of the effect force is capped at the value of the magnitude property. Returns a haptic effect object (see table below).

<device>.addViscousEffect( gain=None

                                     ,magnitude=None )

Adds a viscous force to the total force sent to the haptic device. The viscous force is based on the current velocity of the haptic device and is calculated to resist the motion of the haptic device. Specifically the force is calculated using the expression F = -kV where f is the spring force, V is the velocity and k is the gain. The magnitude of the effect force is capped at the value of the magnitude property. Returns a haptic effect object (see table below).

<device>.getTouchList()

Returns a list of nodes that are currently being touched by the device.

<device>.isTouching(node=None)

Returns True/False whether the device is currently touching the specified node. If node is None, then it returns whether the device is touching any nodes.

<device>.getForce()

Returns the [x,y,z] force vector currently being applied to the device. The vector is define in workspace coordinates.

<device>.enable(flag)

Enable a device capability. See table above for list of available flags.

<device>.disable(flag)

Disable a device capability. See table above for list of available flags.

<device>.getEnabled(flag)

Return whether a capability is enabled. See table above for list of available flags.

<device>.setVelocityLimit(value)

Set the software maximum velocity limit. This does not replace the hardware limit of the device. Units = mm/s

<device>.getVelocityLimit()

Get the software maximum velocity limit. This does not replace the hardware limit of the device. Units = mm/s

<device>.setForceImpulseLimit(value)

Sets the software maximum force impulse limit, which is the maximum change in magnitude and direction calculated by taking the difference between the current and last commanded force. Units = N

<device>.getForceImpulseLimit()

Get the software maximum force impulse limit. This does not replace the hardware limit of the device. Units = N

<device>.setForceRampingRate(value)

Set the force ramping rate, which is the rate that the device ramps up forces when the scheduler is started or after an error. Units = N/s

<device>.getForceRampingRate()

Get the force ramping rate, which is the rate that the device ramps up forces when the scheduler is started or after an error. Units = N/s

<device>.getMaxStiffness()

Get the maximum closed loop stiffness that is recommended for the device, i.e. the spring constant used in F=kx output where k is the spring constant and x is the spring length. Units = 0 to1

<device>.getMaxDamping()

Get the maximum level of damping that is recommended for the device, i.e. the damping constant used in F=kx-dv where d is the damping constant and v is the velocity of the device. Units = 0 to 1

<device>.getMaxForce()

Get the nominal maximum force, i.e. the amount of force that the device can sustain when the motors are at room temperature (optimal). Units = N

<device>.getMaxContinuousForce()

Get the nominal maximum continuous force, i.e. the amount of force that the device can sustain through a period of time. Units = N

<device>.getMotorTemperature()

Get the motor temperature, which is the predicted temperature of all of the motors. Units = 0 (coldest) to 1 (warmest)

<device>.getUpdateRate()

Get the average update rate of the device, i.e. the number of updates that the scheduler performs per second. Units = Hz

<device>.getInstantaneousUpdateRate()

Get the instantaneous update rate of the device, i.e. I/T where T is the time in seconds since the last update. Units = Hz

<device>.getFirmwareVersion()

Get the firmware revision number.

<device>.getVersion()

Get the HDAPI software version string, in the form of major.minor.build. This is taken from the HD_VERSION_ definitions.

<device>.getModelType()

Get a readable string of the device model type.

<device>.getDriverVersion()

Get a readable string of the driver version.

<device>.getVendor()

Get a readable string of the device vendor.

<device>.getSerialNumber()

Gets a readable string of the device serial number.

<device>.getMaxWorkspaceDimensions()

Get the maximum workspace dimensions of the device, i.e. the maximum mechanical limits of the device, as (minX, minY, minZ, maxX, maxY, maxZ). Units = mm

<device>.getUsableWorkspaceDimensions()

Get the usable workspace dimensions of the device, i.e. the practical limits for the device, as (minX, minY, minZ, maxX, maxY, maxZ). It is guaranteed that forces can be reliably rendered within the usable workspace dimensions. Units = mm

<device>.getTableTopOffset()

Get the mechanical offset of the device end-effector in Y from the table top. Units = mm

<device>.getInputDOF()

Get the number of input degrees of freedom. (i.e. the number of independent position variables needed to fully specify the end-effector location for PHANTOM device) 3DOF input means xyz translational sensing-only. 6DOF means 3 translation and 3 rotation.

<device>.getOutputDOF()

Get the number of output degrees of freedom, i.e. the number of independent actuation variable. For PHANTOM devices 3DOF means XYZ linear force output whereas 6DOF means xyz linear forces and roll, pitch, yaw, torques about gimbal.

When a node is added to a haptic device, it will be given a new attribute named haptics. This attribute provides the following methods for accessing the haptic properties of the node:

Method

Description

<node.haptics>.remove()

Remove the node from all haptic devices.

<node.haptics>.setEnabled(mode)

Sets whether haptics is enabled on the node. Can be True, False, or viz.TOGGLE. The default value is True.

<node.haptics>.getEnabled()

Returns True/False whether haptics is currently enabled on the node.

<node.haptics>.setDynamic(mode)

Notifies OpenHaptics whether the node mesh is dynamic and will be changing frequently. Can be True, False, or viz.TOGGLE. The default value is False.

<node.haptics>.getDynamic()

Returns True/False whether the node mesh is marked as dynamic.

<node.haptics>.dirtyMesh()

Mark the node mesh is dirty. This will cause Vizard to recompute the haptic mesh of the node during the next frame.

<node.haptics>.setStiffness(value)

Set the stiffness value of the haptic material. Must be a values between 0 and 1. Default is 0.8

<node.haptics>.getStiffness()

Returns the stiffness value of the haptic material.

<node.haptics>.setDamping(value)

Set the damping value of the haptic material. Must be a values between 0 and 1. Default is 0

<node.haptics>.getDamping()

Returns the damping value of the haptic material.

<node.haptics>.setStaticFriction(value)

Set the static friction value of the haptic material. Must be a values between 0 and 1. Default is 0

<node.haptics>.getStaticFriction()

Returns the static friction value of the haptic material.

<node.haptics>.setDynamicFriction(value)

Set the dynamic friction value of the haptic material. Must be a values between 0 and 1. Default is 0

<node.haptics>.getDynamicFriction()

Returns the dynamic friction value of the haptic material.

Haptic effect objects have the following methods:

Method

Description

<effect>.remove()

Remove the effect from the device.

<effect>.setGain(value)

Set the gain of the effect. Used by spring, friction and viscous effect types. Higher gains will cause these effects to generate larger forces. Default value is 0.

<effect>.getGain()

Return effect gain.

<effect>.setMagnitude(value)

Set the magnitude of the effect. Used by constant, spring, friction and viscous effect types. Represents a cap on the maximum force generated by these effects.Default value is 0.

<effect>.getGain()

Return effect magnitude.

<effect>.setPosition(value)

Set the position of the effect. Used by spring effect. Represents the anchor position of the spring. Default value is [0,0,0].

<effect>.getPosition()

Return effect position.

<effect>.setDirection(value)

Set the direction of the effect. Used by constant effect. Represents direction of constant force vector. Default value is [0,0,0].

<effect>.getDirection()

Return effect direction.

<effect>.setReferenceFrame(value)

Set the reference frame of the position and direction properties of the effect. <sensable>.EFFECT_GLOBAL will apply the values in global workspace coordinates. <sensable>.EFFECT_LOCAL will apply the values in the local device coordinates. The default reference frame is EFFECT_LOCAL.

<effect>.getReferenceFrame()

Return effect reference frame.

<effect>.setEnabled(value)

Enable/Disable the effect. Effects are disabled by default.

<effect>.getEnabled()

Return whether the effect is enabled.

<effect>.trigger(duration)

Trigger the effect for the specified number of seconds. The effect will only be terminated when the duration has elapsed. Disabling or removing an effect will NOT stop a triggered effect from finishing.

Example

The following example shows how to create the SensAble extension:

sensable = viz.add('sensable.dle')

The following example shows how to connect to the default haptic device, scale the workspace by 10, and link an object to the device:

#Add default device
device = sensable.addHapticDevice()
device.workspace.setScale([10,10,10])

#Link model to haptic device
marker = viz.add('marker.wrl')
viz.link(device,marker)

The next example shows how to add a node to the device and detect when the device has touch/untouched it:

#Add box to device
box = viz.add('box.wrl',pos=(0,2,-0.5))
device.addNode(box)

#Setup touch callbacks
def onHapticTouch(e):
    print('box is touched')
viz.callback(sensable.TOUCH_EVENT,onHapticTouch)

def onHapticUntouch(e):
    print('box is untouched')
viz.callback(sensable.UNTOUCH_EVENT,onHapticUntouch)

The next example shows how to change the material properties of a node:

#Set material properties of box
box.haptics.setStiffness(0.1)
box.haptics.setDamping(0.2)
box.haptics.setStaticFriction(0.3)
box.haptics.setDynamicFriction(0.4)
 

The following code shows how to use the standard sensor button events to detect when the buttons on the haptic pen are pressed/released:

#Setup button callbacks
def onSensorDown(e):
    print('Haptic button',e.button,'down')
viz.callback(viz.SENSOR_DOWN_EVENT,onSensorDown)

def onSensorUp(e):
    print('Haptic button',e.button,'up')
viz.callback(viz.SENSOR_UP_EVENT,onSensorUp)