Skip to main content
Version: 3.1.2

Haply Inverse Service

The Haply Inverse Service is a foundational component that integrates Haply's tactile devices with interactive applications, running as a background Windows service to enable real-time interactions. Its functionalities include:

  • Device Discovery and Management: Identifies and configures connected Haply devices automatically.
  • Ownership Management: Manages access to devices across multiple applications, ensuring smooth operation.
  • Real-Time State Streaming: Provides updates on device states at high frequencies for precise control.
  • Command Processing: Executes commands for force or position with high fidelity, enhancing the haptic feedback.
  • Background Operation: Runs in the background, maintaining device readiness without user intervention.

Run, stop, restart​

tip

Use the Haply Hub to easily manage the service and see the connected devices.

On Windows:

  • Open the Services desktop app: Press Windows+R to open the Run box, enter services.msc, and then press Enter or select OK.

On Ubuntu:

  • Start
    • systemctl start haply-inverse-service.service
  • Stop
    • systemctl stop haply-inverse-service.service
  • Enable
    • systemctl enable haply-inverse-service.service
  • Disable
    • systemctl disable haply-inverse-service.service

Important files​

On Windows:

  • The configuration files are located in: %PROGRAMDATA%\Haply\Inverse\*-config.json
  • The logs files are located in: %PROGRAMDATA%\Haply\Inverse\*-log.log

