mirror of
https://github.com/wassname/pyrobolearn.git
synced 2026-09-13 12:50:44 +08:00
add ROS related code (ongoing) + add speaker actuator/interface
This commit is contained in:
@@ -17,7 +17,8 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
# Butterworth Filter
|
||||
# Butterworth Filter: "The Butterworth filter is a type of signal processing filter designed to have a frequency
|
||||
# response as flat as possible in the passband." (Wikipedia: https://en.wikipedia.org/wiki/Butterworth_filter)
|
||||
# Example from http://scipy-cookbook.readthedocs.io/items/ButterworthBandpass.html
|
||||
def butter_bandpass(lowcut, highcut, fs, order=5):
|
||||
nyq = 0.5 * fs
|
||||
|
||||
@@ -5,7 +5,7 @@ This folder contains the various robots that can be used in the PRL framework. C
|
||||
```python
|
||||
import pyrobolearn as prl
|
||||
|
||||
sim = prl.simulators.BulletSim()
|
||||
sim = prl.simulators.Bullet()
|
||||
robot = prl.robots.<RobotClass>(sim)
|
||||
```
|
||||
|
||||
@@ -14,7 +14,7 @@ or
|
||||
```python
|
||||
import pyrobolearn as prl
|
||||
|
||||
sim = prl.simulators.BulletSim()
|
||||
sim = prl.simulators.Bullet()
|
||||
world = prl.worlds.BasicWorld(sim)
|
||||
robot = world.loadRobot(<Robot_name_or_robot_class>)
|
||||
```
|
||||
|
||||
@@ -6,8 +6,10 @@ import inspect
|
||||
|
||||
# General robot class
|
||||
from .base import Body, MovableBody, ControllableBody
|
||||
from .actuators import *
|
||||
from .sensors import *
|
||||
from . import actuators
|
||||
from . import sensors
|
||||
# from .actuators import *
|
||||
# from .sensors import *
|
||||
from .robot import Robot
|
||||
|
||||
# Categories/types of robots
|
||||
|
||||
@@ -4,3 +4,6 @@ from .actuator import Actuator
|
||||
|
||||
# import joint actuators
|
||||
from .joints import *
|
||||
|
||||
# import speaker
|
||||
from .speaker import Speaker
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the various actuators used in robotics.
|
||||
|
||||
This is decoupled from the robots such that actuators can be defined outside the robot class and can be selected at
|
||||
run-time. This is useful for instance when a version of the robot has specific joint motors while another version has
|
||||
other joint actuators. Additionally, this is important as more realistic motors can result in a better transfer from
|
||||
simulation to reality.
|
||||
"""
|
||||
|
||||
from pyrobolearn.robots.actuators import Actuator
|
||||
from pyrobolearn.utils.data_structures.queues import FIFOQueue
|
||||
import pyrobolearn as prl
|
||||
|
||||
|
||||
__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 Speaker(Actuator):
|
||||
r"""Speaker class
|
||||
"""
|
||||
|
||||
def __init__(self, capacity=1, check_same_text=False, verbose=False):
|
||||
"""
|
||||
Initialize the speaker actuator.
|
||||
|
||||
Args:
|
||||
capacity (int): maximum capacity of the queue. Every given text is appended to that queue. If set to 0,
|
||||
it will an infinite capacity.
|
||||
check_same_text (bool): if True, it will check that the same text is not being said twice.
|
||||
verbose (bool): if True, it will print the messages returned by the speaker interface.
|
||||
"""
|
||||
super(Speaker, self).__init__()
|
||||
self.queue = FIFOQueue(maxsize=int(capacity))
|
||||
self.check_same_text = bool(check_same_text)
|
||||
self.last_text = None
|
||||
self.interface = prl.tools.interfaces.audio.SpeakerInterface(use_thread=True, verbose=verbose)
|
||||
|
||||
###########
|
||||
# Methods #
|
||||
###########
|
||||
|
||||
def say(self, text=None):
|
||||
# if we have something to say, add it to the queue
|
||||
if text is not None:
|
||||
if not isinstance(text, str):
|
||||
raise TypeError("Expecting the 'given' text to be an instance of ")
|
||||
if not self.check_same_text or self.last_text != text:
|
||||
self.queue.append(text)
|
||||
|
||||
# if the interface is ready and we have something to say
|
||||
if not self.interface.updated and not self.queue.empty():
|
||||
data = self.queue.get()
|
||||
self.interface.data = data
|
||||
|
||||
def compute(self, text=None):
|
||||
self.say(text)
|
||||
|
||||
def __del__(self):
|
||||
self.interface.close()
|
||||
|
||||
|
||||
# Test the actuator
|
||||
if __name__ == '__main__':
|
||||
import time
|
||||
|
||||
speaker = Speaker(capacity=1)
|
||||
|
||||
speaker.say('Hello world!')
|
||||
speaker.say('My name is Boxy!')
|
||||
|
||||
for t in range(700):
|
||||
if t == 300:
|
||||
speaker.say('How are you today?')
|
||||
time.sleep(0.01)
|
||||
|
||||
# TODO: that should be automatic
|
||||
del speaker
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Atlas(BipedRobot, BiManipulatorRobot):
|
||||
class Atlas(BipedRobot, BiManipulator):
|
||||
r"""Atlas robot
|
||||
|
||||
Atlas robot developed by Boston Dynamics.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Baxter(BiManipulatorRobot):
|
||||
class Baxter(BiManipulator):
|
||||
r"""Baxter robot
|
||||
|
||||
Baxter robot built by Rethink Robotics.
|
||||
|
||||
@@ -24,6 +24,7 @@ class Blackbird(BipedRobot):
|
||||
|
||||
References:
|
||||
[1] https://hackaday.io/project/160882-blackbird-bipedal-robot
|
||||
[2] https://github.com/G-Levine
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
|
||||
@@ -7,7 +7,7 @@ import numpy as np
|
||||
|
||||
from pyrobolearn.robots.legged_robot import QuadrupedRobot
|
||||
from pyrobolearn.robots.wheeled_robot import WheeledRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -18,7 +18,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Centauro(WheeledRobot, QuadrupedRobot, BiManipulatorRobot):
|
||||
class Centauro(WheeledRobot, QuadrupedRobot, BiManipulator):
|
||||
r"""Centauro robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Cogimon(BipedRobot, BiManipulatorRobot):
|
||||
class Cogimon(BipedRobot, BiManipulator):
|
||||
r"""Cogimon humanoid robot.
|
||||
|
||||
References:
|
||||
|
||||
@@ -6,7 +6,7 @@ import os
|
||||
import numpy as np
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -17,7 +17,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Coman(BipedRobot, BiManipulatorRobot):
|
||||
class Coman(BipedRobot, BiManipulator):
|
||||
r"""Coman robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -6,7 +6,7 @@ import os
|
||||
import numpy as np
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -17,7 +17,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Darwin(BipedRobot, BiManipulatorRobot):
|
||||
class Darwin(BipedRobot, BiManipulator):
|
||||
r"""Darwin robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Edo(ManipulatorRobot):
|
||||
class Edo(Manipulator):
|
||||
r"""Edo robot
|
||||
|
||||
E.Do robot developed by Comau.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.wheeled_robot import WheeledRobot
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Fetch(WheeledRobot, ManipulatorRobot):
|
||||
class Fetch(WheeledRobot, Manipulator):
|
||||
r"""Fetch robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Franka(ManipulatorRobot):
|
||||
class Franka(Manipulator):
|
||||
r"""Franka Emika robot
|
||||
|
||||
WARNING: CURRENTLY, THE INERTIAL TAGS ARE NOT SET IN THE URDF!!
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
from pyrobolearn.robots.hand import TwoHand
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
@@ -17,7 +17,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Hubo(BipedRobot, BiManipulatorRobot, TwoHand):
|
||||
class Hubo(BipedRobot, BiManipulator, TwoHand):
|
||||
r"""Hubo robot
|
||||
|
||||
"The HUBO series of biped robots was developed by the Humanoid Robot Research Center at KAIST (Korea Advanced
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Humanoid(BipedRobot, BiManipulatorRobot):
|
||||
class Humanoid(BipedRobot, BiManipulator):
|
||||
r"""Humanoid Mujoco Model
|
||||
|
||||
References:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class ICub(BipedRobot, BiManipulatorRobot):
|
||||
class ICub(BipedRobot, BiManipulator):
|
||||
r"""ICub robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Jaco(ManipulatorRobot):
|
||||
class Jaco(Manipulator):
|
||||
r"""Jaco (manipulator) robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class KR5(ManipulatorRobot):
|
||||
class KR5(Manipulator):
|
||||
r"""Kuka KR5 sixx R650 robot
|
||||
|
||||
Payload of 5.00kg and a reach of 650mm or 850mm.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class KukaIIWA(ManipulatorRobot):
|
||||
class KukaIIWA(Manipulator):
|
||||
r"""Kuka IIWA robot
|
||||
|
||||
IIWA stands for 'Intelligent Industrial Work Assistant'. This robot has 7 DoFs, and an ATI F/T sensor at the
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class KukaLWR(ManipulatorRobot):
|
||||
class KukaLWR(Manipulator):
|
||||
r"""Kuka LWR robot
|
||||
|
||||
LWR stands for 'Light Weight Robot'. This robot has 7 DoFs, and an ATI F/T sensor at the end-effector.
|
||||
|
||||
@@ -14,7 +14,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class ManipulatorRobot(Robot):
|
||||
class Manipulator(Robot):
|
||||
r"""Manipulator robot
|
||||
|
||||
Manipulator robots are robots that use some of its end-effectors to manipulate objects in its environment.
|
||||
@@ -27,7 +27,7 @@ class ManipulatorRobot(Robot):
|
||||
orientation=(0, 0, 0, 1),
|
||||
fixed_base=False,
|
||||
scale=1.):
|
||||
super(ManipulatorRobot, self).__init__(simulator, urdf, position, orientation, fixed_base, scale)
|
||||
super(Manipulator, self).__init__(simulator, urdf, position, orientation, fixed_base, scale)
|
||||
|
||||
self.arms = [] # list of arms where an arm is a list of links
|
||||
self.hands = [] # list of end-effectors/hands
|
||||
@@ -117,7 +117,7 @@ class ManipulatorRobot(Robot):
|
||||
return self.hands
|
||||
|
||||
|
||||
class BiManipulatorRobot(ManipulatorRobot):
|
||||
class BiManipulator(Manipulator):
|
||||
r"""Bi-manipulator Robot
|
||||
|
||||
Bi-manipulators are robots that have two manipulators to manipulate objects in the environment.
|
||||
@@ -125,7 +125,7 @@ class BiManipulatorRobot(ManipulatorRobot):
|
||||
|
||||
def __init__(self, simulator, urdf, position=(0, 0, 1.5), orientation=(0, 0, 0, 1), fixed_base=False,
|
||||
scale=1.):
|
||||
super(BiManipulatorRobot, self).__init__(simulator, urdf, position, orientation, fixed_base, scale)
|
||||
super(BiManipulator, self).__init__(simulator, urdf, position, orientation, fixed_base, scale)
|
||||
|
||||
self.left_arm_id = 0
|
||||
self.left_hand_id = 0
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Manipulator2D(ManipulatorRobot):
|
||||
class Manipulator2D(Manipulator):
|
||||
r"""2D manipulator robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
from pyrobolearn.robots.hand import TwoHand
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
@@ -17,7 +17,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Nao(BipedRobot, BiManipulatorRobot, TwoHand):
|
||||
class Nao(BipedRobot, BiManipulator, TwoHand):
|
||||
r"""Nao robot
|
||||
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.wheeled_robot import WheeledRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
from pyrobolearn.robots.sensors.camera import CameraSensor
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
@@ -17,7 +17,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Pepper(WheeledRobot, BiManipulatorRobot):
|
||||
class Pepper(WheeledRobot, BiManipulator):
|
||||
r"""Pepper robot.
|
||||
|
||||
The Pepper robot is a robot from the Aldebaran company.
|
||||
|
||||
@@ -19,7 +19,8 @@ class PhantomX(HexapodRobot):
|
||||
r"""Phantom X Hexapod robot
|
||||
|
||||
References:
|
||||
[1] https://github.com/HumaRobotics/phantomx_description
|
||||
[1] https://www.trossenrobotics.com/phantomx-ax-hexapod.aspx
|
||||
[2] https://github.com/HumaRobotics/phantomx_description
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.wheeled_robot import WheeledRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class PR2(WheeledRobot, BiManipulatorRobot):
|
||||
class PR2(WheeledRobot, BiManipulator):
|
||||
r"""PR2 robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -55,7 +55,7 @@ class Robot(ControllableBody):
|
||||
"""
|
||||
# check parameters
|
||||
if position is None:
|
||||
position = (0., 0., 1.5)
|
||||
position = (0., 0., 0)
|
||||
if orientation is None:
|
||||
orientation = (0, 0, 0, 1)
|
||||
if fixed_base is None:
|
||||
|
||||
+24
-14
@@ -1,5 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the Coman subscriber.
|
||||
"""
|
||||
|
||||
import rospy
|
||||
#from std_msgs import msg as stdMsg
|
||||
# from std_msgs import msg as stdMsg
|
||||
from sensor_msgs import msg as senMsg
|
||||
from geometry_msgs import msg as geoMsg
|
||||
|
||||
@@ -7,14 +11,17 @@ import sys
|
||||
import numpy as np
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__email__ = "Brian.Delhaisse@iit.it"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
__credits__ = ["Brian Delhaisse"]
|
||||
__license__ = "GNU GPLv3"
|
||||
__version__ = "1.0.0"
|
||||
__date__ = "06/02/2017"
|
||||
__maintainer__ = "Brian Delhaisse"
|
||||
__email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
# ROS - Gazebo
|
||||
class ComanListener:
|
||||
class ComanSubscriber(object):
|
||||
"""
|
||||
ROS node that subscribes to topics to get the state of the coman.
|
||||
|
||||
@@ -25,25 +32,28 @@ class ComanListener:
|
||||
- cameras
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, robot_id=None):
|
||||
|
||||
rospy.init_node('ComanListener')
|
||||
if robot_id is None:
|
||||
rospy.init_node('ComanSubscriber', anonymous=True)
|
||||
else:
|
||||
rospy.init_node('ComanSubscriber' + str(robot_id))
|
||||
|
||||
### Joint States
|
||||
# Joint States
|
||||
self.sub_joints = rospy.Subscriber(
|
||||
"/coman/joint_states", senMsg.JointState, self.joints_callback)
|
||||
self.joints = None
|
||||
|
||||
### IMUs
|
||||
self.sub_imu1 = rospy.Subscriber(
|
||||
"/coman/sensor/IMU", senMsg.Imu, self.imu1_callback)
|
||||
self.imu1 = None
|
||||
# IMUs
|
||||
# self.sub_imu1 = rospy.Subscriber(
|
||||
# "/coman/sensor/IMU", senMsg.Imu, self.imu1_callback)
|
||||
# self.imu1 = None
|
||||
|
||||
# self.sub_imu2 = rospy.Subscriber(
|
||||
# "/coman/sensor/imu2", senMsg.Imu, self.imu2_callback)
|
||||
# self.imu2 = None
|
||||
|
||||
### Force-Torque sensors
|
||||
# Force-Torque sensors
|
||||
self.sub_ft_LForearm = rospy.Subscriber(
|
||||
"/coman/ft_sensor/LForearm", geoMsg.WrenchStamped, self.ft_LForearm_callback)
|
||||
self.ft_LForearm = None
|
||||
@@ -60,7 +70,7 @@ class ComanListener:
|
||||
"/coman/ft_sensor/RAnkle", geoMsg.WrenchStamped, self.ft_RAnkle_callback)
|
||||
self.ft_RAnkle = None
|
||||
|
||||
### Cameras
|
||||
# Cameras
|
||||
self.sub_camera_rgb = rospy.Subscriber(
|
||||
"/camera/rgb/image_raw", senMsg.Image, self.camera_rgb_callback)
|
||||
self.camera_rgb = None
|
||||
@@ -89,4 +99,4 @@ class ComanListener:
|
||||
|
||||
# rospy.loginfo("Running coman listener...")
|
||||
|
||||
# rospy.spin()
|
||||
# rospy.spin()
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the abstract robot publisher.
|
||||
"""
|
||||
|
||||
import rospy
|
||||
|
||||
# import the messages
|
||||
from std_msgs import msg as std_msg
|
||||
from sensor_msgs import msg as sensor_msg
|
||||
from geometry_msgs import msg as geometry_msg
|
||||
|
||||
|
||||
__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 PublisherData(object):
|
||||
r"""Publisher data holder
|
||||
"""
|
||||
|
||||
def __init__(self, topic, data_class, queue_size=10):
|
||||
self.__dict__['publisher'] = rospy.Publisher(topic, data_class, queue_size=queue_size)
|
||||
self.__dict__['attributes'] = [attr for attr in [attr for attr in dir(data_class) if not attr.startswith('_')]
|
||||
if not callable(getattr(data_class, attr))]
|
||||
self.__dict__['publisher_data'] = data_class()
|
||||
|
||||
def publish(self, data=None):
|
||||
if data is None:
|
||||
self.publisher.publish(self.publisher_data)
|
||||
else:
|
||||
self.publisher.publish(data)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
if key in self.attributes:
|
||||
setattr(self.publisher_data, key, value)
|
||||
|
||||
|
||||
class Publisher(object):
|
||||
r"""Publisher class
|
||||
|
||||
This Publisher abstract class is the class from which all the other publishers inherit from. It provides the
|
||||
common functionalities between the various publishers.
|
||||
"""
|
||||
|
||||
def __init__(self, publisher_id=None):
|
||||
"""
|
||||
Initialize the publisher.
|
||||
|
||||
Args:
|
||||
publisher_id (int, None): publisher id which is used when initializing the node. If None, a name will be
|
||||
auto-generated for the name using name as the base. See the documentation for the :attr:`anonymous`
|
||||
parameter in `rospy.init_node`.
|
||||
"""
|
||||
|
||||
# initialize the node
|
||||
if publisher_id is None:
|
||||
rospy.init_node(self.__class__.__name__, anonymous=True)
|
||||
else:
|
||||
rospy.init_node(self.__class__.__name__ + str(publisher_id))
|
||||
|
||||
# all publishers
|
||||
self.publishers = dict()
|
||||
|
||||
def create_publisher(self, name, topic, data_class):
|
||||
"""
|
||||
Create a publisher to the specific topic.
|
||||
|
||||
Args:
|
||||
name (str): unique name of the publisher. The name must be unique. You will be able to access to this
|
||||
topic (str): name of the topic.
|
||||
data_class (object): data type class to use for messages
|
||||
|
||||
Returns:
|
||||
PublisherData: the publisher data holder.
|
||||
"""
|
||||
publisher = PublisherData(topic, data_class)
|
||||
self.publishers[name] = publisher
|
||||
setattr(self, name, publisher)
|
||||
return publisher
|
||||
|
||||
def publish(self, name=None, data=None):
|
||||
if name is None and data is None:
|
||||
for publisher in self.publishers.values():
|
||||
publisher.publish()
|
||||
elif name is not None:
|
||||
self.name.publish(data)
|
||||
|
||||
# def __getattr__(self, name):
|
||||
# return self.publishers[name]
|
||||
|
||||
|
||||
class RobotPublisher(Publisher):
|
||||
r"""Robot Publisher class
|
||||
|
||||
This Robot Publisher class is the class from which all the robot publishers inherit from.
|
||||
"""
|
||||
|
||||
def __init__(self, name, id_=None):
|
||||
r"""
|
||||
Initialize the robot publisher.
|
||||
|
||||
Args:
|
||||
name (str): name of the robot. This will be used to create the topics.
|
||||
id_ (int, None): robot id which is used when initializing the node. If None, a name will be
|
||||
auto-generated for the name using name as the base. See the documentation for the :attr:`anonymous`
|
||||
parameter in `rospy.init_node`.
|
||||
"""
|
||||
super(RobotPublisher, self).__init__(publisher_id=id_)
|
||||
self.name = name.lower()
|
||||
|
||||
# create Joint states
|
||||
# self.create_publisher('joint_states', self.name + '/joint_states', sensor_msg.JointState)
|
||||
self.joint_states = PublisherData(self.name + '/joint_states', sensor_msg.JointState)
|
||||
self.publishers['joint_states'] = self.joint_states
|
||||
|
||||
def set_joint_positions(self, joint_ids, positions):
|
||||
self.joint_states.position[joint_ids] = positions
|
||||
|
||||
def set_joint_velocities(self, joint_ids, velocities):
|
||||
self.joint_states.velocity[joint_ids] = velocities
|
||||
|
||||
def set_joint_torques(self, joint_ids, torques):
|
||||
self.joint_states.effort[joint_ids] = torques
|
||||
|
||||
|
||||
# Tests
|
||||
if __name__ == '__main__':
|
||||
# NOTE: run roscore before hand
|
||||
import numpy as np
|
||||
import time
|
||||
|
||||
publisher = RobotPublisher('walter')
|
||||
print("Robot joint state attributes: {}".format(publisher.joint_states.attributes))
|
||||
|
||||
publisher.joint_states.position = np.array(range(3))
|
||||
|
||||
for t in range(20):
|
||||
publisher.publish()
|
||||
time.sleep(0.1)
|
||||
|
||||
print("Published topics: {}".format(rospy.get_published_topics()))
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the RRBot subscriber.
|
||||
"""
|
||||
|
||||
from pyrobolearn.robots.ros.subscriber import RobotSubscriber
|
||||
|
||||
|
||||
__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 RRBotSubscriber(RobotSubscriber):
|
||||
|
||||
def __init__(self, id_=None):
|
||||
"""
|
||||
Initialize the RRBot Subscriber.
|
||||
|
||||
Args:
|
||||
id_ (int, None): robot id which is used when initializing the node. If None, a name will be
|
||||
auto-generated for the name using name as the base. See the documentation for the :attr:`anonymous`
|
||||
parameter in `rospy.init_node`.
|
||||
"""
|
||||
super(RRBotSubscriber, self).__init__(name='rrbot', id_=id_)
|
||||
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the abstract robot subscriber.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import rospy
|
||||
|
||||
# import the messages
|
||||
# from std_msgs import msg as std_msg
|
||||
from sensor_msgs import msg as sensor_msg
|
||||
# from geometry_msgs import msg as geometry_msg
|
||||
|
||||
|
||||
__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 SubscriberData(object):
|
||||
r"""Subscriber data holder
|
||||
"""
|
||||
|
||||
def __init__(self, topic, data_class):
|
||||
self.subscriber = rospy.Subscriber(topic, data_class, callback=self.callback)
|
||||
self.attributes = set([attr for attr in [attr for attr in dir(data_class) if not attr.startswith('_')]
|
||||
if not callable(getattr(data_class, attr))])
|
||||
self.subscriber_data = None
|
||||
|
||||
def callback(self, data):
|
||||
self.subscriber_data = data
|
||||
|
||||
def __getattr__(self, name):
|
||||
if self.subscriber_data is not None:
|
||||
return getattr(self.subscriber_data, name, None)
|
||||
|
||||
def unregister(self):
|
||||
self.subscriber.unregister()
|
||||
|
||||
|
||||
class Subscriber(object):
|
||||
r"""Subscriber class
|
||||
|
||||
This Subscriber abstract class is the class from which all the other subscribers inherit from. It provides the
|
||||
common functionalities between the various subscribers.
|
||||
"""
|
||||
|
||||
def __init__(self, subscriber_id=None):
|
||||
"""
|
||||
Initialize the subscriber.
|
||||
|
||||
Args:
|
||||
subscriber_id (int, None): subscriber id which is used when initializing the node. If None, a name will be
|
||||
auto-generated for the name using name as the base. See the documentation for the :attr:`anonymous`
|
||||
parameter in `rospy.init_node`.
|
||||
"""
|
||||
|
||||
# initialize the node
|
||||
if subscriber_id is None:
|
||||
rospy.init_node(self.__class__.__name__, anonymous=True)
|
||||
else:
|
||||
rospy.init_node(self.__class__.__name__ + str(subscriber_id))
|
||||
|
||||
# all subscribers
|
||||
self.subscribers = dict()
|
||||
|
||||
def create_subscriber(self, name, topic, data_class):
|
||||
"""
|
||||
Create a subscriber to the specific topic.
|
||||
|
||||
Args:
|
||||
name (str): unique name of the subscriber. The name must be unique. You will be able to access to this
|
||||
topic (str): name of the topic.
|
||||
data_class (object): data type class to use for messages
|
||||
|
||||
Returns:
|
||||
SubscriberData: the subscriber data holder.
|
||||
"""
|
||||
subscriber = SubscriberData(topic, data_class)
|
||||
self.subscribers[name] = subscriber
|
||||
return subscriber
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self.subscribers[name]
|
||||
|
||||
def unregister(self, name=None):
|
||||
if name is None:
|
||||
for subscriber in self.subscribers.values():
|
||||
subscriber.unregister()
|
||||
else:
|
||||
self.subscribers[name].unregister()
|
||||
|
||||
def close(self):
|
||||
self.unregister()
|
||||
|
||||
def __del__(self):
|
||||
self.unregister()
|
||||
|
||||
|
||||
class RobotSubscriber(Subscriber):
|
||||
r"""Robot Subscriber class
|
||||
|
||||
This Robot Subscriber class is the class from which all the robot subscribers inherit from.
|
||||
"""
|
||||
|
||||
def __init__(self, name, id_=None):
|
||||
r"""
|
||||
Initialize the robot subscriber.
|
||||
|
||||
Args:
|
||||
name (str): name of the robot. This will be used to create the topics.
|
||||
id_ (int, None): robot id which is used when initializing the node. If None, a name will be
|
||||
auto-generated for the name using name as the base. See the documentation for the :attr:`anonymous`
|
||||
parameter in `rospy.init_node`.
|
||||
"""
|
||||
super(RobotSubscriber, self).__init__(subscriber_id=id_)
|
||||
self.name = name.lower()
|
||||
|
||||
# create Joint states
|
||||
self.create_subscriber('joint_states', self.name + '/joint_states', sensor_msg.JointState)
|
||||
|
||||
def get_joint_positions(self, joint_ids):
|
||||
return np.asarray(self.joint_states.position)[joint_ids]
|
||||
|
||||
def get_joint_velocities(self, joint_ids):
|
||||
return np.asarray(self.joint_states.velocity)[joint_ids]
|
||||
|
||||
def get_joint_torques(self, joint_ids):
|
||||
return np.asarray(self.joint_states.effort)[joint_ids]
|
||||
|
||||
|
||||
# Tests
|
||||
if __name__ == '__main__':
|
||||
# NOTE: run roscore before hand and don't forget to run the publisher code
|
||||
import time
|
||||
from itertools import count
|
||||
|
||||
subscriber = RobotSubscriber('walter')
|
||||
print("Published topics: {}".format(rospy.get_published_topics()))
|
||||
print("Robot joint state attributes: {}".format(subscriber.joint_states.attributes))
|
||||
|
||||
for t in range(100):
|
||||
print(t)
|
||||
print("Joint position data: {}".format(subscriber.joint_states.position))
|
||||
time.sleep(0.1)
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class RRBot(ManipulatorRobot):
|
||||
class RRBot(Manipulator):
|
||||
r"""RRBot
|
||||
|
||||
Note that in the URDF, the continuous joints were replace by revolute joints. Be careful, that the limit values
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.wheeled_robot import WheeledRobot
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -16,7 +16,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Sawyer(ManipulatorRobot, WheeledRobot):
|
||||
class Sawyer(Manipulator, WheeledRobot):
|
||||
r"""Sawyer robot
|
||||
|
||||
Sawyer robot built by Rethink Robotics.
|
||||
|
||||
@@ -76,6 +76,3 @@ Here is the list of repos where you can find the original URDF/meshes of each ro
|
||||
* Currently (Apr.25, 2018), pybullet sets a mass of 1 and an identity inertia to links which don't have an inertia tag defined in the urdf (see bullet3/examples/Importers/ImportURDFDemo/UrdfParser.cpp, line 991-997). This is not desirable, and as such, you should set a mass/inertia of zero to fake/dummy links which are connected by a **fixed** joint. For other links connected by other type of joints, sets a reasonable inertia matrix; an identity matrix is often unreasonable (see ["Adding Physical and Collision Properties to a URDF Model"](http://wiki.ros.org/urdf/Tutorials/Adding%20Physical%20and%20Collision%20Properties%20to%20a%20URDF%20Model)).
|
||||
* The first link (often called base_link/world_link) shouldn't have a mass/inertia of zero, this causes the robot to float in the air. Remove the corresponding tag from the urdf.
|
||||
* I do not own the rights to the URDFs (see the corresponding repo and their associated license). They are just regrouped here for convenience, and slightly updated to be used with pybullet. Each URDF has a pybullet robot class associated with it.
|
||||
|
||||
---> TODO: ADD IN EACH FOLDER THEIR CORRESPONDING LICENSE.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.legged_robot import BipedRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import BiManipulator
|
||||
from pyrobolearn.robots.sensors import CameraSensor
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
@@ -17,7 +17,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class Walkman(BipedRobot, BiManipulatorRobot):
|
||||
class Walkman(BipedRobot, BiManipulator):
|
||||
r"""Walk-man robot
|
||||
|
||||
The Walk-man robot is a humanoid robot developed at the Italian Institute of Technology (IIT) with ... degrees
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
__copyright__ = "Copyright 2018, PyRoboLearn"
|
||||
@@ -15,7 +15,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class WAM(ManipulatorRobot):
|
||||
class WAM(Manipulator):
|
||||
r"""Wam robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -7,7 +7,7 @@ These include: YoubotBase, KukaYoubotArm, Youbot, YoubotDualArm
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
from pyrobolearn.robots.manipulator import ManipulatorRobot, BiManipulatorRobot
|
||||
from pyrobolearn.robots.manipulator import Manipulator, BiManipulator
|
||||
from pyrobolearn.robots.wheeled_robot import DifferentialWheeledRobot
|
||||
|
||||
__author__ = "Brian Delhaisse"
|
||||
@@ -51,7 +51,7 @@ class YoubotBase(DifferentialWheeledRobot):
|
||||
# self.wheel_directions = np.ones(len(self.wheels))
|
||||
|
||||
|
||||
class KukaYoubotArm(ManipulatorRobot):
|
||||
class KukaYoubotArm(Manipulator):
|
||||
r"""Kuka Youbot arm robot
|
||||
|
||||
References:
|
||||
@@ -79,7 +79,7 @@ class KukaYoubotArm(ManipulatorRobot):
|
||||
self.name = 'kuka_youbot_arm'
|
||||
|
||||
|
||||
class Youbot(ManipulatorRobot, DifferentialWheeledRobot):
|
||||
class Youbot(Manipulator, DifferentialWheeledRobot):
|
||||
r"""Youbot robot
|
||||
|
||||
References:
|
||||
@@ -111,7 +111,7 @@ class Youbot(ManipulatorRobot, DifferentialWheeledRobot):
|
||||
# self.wheel_directions = np.ones(len(self.wheels))
|
||||
|
||||
|
||||
class YoubotDualArm(BiManipulatorRobot, DifferentialWheeledRobot):
|
||||
class YoubotDualArm(BiManipulator, DifferentialWheeledRobot):
|
||||
r"""Youbot dual arm robot
|
||||
|
||||
References:
|
||||
|
||||
@@ -16,18 +16,21 @@ Dependencies in PRL:
|
||||
* `pyrobolearn.simulators.ros.ROS`
|
||||
|
||||
References:
|
||||
[1] PyBullet: https://pybullet.org
|
||||
[2] PyBullet Quickstart Guide: https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA
|
||||
[3] ROS: http://www.ros.org/
|
||||
[4] PEP8: https://www.python.org/dev/peps/pep-0008/
|
||||
- [1] PyBullet: https://pybullet.org
|
||||
- [2] PyBullet Quickstart Guide: https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA
|
||||
- [3] ROS: http://www.ros.org/
|
||||
- [4] PEP8: https://www.python.org/dev/peps/pep-0008/
|
||||
"""
|
||||
|
||||
# TODO
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import psutil
|
||||
import signal
|
||||
import rospy
|
||||
|
||||
from pyrobolearn.simulators.simulator import Simulator
|
||||
# from pyrobolearn.simulators.bullet import Bullet
|
||||
# from pyrobolearn.simulators.simulator import Simulator
|
||||
from pyrobolearn.simulators.bullet import Bullet
|
||||
# from pyrobolearn.simulators.ros import ROS
|
||||
|
||||
|
||||
@@ -41,7 +44,7 @@ __email__ = "briandelhaisse@gmail.com"
|
||||
__status__ = "Development"
|
||||
|
||||
|
||||
class BulletROS(Simulator): # Bullet, ROS):
|
||||
class BulletROS(Bullet): # , ROS):
|
||||
r"""Bullet ROS
|
||||
|
||||
Update the Bullet simulator based on the real robot(s): it updates the robot kinematic and dynamic state based on
|
||||
@@ -51,6 +54,224 @@ class BulletROS(Simulator): # Bullet, ROS):
|
||||
sensors, actuators, and forces, to map the real world to the simulated one, etc.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(BulletROS, self).__init__()
|
||||
raise NotImplementedError
|
||||
def __init__(self, render=True, subscribe=False, publish=False, ros_master_uri=11311, **kwargs):
|
||||
"""
|
||||
Initialize the Bullet-ROS simulator.
|
||||
|
||||
Args:
|
||||
render (bool): if True, it will open the GUI, otherwise, it will just run the server.
|
||||
subscribe (bool): if True, it will subscribe to the topics associated to the loaded robots, and will read
|
||||
the values published on these topics.
|
||||
publish (bool): if True, it will publish the given values to the topics associated to the loaded robots.
|
||||
**kwargs (dict): optional arguments (this is not used here).
|
||||
"""
|
||||
super(BulletROS, self).__init__(render=render, **kwargs)
|
||||
|
||||
# Environment variable
|
||||
self.env = os.environ.copy()
|
||||
self.env["ROS_MASTER_URI"] = "http://localhost:" + str(ros_master_uri)
|
||||
|
||||
# this is for the rospy methods such as: wait_for_service(), init_node(), ...
|
||||
os.environ['ROS_MASTER_URI'] = self.env['ROS_MASTER_URI']
|
||||
|
||||
# run ROS core if not already running
|
||||
self.roscore = None
|
||||
if "roscore" not in [p.name() for p in psutil.process_iter()]:
|
||||
# subprocess.Popen("roscore", env=self.env)
|
||||
self.roscore = subprocess.Popen(["roscore", "-p", str(ros_master_uri)], env=self.env,
|
||||
preexec_fn=os.setsid) # , shell=True)
|
||||
|
||||
# set variables
|
||||
self.subscribe = subscribe
|
||||
self.publish = publish
|
||||
|
||||
# remember each publisher/subscriber
|
||||
self.subscribers = {}
|
||||
self.publishers = {}
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Close everything
|
||||
"""
|
||||
# delete each subscribers
|
||||
|
||||
# delete each publishers
|
||||
|
||||
# delete ROS
|
||||
os.killpg(os.getpgid(self.roscore.pid), signal.SIGTERM)
|
||||
|
||||
@property
|
||||
def is_subscribing(self):
|
||||
"""Return True if we are subscribing to topics."""
|
||||
return self.subscribe
|
||||
|
||||
@property
|
||||
def is_publishing(self):
|
||||
"""Return True if we are publishing to topics."""
|
||||
return self.publish
|
||||
|
||||
def load_urdf(self, filename, position=None, orientation=None, use_maximal_coordinates=None,
|
||||
use_fixed_base=None, flags=None, scale=None):
|
||||
"""Load the given URDF file.
|
||||
|
||||
The load_urdf will send a command to the physics server to load a physics model from a Universal Robot
|
||||
Description File (URDF). The URDF file is used by the ROS project (Robot Operating System) to describe robots
|
||||
and other objects, it was created by the WillowGarage and the Open Source Robotics Foundation (OSRF).
|
||||
Many robots have public URDF files, you can find a description and tutorial here:
|
||||
http://wiki.ros.org/urdf/Tutorials
|
||||
|
||||
Important note:
|
||||
most joints (slider, revolute, continuous) have motors enabled by default that prevent free
|
||||
motion. This is similar to a robot joint with a very high-friction harmonic drive. You should set the joint
|
||||
motor control mode and target settings using `pybullet.setJointMotorControl2`. See the
|
||||
`setJointMotorControl2` API for more information.
|
||||
|
||||
Warning:
|
||||
by default, PyBullet will cache some files to speed up loading. You can disable file caching using
|
||||
`setPhysicsEngineParameter(enableFileCaching=0)`.
|
||||
|
||||
Args:
|
||||
filename (str): a relative or absolute path to the URDF file on the file system of the physics server.
|
||||
position (vec3): create the base of the object at the specified position in world space coordinates [x,y,z]
|
||||
orientation (quat): create the base of the object at the specified orientation as world space quaternion
|
||||
[x,y,z,w]
|
||||
use_maximal_coordinates (int): Experimental. By default, the joints in the URDF file are created using the
|
||||
reduced coordinate method: the joints are simulated using the Featherstone Articulated Body algorithm
|
||||
(btMultiBody in Bullet 2.x). The useMaximalCoordinates option will create a 6 degree of freedom rigid
|
||||
body for each link, and constraints between those rigid bodies are used to model joints.
|
||||
use_fixed_base (bool): force the base of the loaded object to be static
|
||||
flags (int): URDF_USE_INERTIA_FROM_FILE (val=2): by default, Bullet recomputed the inertia tensor based on
|
||||
mass and volume of the collision shape. If you can provide more accurate inertia tensor, use this flag.
|
||||
URDF_USE_SELF_COLLISION (val=8): by default, Bullet disables self-collision. This flag let's you
|
||||
enable it.
|
||||
You can customize the self-collision behavior using the following flags:
|
||||
* URDF_USE_SELF_COLLISION_EXCLUDE_PARENT (val=16) will discard self-collision between links that
|
||||
are directly connected (parent and child).
|
||||
* URDF_USE_SELF_COLLISION_EXCLUDE_ALL_PARENTS (val=32) will discard self-collisions between a
|
||||
child link and any of its ancestors (parents, parents of parents, up to the base).
|
||||
* URDF_USE_IMPLICIT_CYLINDER (val=128), will use a smooth implicit cylinder. By default, Bullet
|
||||
will tessellate the cylinder into a convex hull.
|
||||
scale (float): scale factor to the URDF model.
|
||||
|
||||
Returns:
|
||||
int (non-negative): unique id associated to the load model.
|
||||
"""
|
||||
id_ = super(BulletROS, self).load_urdf(filename=filename, position=position, orientation=orientation,
|
||||
use_maximal_coordinates=use_maximal_coordinates,
|
||||
use_fixed_base=use_fixed_base, flags=flags, scale=scale)
|
||||
# get path to directory of urdf
|
||||
path = os.path.dirname(filename)
|
||||
robot_directory_name = path.split('/')[-1]
|
||||
path = path + '/../../ros/' + robot_directory_name + '/'
|
||||
|
||||
# check if valid robot directory
|
||||
|
||||
# load subscriber in simulator
|
||||
if self.subscribe:
|
||||
pass
|
||||
|
||||
# load publisher in simulator
|
||||
if self.publish:
|
||||
pass
|
||||
|
||||
return id_
|
||||
|
||||
def get_joint_positions(self, body_id, joint_ids):
|
||||
"""
|
||||
Get the position of the given joint(s).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
|
||||
Returns:
|
||||
if 1 joint:
|
||||
float: joint position [rad]
|
||||
if multiple joints:
|
||||
np.float[N]: joint positions [rad]
|
||||
"""
|
||||
if body_id in self.subscribers:
|
||||
q = self.subscribers[body_id].get_joint_positions[joint_ids]
|
||||
super(BulletROS, self).set_joint_positions(body_id=body_id, joint_ids=joint_ids, positions=q) # or reset?
|
||||
else:
|
||||
q = super(BulletROS, self).get_joint_positions(body_id=body_id, joint_ids=joint_ids)
|
||||
return q
|
||||
|
||||
def set_joint_positions(self, body_id, joint_ids, positions, velocities=None, kps=None, kds=None, forces=None):
|
||||
"""
|
||||
Set the position of the given joint(s) (using position control).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
positions (float, np.float[N]): desired position, or list of desired positions [rad]
|
||||
velocities (None, float, np.float[N]): desired velocity, or list of desired velocities [rad/s]
|
||||
kps (None, float, np.float[N]): position gain(s)
|
||||
kds (None, float, np.float[N]): velocity gain(s)
|
||||
forces (None, float, np.float[N]): maximum motor force(s)/torque(s) used to reach the target values.
|
||||
"""
|
||||
super(BulletROS, self).set_joint_positions(body_id, joint_ids, positions, velocities, kps, kds, forces)
|
||||
if body_id in self.publishers:
|
||||
self.publishers[body_id].set_joint_positions(joint_ids, positions)
|
||||
|
||||
def get_joint_velocities(self, body_id, joint_ids):
|
||||
"""
|
||||
Get the velocity of the given joint(s).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
|
||||
Returns:
|
||||
if 1 joint:
|
||||
float: joint velocity [rad/s]
|
||||
if multiple joints:
|
||||
np.float[N]: joint velocities [rad/s]
|
||||
"""
|
||||
pass
|
||||
|
||||
def set_joint_velocities(self, body_id, joint_ids, velocities, max_force=None):
|
||||
"""
|
||||
Set the velocity of the given joint(s) (using velocity control).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
velocities (float, np.float[N]): desired velocity, or list of desired velocities [rad/s]
|
||||
max_force (None, float, np.float[N]): maximum motor forces/torques
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_joint_torques(self, body_id, joint_ids):
|
||||
"""
|
||||
Get the applied torque(s) on the given joint(s). "This is the motor torque applied during the last `step`.
|
||||
Note that this only applies in VELOCITY_CONTROL and POSITION_CONTROL. If you use TORQUE_CONTROL then the
|
||||
applied joint motor torque is exactly what you provide, so there is no need to report it separately." [1]
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): a joint id, or list of joint ids.
|
||||
|
||||
Returns:
|
||||
if 1 joint:
|
||||
float: torque [Nm]
|
||||
if multiple joints:
|
||||
np.float[N]: torques associated to the given joints [Nm]
|
||||
"""
|
||||
pass
|
||||
|
||||
def set_joint_torques(self, body_id, joint_ids, torques):
|
||||
"""
|
||||
Set the torque/force to the given joint(s) (using force/torque control).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
torques (float, list of float): desired torque(s) to apply to the joint(s) [N].
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# Test
|
||||
if __name__ == '__main__':
|
||||
pass
|
||||
|
||||
@@ -17,6 +17,7 @@ References:
|
||||
"""
|
||||
|
||||
# TODO
|
||||
# import mujoco_py as mujoco
|
||||
|
||||
from pyrobolearn.simulators.simulator import Simulator
|
||||
|
||||
|
||||
+180
-12
@@ -50,17 +50,185 @@ class ROS(Simulator):
|
||||
r"""ROS Interface
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(ROS, self).__init__()
|
||||
def __init__(self, subscribe=False, publish=False, master_uri=11311, **kwargs):
|
||||
super(ROS, self).__init__(render=False)
|
||||
|
||||
# Environment variable
|
||||
self.env = os.environ.copy()
|
||||
self.env["ROS_MASTER_URI"] = "http://localhost:" + str(ros_master_uri)
|
||||
|
||||
# this is for the rospy methods such as: wait_for_service(), init_node(), ...
|
||||
os.environ['ROS_MASTER_URI'] = self.env['ROS_MASTER_URI']
|
||||
|
||||
# run ROS core if not already running
|
||||
self.roscore = None
|
||||
if "roscore" not in [p.name() for p in psutil.process_iter()]:
|
||||
# subprocess.Popen("roscore", env=self.env)
|
||||
self.roscore = subprocess.Popen(["roscore", "-p", str(ros_master_uri)], env=self.env,
|
||||
preexec_fn=os.setsid) # , shell=True)
|
||||
|
||||
# set variables
|
||||
self.subscribe = subscribe
|
||||
self.publish = publish
|
||||
|
||||
# remember each publisher/subscriber
|
||||
self.subscribers = {}
|
||||
self.publishers = {}
|
||||
self.models = []
|
||||
|
||||
# def load_urdf(self, filename, position=None, orientation=None):
|
||||
# # load URDF: get ros services and ros topics
|
||||
# model = ROSModel(filename)
|
||||
#
|
||||
# # create id and add model to the list of models
|
||||
# idx = len(self.models)
|
||||
# self.models.append(model)
|
||||
#
|
||||
# # return id
|
||||
# return idx
|
||||
self.count_id = -1
|
||||
|
||||
def load_urdf(self, filename, position=None, orientation=None, use_maximal_coordinates=None,
|
||||
use_fixed_base=None, flags=None, scale=None):
|
||||
"""Load the given URDF file.
|
||||
|
||||
The load_urdf will send a command to the physics server to load a physics model from a Universal Robot
|
||||
Description File (URDF). The URDF file is used by the ROS project (Robot Operating System) to describe robots
|
||||
and other objects, it was created by the WillowGarage and the Open Source Robotics Foundation (OSRF).
|
||||
Many robots have public URDF files, you can find a description and tutorial here:
|
||||
http://wiki.ros.org/urdf/Tutorials
|
||||
|
||||
Important note:
|
||||
most joints (slider, revolute, continuous) have motors enabled by default that prevent free
|
||||
motion. This is similar to a robot joint with a very high-friction harmonic drive. You should set the joint
|
||||
motor control mode and target settings using `pybullet.setJointMotorControl2`. See the
|
||||
`setJointMotorControl2` API for more information.
|
||||
|
||||
Warning:
|
||||
by default, PyBullet will cache some files to speed up loading. You can disable file caching using
|
||||
`setPhysicsEngineParameter(enableFileCaching=0)`.
|
||||
|
||||
Args:
|
||||
filename (str): a relative or absolute path to the URDF file on the file system of the physics server.
|
||||
position (vec3): create the base of the object at the specified position in world space coordinates [x,y,z]
|
||||
orientation (quat): create the base of the object at the specified orientation as world space quaternion
|
||||
[x,y,z,w]
|
||||
use_maximal_coordinates (int): Experimental. By default, the joints in the URDF file are created using the
|
||||
reduced coordinate method: the joints are simulated using the Featherstone Articulated Body algorithm
|
||||
(btMultiBody in Bullet 2.x). The useMaximalCoordinates option will create a 6 degree of freedom rigid
|
||||
body for each link, and constraints between those rigid bodies are used to model joints.
|
||||
use_fixed_base (bool): force the base of the loaded object to be static
|
||||
flags (int): URDF_USE_INERTIA_FROM_FILE (val=2): by default, Bullet recomputed the inertia tensor based on
|
||||
mass and volume of the collision shape. If you can provide more accurate inertia tensor, use this flag.
|
||||
URDF_USE_SELF_COLLISION (val=8): by default, Bullet disables self-collision. This flag let's you
|
||||
enable it.
|
||||
You can customize the self-collision behavior using the following flags:
|
||||
* URDF_USE_SELF_COLLISION_EXCLUDE_PARENT (val=16) will discard self-collision between links that
|
||||
are directly connected (parent and child).
|
||||
* URDF_USE_SELF_COLLISION_EXCLUDE_ALL_PARENTS (val=32) will discard self-collisions between a
|
||||
child link and any of its ancestors (parents, parents of parents, up to the base).
|
||||
* URDF_USE_IMPLICIT_CYLINDER (val=128), will use a smooth implicit cylinder. By default, Bullet
|
||||
will tessellate the cylinder into a convex hull.
|
||||
scale (float): scale factor to the URDF model.
|
||||
|
||||
Returns:
|
||||
int (non-negative): unique id associated to the load model.
|
||||
"""
|
||||
# get path to directory of urdf
|
||||
path = os.path.dirname(filename)
|
||||
robot_directory_name = path.split('/')[-1]
|
||||
path = path + '/../../ros/' + robot_directory_name + '/'
|
||||
|
||||
# check if valid robot directory
|
||||
|
||||
# load subscriber in simulator
|
||||
if self.subscribe:
|
||||
pass
|
||||
|
||||
# load publisher in simulator
|
||||
if self.publish:
|
||||
pass
|
||||
|
||||
self.count_id += 1
|
||||
|
||||
return self.count_id
|
||||
|
||||
def get_joint_positions(self, body_id, joint_ids):
|
||||
"""
|
||||
Get the position of the given joint(s).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
|
||||
Returns:
|
||||
if 1 joint:
|
||||
float: joint position [rad]
|
||||
if multiple joints:
|
||||
np.float[N]: joint positions [rad]
|
||||
"""
|
||||
if body_id in self.subscribers:
|
||||
return self.subscribers[body_id].get_joint_positions[joint_ids]
|
||||
|
||||
def set_joint_positions(self, body_id, joint_ids, positions, velocities=None, kps=None, kds=None, forces=None):
|
||||
"""
|
||||
Set the position of the given joint(s) (using position control).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
positions (float, np.float[N]): desired position, or list of desired positions [rad]
|
||||
velocities (None, float, np.float[N]): desired velocity, or list of desired velocities [rad/s]
|
||||
kps (None, float, np.float[N]): position gain(s)
|
||||
kds (None, float, np.float[N]): velocity gain(s)
|
||||
forces (None, float, np.float[N]): maximum motor force(s)/torque(s) used to reach the target values.
|
||||
"""
|
||||
if body_id in self.publishers:
|
||||
self.publishers[body_id].set_joint_positions(joint_ids, positions)
|
||||
|
||||
def get_joint_velocities(self, body_id, joint_ids):
|
||||
"""
|
||||
Get the velocity of the given joint(s).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
|
||||
Returns:
|
||||
if 1 joint:
|
||||
float: joint velocity [rad/s]
|
||||
if multiple joints:
|
||||
np.float[N]: joint velocities [rad/s]
|
||||
"""
|
||||
pass
|
||||
|
||||
def set_joint_velocities(self, body_id, joint_ids, velocities, max_force=None):
|
||||
"""
|
||||
Set the velocity of the given joint(s) (using velocity control).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
velocities (float, np.float[N]): desired velocity, or list of desired velocities [rad/s]
|
||||
max_force (None, float, np.float[N]): maximum motor forces/torques
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_joint_torques(self, body_id, joint_ids):
|
||||
"""
|
||||
Get the applied torque(s) on the given joint(s). "This is the motor torque applied during the last `step`.
|
||||
Note that this only applies in VELOCITY_CONTROL and POSITION_CONTROL. If you use TORQUE_CONTROL then the
|
||||
applied joint motor torque is exactly what you provide, so there is no need to report it separately." [1]
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): a joint id, or list of joint ids.
|
||||
|
||||
Returns:
|
||||
if 1 joint:
|
||||
float: torque [Nm]
|
||||
if multiple joints:
|
||||
np.float[N]: torques associated to the given joints [Nm]
|
||||
"""
|
||||
pass
|
||||
|
||||
def set_joint_torques(self, body_id, joint_ids, torques):
|
||||
"""
|
||||
Set the torque/force to the given joint(s) (using force/torque control).
|
||||
|
||||
Args:
|
||||
body_id (int): unique body id.
|
||||
joint_ids (int, list of int): joint id, or list of joint ids.
|
||||
torques (float, list of float): desired torque(s) to apply to the joint(s) [N].
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
# import audio interfaces
|
||||
# from audio import *
|
||||
# from .audio import *
|
||||
# from . import audio
|
||||
|
||||
from .speaker import SpeakerInterface
|
||||
|
||||
@@ -1,8 +1,93 @@
|
||||
#!/usr/bin/env python
|
||||
"""Define the speaker audio interface.
|
||||
"""
|
||||
|
||||
from pyrobolearn.tools.interfaces.audio import OutputAudioInterface
|
||||
import os
|
||||
|
||||
# Speech synthesis
|
||||
# Good tutorial: https://pythonprogramminglanguage.com/text-to-speech/
|
||||
# If Python3.3 or higher: https://pypi.org/project/google_speech/
|
||||
try:
|
||||
from gtts import gTTS
|
||||
except ImportError as e:
|
||||
string = "\nHint: try to install gTTS by typing: `pip install gTTS`." \
|
||||
"Also install `mpg321` using `sudo apt-get install mpg321`."
|
||||
raise ImportError(e.__str__() + string)
|
||||
|
||||
from pyrobolearn.tools.interfaces import OutputInterface
|
||||
|
||||
|
||||
class SpeakerInterface(OutputAudioInterface):
|
||||
r"""Speaker Interface
|
||||
__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 SpeakerInterface(OutputInterface):
|
||||
r"""Speech Synthesizer Interface
|
||||
|
||||
References:
|
||||
[1] tutorial: https://pythonprogramminglanguage.com/text-to-speech/
|
||||
[2] If Python3.3 or higher: https://pypi.org/project/google_speech/
|
||||
"""
|
||||
pass
|
||||
|
||||
available_languages = {'french', 'english', 'american english', 'british english', 'indian english', 'italian',
|
||||
'japanese', 'korean', 'german', 'dutch', 'spanish', 'spanish (peru)', 'chinese',
|
||||
'mandarin', 'polish', 'portuguese', 'russian', 'greek'}
|
||||
|
||||
def __init__(self, use_thread=False, lang='english', verbose=False):
|
||||
"""
|
||||
Initialize the speech synthesizer output 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.
|
||||
lang (str): language to recognize
|
||||
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.
|
||||
"""
|
||||
languages = {'french': 'fr', 'english': 'en', 'american english': 'en-US', 'british english': 'en-GB',
|
||||
'indian english': 'en-IN', 'italian': 'it', 'japanese': 'ja', 'korean': 'ko', 'german': 'de',
|
||||
'dutch': 'nl', 'spanish': 'es', 'spanish (peru)': 'es-PE', 'chinese': 'zh-CN',
|
||||
'mandarin': 'zh-CN', 'polish': 'pl', 'portuguese': 'pt', 'russian': 'ru', 'greek': 'el-GR'}
|
||||
# Check < https://gist.github.com/traysr/2001377 > for more
|
||||
self.lang = languages[lang]
|
||||
|
||||
self.updated = False
|
||||
self._data = ''
|
||||
|
||||
super(SpeakerInterface, self).__init__(use_thread=use_thread, verbose=verbose)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._data
|
||||
|
||||
@data.setter
|
||||
def data(self, data):
|
||||
if isinstance(data, (str, unicode)):
|
||||
self._data = data
|
||||
self.updated = True
|
||||
|
||||
def run(self):
|
||||
"""Run the interface."""
|
||||
if self.updated:
|
||||
if self.verbose:
|
||||
print("Generating speech...")
|
||||
# tts = text-to-speech
|
||||
tts = gTTS(text=self.data, lang=self.lang)
|
||||
tts.save('tmp.mp3')
|
||||
os.system('mpg321 tmp.mp3 > /dev/null 2>&1') # TODO: use subprocess instead
|
||||
os.system('rm tmp.mp3')
|
||||
# subprocess.call(['mpg321 tmp.mp3'])
|
||||
# subprocess.call(['rm tmp.mp3'])
|
||||
self.updated = False
|
||||
print("Speech generated!")
|
||||
return self.data
|
||||
|
||||
def update(self, data):
|
||||
"""Update the data."""
|
||||
self.data = data
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# To run the code `H3DLoad
|
||||
|
||||
import H3DInterface as h3d
|
||||
|
||||
|
||||
# print(dir(h3d))
|
||||
# ['AutoUpdate', 'Console', 'Field', 'H3DConsole', 'INITIALIZE_ONLY', 'INPUT_ONLY', 'INPUT_OUTPUT', 'LogLevel',
|
||||
# 'MFBOOL', 'MFBool', 'MFCOLOR', 'MFCOLORRGBA', 'MFColor', 'MFColorRGBA', 'MFDOUBLE', 'MFDouble', 'MFFLOAT',
|
||||
# 'MFFloat', 'MFINT32', 'MFInt32', 'MFMATRIX3D', 'MFMATRIX3F', 'MFMATRIX4D', 'MFMATRIX4F', 'MFMatrix3d',
|
||||
# 'MFMatrix3f', 'MFMatrix4d', 'MFMatrix4f', 'MFNODE', 'MFNode', 'MFQUATERNION', 'MFQuaternion', 'MFROTATION',
|
||||
# 'MFRotation', 'MFSTRING', 'MFString', 'MFTIME', 'MFTime', 'MFVEC2D', 'MFVEC2F', 'MFVEC3D', 'MFVEC3F', 'MFVEC4D',
|
||||
# 'MFVEC4F', 'MFVec2d', 'MFVec2f', 'MFVec3d', 'MFVec3f', 'MFVec4d', 'MFVec4f', 'MField', 'MFieldBack', 'MFieldClear',
|
||||
# 'MFieldEmpty', 'MFieldErase', 'MFieldFront', 'MFieldPopBack', 'MFieldPushBack', 'MFieldSize', 'Matrix3d',
|
||||
# 'Matrix3f', 'Matrix4d', 'Matrix4f', 'Node', 'OUTPUT_ONLY', 'PeriodicUpdate', 'Quaternion', 'RGB', 'RGBA',
|
||||
# 'Rotation', 'SFBOOL', 'SFBool', 'SFCOLOR', 'SFCOLORRGBA', 'SFColor', 'SFColorRGBA', 'SFDOUBLE', 'SFDouble',
|
||||
# 'SFFLOAT', 'SFFloat', 'SFINT32', 'SFInt32', 'SFMATRIX3D', 'SFMATRIX3F', 'SFMATRIX4D', 'SFMATRIX4F', 'SFMatrix3d',
|
||||
# 'SFMatrix3f', 'SFMatrix4d', 'SFMatrix4f', 'SFNODE', 'SFNode', 'SFQUATERNION', 'SFQuaternion', 'SFROTATION',
|
||||
# 'SFRotation', 'SFSTRING', 'SFString', 'SFStringGetValidValues', 'SFStringIsValidValue', 'SFTIME', 'SFTime',
|
||||
# 'SFVEC2D', 'SFVEC2F', 'SFVEC3D', 'SFVEC3F', 'SFVEC4D', 'SFVEC4F', 'SFVec2d', 'SFVec2f', 'SFVec3d', 'SFVec3f',
|
||||
# 'SFVec4d', 'SFVec4f', 'SField', 'TypedField', 'UNKNOWN_X3D_TYPE', 'Vec2d', 'Vec2f', 'Vec3d', 'Vec3f', 'Vec4d',
|
||||
# 'Vec4f', '_ConsoleStderr', '_ConsoleStdout', '__builtins__', '__doc__', '__name__', '__package__',
|
||||
# 'addProgramSetting', 'addURNResolveRule', 'auto_update_classes', 'createField', 'createNode',
|
||||
# 'createVRMLFromString', 'createVRMLFromURL', 'createVRMLNodeFromString', 'createVRMLNodeFromURL',
|
||||
# 'createX3DFromString', 'createX3DFromURL', 'createX3DNodeFromString', 'createX3DNodeFromURL', 'eventSink',
|
||||
# 'exportGeometryAsSTL', 'fieldGetAccessType', 'fieldGetFullName', 'fieldGetName', 'fieldGetOwner',
|
||||
# 'fieldGetRoutesIn', 'fieldGetRoutesOut', 'fieldGetTypeName', 'fieldGetValue', 'fieldGetValueAsString',
|
||||
# 'fieldHasRouteFrom', 'fieldIsAccessCheckOn', 'fieldIsUpToDate', 'fieldReplaceRoute', 'fieldReplaceRouteNoEvent',
|
||||
# 'fieldRoute', 'fieldRouteNoEvent', 'fieldRoutesTo', 'fieldSetAccessCheck', 'fieldSetAccessType', 'fieldSetName',
|
||||
# 'fieldSetOwner', 'fieldSetValue', 'fieldSetValueFromString', 'fieldTouch', 'fieldUnroute', 'fieldUnrouteAll',
|
||||
# 'fieldUpToDate', 'findNodes', 'getActiveBackground', 'getActiveBindableNode', 'getActiveDeviceInfo', 'getActiveFog',
|
||||
# 'getActiveGlobalSettings', 'getActiveNavigationInfo', 'getActiveStereoInfo', 'getActiveViewpoint', 'getCPtr',
|
||||
# 'getCurrentScenes', 'getHapticsDevice', 'getNamedNode', 'getNrHapticsDevices', 'log', 'mfield_types',
|
||||
# 'periodic_update_classes', 'resolveURLAsFile', 'resolveURLAsFolder', 'sfield_types', 'sys', 't',
|
||||
# 'takeScreenshot', 'throwQuitAPIException', 'time', 'typed_field_classes', 'writeNodeAsX3D']
|
||||
|
||||
|
||||
num_devices = h3d.getNrHapticsDevices()
|
||||
print("Number of devices: {}".format(num_devices))
|
||||
|
||||
device = None
|
||||
info = h3d.getActiveDeviceInfo()
|
||||
if info:
|
||||
device = info.device.getValue()[0]
|
||||
|
||||
if device is not None:
|
||||
print(device.trackerPosition)
|
||||
print(device.trackerOrientation)
|
||||
print(device.mainButton)
|
||||
print(device.secondaryButton)
|
||||
@@ -3,6 +3,13 @@
|
||||
|
||||
Prerequisites:
|
||||
- follow instructions in [4] on how to install h3dapi.
|
||||
- To use the Python library, you have to run `H3DLoad <file>.x3d` where in the `<file>.x3d` you make a reference to
|
||||
the Python script you want to run. Inside this Python script, you will be able to access to the Python library
|
||||
`H3DInterface`... This is bad... Need to find a better alternative.
|
||||
|
||||
Troubleshooting:
|
||||
- Check: https://www.h3dapi.org/modules/mediawiki/index.php/H3DAPI_FAQ#Python
|
||||
-
|
||||
|
||||
Dependencies:
|
||||
- `pyrobolearn.tools.interfaces`
|
||||
@@ -18,7 +25,13 @@ References:
|
||||
|
||||
# TODO
|
||||
|
||||
# import H3DInterface as h3d
|
||||
try:
|
||||
import H3DInterface as h3d
|
||||
except ImportError as e:
|
||||
string = "\nHint: try to install h3dapi by following the instructions on: " \
|
||||
"https://www.h3dapi.org/modules/mediawiki/index.php/H3DAPI_Installation" \
|
||||
"\nNote that you will have to install the API from source to have the Python library."
|
||||
raise ImportError(e.__str__() + string)
|
||||
|
||||
from pyrobolearn.tools.interfaces import InputOutputInterface
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<Scene>
|
||||
<PythonScript url="h3d_haptic.py" />
|
||||
</Scene>
|
||||
@@ -0,0 +1,4 @@
|
||||
## Tests
|
||||
|
||||
This folder contains the unit and integration tests.
|
||||
|
||||
Reference in New Issue
Block a user