mirror of
https://github.com/wassname/pyrobolearn.git
synced 2026-09-10 12:21:16 +08:00
add spacemouse interface + example (+add haptic skeleton code)
This commit is contained in:
@@ -12,5 +12,6 @@ Here are few examples that depict the various interfaces available to the user:
|
||||
5. `asus_xtion.py`: use the Asus Xtion interface
|
||||
6. `openpose.py`: use the Openpose interface
|
||||
7. `speech.py`: use the speech (recognizer/translator) interface
|
||||
8. `spacemouse.py`: use the (3Dconnexion) SpaceMouse interface
|
||||
|
||||
**Note**: some interfaces require to install different libraries, and possibly to configure them. Check the raised errors.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python
|
||||
"""Run the Space mouse interface.
|
||||
|
||||
Make sure that the `spnav` library is installed, and the space mouse (by 3Dconnexion) is connected to the computer
|
||||
before running this code.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import time
|
||||
|
||||
from pyrobolearn.tools.interfaces.mouse_keyboard.spacemouse import SpaceMouseInterface
|
||||
|
||||
|
||||
# create parser
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-t', '--use_thread', help='If we should run the webcam interface in a thread.', type=bool,
|
||||
default=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
# create webcam interface
|
||||
if args.use_thread:
|
||||
# create and run interface in a thread
|
||||
interface = SpaceMouseInterface(use_thread=True, sleep_dt=0.001, verbose=True)
|
||||
raw_input('Press key to stop the space mouse interface')
|
||||
else:
|
||||
# create interface
|
||||
interface = SpaceMouseInterface(use_thread=False, verbose=True)
|
||||
|
||||
while True:
|
||||
# perform a `step` with the interface
|
||||
interface.step()
|
||||
time.sleep(0.001)
|
||||
@@ -1,3 +1,6 @@
|
||||
"""PyRoboLearn: a Python framework in Robot Learning for Education and Research.
|
||||
"""
|
||||
|
||||
name = "pyrobolearn"
|
||||
|
||||
import sys
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the haptic interface.
|
||||
|
||||
Prerequisites:
|
||||
- follow instructions in [4] on how to install h3dapi.
|
||||
|
||||
Dependencies:
|
||||
- `pyrobolearn.tools.interfaces`
|
||||
|
||||
References:
|
||||
- [1] Haptic devices from Force Dimension: http://www.forcedimension.com/
|
||||
- [2] Haptic devices from 3D Systems: https://www.3dsystems.com/haptics-devices/openhaptics
|
||||
- [3] H3D API: https://h3dapi.org/
|
||||
- [4] H3D API - Documentation: https://www.h3dapi.org/modules/mediawiki/index.php/Main_Page
|
||||
- [6] H3D API - Github repo: https://github.com/SenseGraphics/h3dapi
|
||||
- [7] Haptic devices: https://www.h3dapi.org/modules/mediawiki/index.php/Haptics_devices
|
||||
"""
|
||||
|
||||
# TODO
|
||||
|
||||
# import H3DInterface as h3d
|
||||
|
||||
from pyrobolearn.tools.interfaces import InputOutputInterface
|
||||
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
__credits__ = ["Brian Delhaisse"]
|
||||
__license__ = "GNU GPLv3"
|
||||
__version__ = "1.0.0"
|
||||
__maintainer__ = "Brian Delhaisse"
|
||||
__email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class HapticInterface(InputOutputInterface):
|
||||
r"""Haptic Interface
|
||||
|
||||
Provide the haptic interface which, for instance, allows the user to interact with the world and the robots.
|
||||
|
||||
References:
|
||||
- [1] Haptic devices from Force Dimension: http://www.forcedimension.com/
|
||||
- [2] Haptic devices from 3D Systems: https://www.3dsystems.com/haptics-devices/openhaptics
|
||||
- [3] H3D API: https://h3dapi.org/
|
||||
- [4] H3D API - Documentation: https://www.h3dapi.org/modules/mediawiki/index.php/Main_Page
|
||||
- [6] H3D API - Github repo: https://github.com/SenseGraphics/h3dapi
|
||||
"""
|
||||
|
||||
def __init__(self, use_thread=False, sleep_dt=0., verbose=False):
|
||||
"""
|
||||
Initialize the SpaceMouse interface.
|
||||
|
||||
Args:
|
||||
use_thread (bool): If True, it will run the interface in a separate thread than the main one.
|
||||
The interface will update its data automatically.
|
||||
sleep_dt (float): If :attr:`use_thread` is True, it will sleep the specified amount before acquiring or
|
||||
setting the next sample.
|
||||
verbose (bool): If True, it will print information about the state of the interface. This is let to the
|
||||
programmer what he / she wishes to print.
|
||||
"""
|
||||
|
||||
# From [7]
|
||||
# root, = references.getValue()
|
||||
#
|
||||
# di = getActiveDeviceInfo()
|
||||
# if di:
|
||||
# hd = di.device.getValue()[0]
|
||||
|
||||
# available fields
|
||||
# hd.trackerPosition
|
||||
# hd.trackerOrientation
|
||||
# hd.mainButton
|
||||
# hd.secondaryButton
|
||||
|
||||
super(HapticInterface, self).__init__(use_thread=use_thread, sleep_dt=sleep_dt, verbose=verbose)
|
||||
|
||||
###########
|
||||
# Methods #
|
||||
###########
|
||||
|
||||
def run(self):
|
||||
"""Run the interface."""
|
||||
pass
|
||||
|
||||
|
||||
# Test the interface
|
||||
if __name__ == '__main__':
|
||||
pass
|
||||
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the space mouse (from 3D connexion) interface.
|
||||
|
||||
Prerequisites:
|
||||
1. install spacenavd (http://spacenav.sourceforge.net/): `sudo apt-get install spacenavd`
|
||||
2. install spnav (https://spnav.readthedocs.io/en/latest/): `pip install spnav`
|
||||
|
||||
Troubleshooting:
|
||||
- if you get 'OSError: libspnav.so: cannot open shared object file: No such file or directory', you have to copy-paste
|
||||
the file '/usr/lib/libspnav.so.0' to '/usr/lib/libspnav.so'
|
||||
|
||||
Dependencies:
|
||||
- `pyrobolearn.tools.interfaces`
|
||||
|
||||
References:
|
||||
- [1] SpaceMouse from 3D connexion: https://www.3dconnexion.com/products/spacemouse.html
|
||||
- [2] SpaceNav: http://spacenav.sourceforge.net/
|
||||
- [3] spnav: Space Navigator support in Python:
|
||||
- documentation: https://spnav.readthedocs.io/en/latest/
|
||||
- repository: https://bitbucket.org/seibert/spnav/src/default/
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
import spnav
|
||||
except ImportError as e:
|
||||
string = "\nHint: try to install `spnav` by typing: " \
|
||||
"\n`sudo apt-get install spacenavd`" \
|
||||
"\n`pip install spnav`"
|
||||
raise ImportError(e.__str__() + string)
|
||||
|
||||
|
||||
from pyrobolearn.tools.interfaces import InputInterface
|
||||
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
__credits__ = ["Brian Delhaisse"]
|
||||
__license__ = "GNU GPLv3"
|
||||
__version__ = "1.0.0"
|
||||
__maintainer__ = "Brian Delhaisse"
|
||||
__email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class SpaceMouseInterface(InputInterface):
|
||||
r"""Space Mouse Interface
|
||||
|
||||
Provide the space mouse interface which, for instance, allows the user to interact with the world and the robots
|
||||
using the space mouse (from 3D connexion).
|
||||
|
||||
Space mouse:
|
||||
* 2 buttons
|
||||
* 3 degrees of translation and 3 degrees of rotation
|
||||
|
||||
References:
|
||||
- [1] SpaceMouse from 3D connexion: https://www.3dconnexion.com/products/spacemouse.html
|
||||
- [2] SpaceNav: http://spacenav.sourceforge.net/
|
||||
- [3] spnav: Space Navigator support in Python:
|
||||
- documentation: https://spnav.readthedocs.io/en/latest/
|
||||
- repository: https://bitbucket.org/seibert/spnav/src/default/
|
||||
"""
|
||||
|
||||
def __init__(self, use_thread=False, sleep_dt=0., verbose=False, translation_range=(-1, 1),
|
||||
rotation_range=(-1, 1)):
|
||||
"""
|
||||
Initialize the SpaceMouse interface.
|
||||
|
||||
Args:
|
||||
use_thread (bool): If True, it will run the interface in a separate thread than the main one.
|
||||
The interface will update its data automatically.
|
||||
sleep_dt (float): If :attr:`use_thread` is True, it will sleep the specified amount before acquiring or
|
||||
setting the next sample.
|
||||
verbose (bool): If True, it will print information about the state of the interface. This is let to the
|
||||
programmer what he / she wishes to print.
|
||||
translation_range (np.array[2], np.array[2,3], tuple of 2 float, tuple of 2 np.array[3]): the lower and
|
||||
higher bounds for the (x, y, z). This is used to normalize the translation range to be between
|
||||
[-1, 1]. The frame (x,y,z) is defined with x pointing forward, y to the left, and z up.
|
||||
rotation_range (np.array[2], np.array[2,3], tuple of 2 float, tuple of 2 np.array[3]): the lower and higher
|
||||
bounds for the roll-pitch-yaw angles. This is used to normalize the rotation range to be between
|
||||
[-1, 1]. The frame (x,y,z) is defined with x pointing forward, y to the left, and z up.
|
||||
"""
|
||||
|
||||
# Open connection to the daemon via AF_UNIX socket.
|
||||
spnav.spnav_open()
|
||||
|
||||
# check the ranges and their shapes
|
||||
translation_range = np.abs(np.asarray(translation_range, dtype=np.float))
|
||||
rotation_range = np.abs(np.asarray(rotation_range, dtype=np.float))
|
||||
|
||||
if translation_range.shape != (2,) and translation_range.shape != (2, 3):
|
||||
raise ValueError("Expecting the shape of 'translation_range' to be (2,) or (2,3), instead got: "
|
||||
"{}".format(translation_range.shape))
|
||||
if rotation_range.shape != (2,) and rotation_range.shape != (2, 3):
|
||||
raise ValueError("Expecting the shape of 'rotation_range' to be (2,) or (2,3), instead got: "
|
||||
"{}".format(rotation_range.shape))
|
||||
|
||||
if translation_range.shape == (2,):
|
||||
translation_range = np.vstack([translation_range]*3).T
|
||||
if rotation_range.shape == (2,):
|
||||
rotation_range = np.vstack([rotation_range]*3).T
|
||||
|
||||
self.translation_range = translation_range
|
||||
self.rotation_range = rotation_range
|
||||
|
||||
# define space mouse events
|
||||
self.left_button_pressed = False
|
||||
self.right_button_pressed = False
|
||||
self.translation = np.zeros(3)
|
||||
self.rotation = np.zeros(3)
|
||||
self.updated = False
|
||||
|
||||
super(SpaceMouseInterface, self).__init__(use_thread=use_thread, sleep_dt=sleep_dt, verbose=verbose)
|
||||
|
||||
###########
|
||||
# Methods #
|
||||
###########
|
||||
|
||||
def run(self):
|
||||
"""Run the interface."""
|
||||
|
||||
# # Remove pending space navigator events from the queue
|
||||
# spnav.spnav_remove_events(spnav.SPNAV_EVENT_ANY)
|
||||
|
||||
# get space mouse event (without waiting)
|
||||
# event = spnav_wait_event() # blocking wait for the next event
|
||||
# try:
|
||||
event = spnav.spnav_poll_event()
|
||||
# except KeyboardInterrupt:
|
||||
# print '\nQuitting...'
|
||||
# finally:
|
||||
# self.close()
|
||||
|
||||
# check the event
|
||||
self.updated = True
|
||||
if isinstance(event, spnav.SpnavButtonEvent): # button event
|
||||
if event.bnum == 0: # left
|
||||
self.left_button_pressed = event.press
|
||||
elif event.bnum == 1: # right
|
||||
self.right_button_pressed = event.press
|
||||
elif isinstance(event, spnav.SpnavMotionEvent): # mouse motion event
|
||||
# translation
|
||||
x, y, z = event.translation # x, y, z in spnav
|
||||
self.translation = np.array([z, -x, y], dtype=np.float) # x (front), y (left), z (up)
|
||||
condition = self.translation < 0
|
||||
self.translation[condition] /= self.translation_range[0][condition]
|
||||
self.translation[~condition] /= self.translation_range[1][~condition]
|
||||
|
||||
# rotation
|
||||
r, p, y = event.rotation # r, p, y in spnav
|
||||
self.rotation = np.array([y, -r, p], dtype=np.float) # x (front), y (left), z (up)
|
||||
condition = self.rotation < 0
|
||||
self.rotation[condition] /= self.rotation_range[0][condition]
|
||||
self.rotation[~condition] /= self.rotation_range[1][~condition]
|
||||
else:
|
||||
self.updated = False
|
||||
|
||||
# if we should print the events
|
||||
if self.verbose and self.updated:
|
||||
print("Left and Right buttons: {} and {}".format(self.left_button_pressed, self.right_button_pressed))
|
||||
print("Space mouse translation and orientation: {} and {}".format(self.translation, self.rotation))
|
||||
|
||||
def close(self):
|
||||
"""Close the interface."""
|
||||
# spnav.spnav_close()
|
||||
if self.use_thread:
|
||||
self.stop_thread = True
|
||||
|
||||
|
||||
# Test the interface
|
||||
if __name__ == '__main__':
|
||||
import time
|
||||
from itertools import count
|
||||
|
||||
# create interface
|
||||
# interface = SpaceMouseInterface(verbose=True)
|
||||
interface = SpaceMouseInterface(verbose=True, translation_range=[[-410, -410, -430], [460, 400, 420]],
|
||||
rotation_range=[[-410., -420, -360], [410, 400, 410]])
|
||||
|
||||
for i in count():
|
||||
interface.step()
|
||||
# if i > 1e6:
|
||||
# print('closing the program')
|
||||
# interface.close()
|
||||
# break
|
||||
time.sleep(0.001)
|
||||
@@ -25,7 +25,7 @@ from pyrobolearn.tools.interfaces.vr import VRInterface
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
__credits__ = ["Brian Delhaisse"]
|
||||
__license__ = "MIT"
|
||||
__license__ = "GNU GPLv3"
|
||||
__version__ = "1.0.0"
|
||||
__maintainer__ = "Brian Delhaisse"
|
||||
__email__ = "briandelhaisse@gmail.com"
|
||||
|
||||
@@ -1,10 +1,53 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the main Virtual Reality (VR) interface class.
|
||||
|
||||
References:
|
||||
- steamvr: https://www.steamvr.com/en/
|
||||
- SteamVR on Linux:
|
||||
- https://github.com/ValveSoftware/SteamVR-for-Linux
|
||||
- https://www.cgl.ucsf.edu/chimera/data/linux-vr-oct2018/ubuntuvr.html
|
||||
- OpenVR (not open source):
|
||||
- Github repository: https://github.com/ValveSoftware/openvr
|
||||
- Documentation: https://github.com/ValveSoftware/openvr/wiki/API-Documentation
|
||||
- PyOpenVR:
|
||||
- Github repository: https://github.com/cmbruns/pyopenvr
|
||||
- OSVR
|
||||
- http://www.osvr.org/
|
||||
- https://osvr.github.io/doc/installing/linux/
|
||||
- Misc:
|
||||
- How to use the HTC Vive Trackers in Ubuntu using Python 3.6: https://gist.github.com/DanielArnett/c9a56c9c7cc0def20648480bca1f6772
|
||||
- https://github.com/osudrl/CassieVrControls/wiki/Tracking:-OpenVR-SDK
|
||||
|
||||
Log:
|
||||
$ sudo add-apt-repository multiverse
|
||||
$ sudo apt install steam
|
||||
$ sudo apt install steam-devices
|
||||
|
||||
* installing OSVR
|
||||
"""
|
||||
|
||||
# TODO
|
||||
|
||||
# import openvr
|
||||
|
||||
from pyrobolearn.tools.interfaces.interface import InputOutputInterface
|
||||
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
__credits__ = ["Brian Delhaisse"]
|
||||
__license__ = "GNU GPLv3"
|
||||
__version__ = "1.0.0"
|
||||
__maintainer__ = "Brian Delhaisse"
|
||||
__email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class VRInterface(InputOutputInterface):
|
||||
r"""Virtual Reality Interface
|
||||
|
||||
Virtual reality interface from which other VR interfaces (such as HTC, Oculus) inherit from.
|
||||
"""
|
||||
pass
|
||||
|
||||
def __init__(self, use_thread=False, sleep_dt=0., verbose=False):
|
||||
super(VRInterface, self).__init__(use_thread=use_thread, sleep_dt=sleep_dt, verbose=verbose)
|
||||
|
||||
Reference in New Issue
Block a user