On Ubuntu:

  • The configuration files are located in: /etc/haply-inverse-service/*-config.json
  • The logs files are located in: /var/log/haply-inverse-service/*-log.log

On OSX:

  • The configuration files are located in: $TMPDIR/Haply/Inverse/*-config.json
  • The logs files are located in: $TMPDIR/Haply/Inverse/*-log.log

JSON Format Versions​

The service currently supports two different JSON formats: 3.0 and 3.1. Both versions are available concurrently, ensuring backward compatibility. If you are using the 3.0 format in your simulations, no changes are required and will continue to work as before. However, you are encouraged to update to the 3.1.x version to take advantage of its enhancements and improved performance for game engine integration.

Key Details​

  • 3.0 Version

    • Fully documented in the 3.0.x documentation pages.
    • HTTP accessible by default on http://localhost:10000/3.0.
    • Websockets accessible by default on port 10000.
  • 3.1 Version

    • Fully documented in the 3.1.x documentation pages.
    • HTTP accessible by default on http://localhost:10000/3.1.
    • Websockets accessible by default on port 10001.
    • Offers improvements in functionality and faster integration with game engines.

Feel free to upgrade to the 3.1 format at your convenience to leverage its benefits without any disruption to your existing workflows.

Interfaces​

Both the HTTP and Websocket interfaces use JSON formatted payloads.

info

When reading the position of the end-effector, you must also send a force value to the device (even if the force values are all zeros).

HTTP​

By default the HTTP service starts on: http://localhost:10000. Note: the port can be changed in the configuration.

Dashboard​

The dashboard is available at: http://localhost:10000

Version​

Method: GET

URL: http://localhost:10000/3.1/version

Response example:

{
"build_time": "2024-08-07T16:01:53Z",
"git_branch": "main",
"git_describe": "3.0.0-2-gce34c39e",
"git_hash": "ce34c39e",
"git_tag": "3.0.0",
"project_name": "haply-inverse-service",
"project_version": "3.0.0.0"
}

Devices​

Method: GET

URL: http://localhost:10000/3.1/devices

Response example:

{
"inverse3": [
{
"device_id": "04BA",
"config": {
"type": "inverse3",
"device_info": {
"minor_version": 1,
"major_version": 7,
"id": "04BA",
"device_type": 4,
"uuid": "2D35F80DD9005F599B68F49944CB04BA"
},
"port": "COM13",
"extended_device_id": "2D35F80DD9005F599B68F49944CB04BA",
"extended_firmware_version": "8C20FDC8010AA1E15AA133CDA2534874",
"gravity_compensation": {
"enabled": true,
"scaling_factor": 1
},
"handedness": "right",
"torque_scaling": {
"enabled": true
}
},
"state": {
"angular_position": {
"a0": -69.31704,
"a1": 137.62952,
"a2": 19.832787
},
"angular_velocity": {
"a0": 0,
"a1": 0,
"a2": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"mode": "idle"
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"config": {
"port": "COM3",
"type": "verse_grip"
},
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"config": {
"port": "COM6",
"type": "wireless_verse_grip"
},
"state": {
"battery_level": 0.42000008,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
}
},
"status": {
"ready": true
}
}
]
}

Force Scale​

Method: POST

URL: http://localhost:10000/3.1/force_scale

Body example:

{
"force_scale": 0.5
}

Response example:

{
"ok": true
}

Gravity Compensation​

Method: POST

URL: http://localhost:10000/3.1/gravity_compensation

Body example:

{
"device_id": "049D",
"enable": true,
"gravity_scaling_factor": 0.8
}

Response example:

{
"ok": true
}

Torque scaling​

Method: POST

URL: http://localhost:10000/3.1/torque_scaling

Body example:

{
"device_id": "049D",
"enable": true
}

Response example:

{
"ok": true
}

Device Handedness​

Method: POST

URL: http://localhost:10000/3.1/device_handedness

Body example:

{
"device_id": "049D",
"handedness": "right"
}

Response example:

{
"ok": true
}

Save Configuration​

Only works with Inverse3 devices. Warning: Avoid saving the configuration too often, since there is a limited number of save that can be applied to any given device.

Method: POST

URL: http://localhost:10000/3.1/save_configuration

Body example:

{
"device_id": "049D"
}

Response example:

{
"ok": true
}

Serial Enable​

Enable or disable all the serial communication. When the serial communication is disabled it is impossible to send commands to the devices.

Method: POST

URL: http://localhost:10000/3.1/serial_enable

Body example:

{
"enable": true
}

Response example:

{
"ok": true
}

Grip Vertical Stopper​

Enable or disable the grip vertical stopper experimental feature. This feature will check the wireless VerseGrip orientation to detect when the VerseGrip is dropped. When it triggers, it sets the Inverse3 into position control in its current position so that the end effector doesn't drop. It is disabled automatically when the VerseGrip is picked up again.

warning

As an experimental feature it is disabled by default and needs to be explicitly enabled to activate.

Method: POST

URL: http://localhost:10000/3.1/experimental/features/grip_dropped_simulation_stopper

Body example:

{
"enable": true,
"hall_effect_threshold": 17
}

Response example:

{
"ok": true
}

Websocket​

The default websocket URL is ws://localhost:10001. Note: the port can be changed in the configuration.

Initial Message​

The service sends a message containing the complete device list when a websocket is connected. The initial message has the following JSON format:

{
"inverse3": [
{
"device_id": "04BA",
"config": {
"type": "inverse3",
"device_info": {
"minor_version": 1,
"major_version": 7,
"id": "04BA",
"model": 4,
"uuid": ""
},
"port": "COM13",
"extended_device_id": "2D35F80DD9005F599B68F49944CB04BA",
"extended_firmware_version": "8C20FDC8010AA1E15AA133CDA2534874",
"gravity_compensation": {
"enabled": true,
"scaling_factor": 1
},
"handedness": "right",
"torque_scaling": {
"enabled": true
}
},
"state": {
"angular_position": {
"a0": -69.31704,
"a1": 137.62952,
"a2": 19.832787
},
"angular_velocity": {
"a0": 0,
"a1": 0,
"a2": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"mode": "idle"
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"config": {
"port": "COM3",
"type": "verse_grip"
},
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"config": {
"port": "COM6",
"type": "wireless_verse_grip"
},
"state": {
"battery_level": 0.42000008,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
}
},
"status": {
"ready": true
}
}
]
}

State Update Message​

The service will send one state update message containing the state of all devices for each command message received.

If you wish to know the state of the machine, you must send it a message beforehand, such as a force value (even if the values are zeros). This is particularly important if using our devices as an input device, such as tracking position and not applying force. The state update message has the following JSON format:

{
"inverse3": [
{
"device_id": "04BA",
"state": {
"angular_position": {
"a0": -69.31704,
"a1": 137.62952,
"a2": 19.832787
},
"angular_velocity": {
"a0": 0,
"a1": 0,
"a2": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"mode": "idle"
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"state": {
"battery_level": 0.42000008,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
}
},
"status": {
"ready": true
}
}
]
}

Command Message​

In order to send commands to the inverse3 the client has to send a command message. Here is an example:

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"values": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}

Also, it is possible to send commands to multiple devices in a single message. here is an example:

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"values": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
},
{
"device_id": "049E",
"commands": {
"set_cursor_force": {
"values": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}

The following commands are currently available on the inverse3:

Set Cursor Position​
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_position": {
"values": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}
Set Cursor Force​
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"values": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}
Set Angular Position​
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"values": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}
Set Angular Torque​
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_torque": {
"values": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}
Probing commands​

probe_cursor_position, probe_angular_position for the inverse3, and probe_orientation for verse grips all contains no command data.

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"probe_cursor_position": {},
"probe_angular_position": {}
}
}
],
"verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
],
"wireless_verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
]
}