diff --git a/cmake b/cmake
index d63b949baa72cae06bad7497d3fcb35a9c7e124c..fb4c22c319ec5320f9a85527eb1a4130954846f5 160000
--- a/cmake
+++ b/cmake
@@ -1 +1 @@
-Subproject commit d63b949baa72cae06bad7497d3fcb35a9c7e124c
+Subproject commit fb4c22c319ec5320f9a85527eb1a4130954846f5
diff --git a/python/example_robot_data/robots_loader.py b/python/example_robot_data/robots_loader.py
index f0fa302461131b77800d5d5d97d54b89a298d5c8..630fa9c0c62a9b7e4dda20bc05671c2060827cce 100644
--- a/python/example_robot_data/robots_loader.py
+++ b/python/example_robot_data/robots_loader.py
@@ -1,11 +1,13 @@
 import sys
+import warnings
 from os.path import dirname, exists, join
 
 import numpy as np
-import pinocchio
+
+import pinocchio as pin
 from pinocchio.robot_wrapper import RobotWrapper
 
-pinocchio.switchToNumpyArray()
+pin.switchToNumpyArray()
 
 
 def getModelPath(subpath, printmsg=False):
@@ -27,16 +29,12 @@ def getModelPath(subpath, printmsg=False):
     raise IOError('%s not found' % subpath)
 
 
-def getVisualPath(modelPath):
-    return join(modelPath, '../..')
-
-
 def readParamsFromSrdf(model, SRDF_PATH, verbose=False, has_rotor_parameters=True, referencePose='half_sitting'):
     if has_rotor_parameters:
-        pinocchio.loadRotorParameters(model, SRDF_PATH, verbose)
+        pin.loadRotorParameters(model, SRDF_PATH, verbose)
     model.armature = np.multiply(model.rotorInertia.flat, np.square(model.rotorGearRatio.flat))
-    pinocchio.loadReferenceConfigurations(model, SRDF_PATH, verbose)
-    q0 = pinocchio.neutral(model)
+    pin.loadReferenceConfigurations(model, SRDF_PATH, verbose)
+    q0 = pin.neutral(model)
     if referencePose is not None:
         q0 = model.referenceConfigurations[referencePose].copy()
     return q0
@@ -51,6 +49,29 @@ def addFreeFlyerJointLimits(model):
     model.lowerPositionLimit = lb
 
 
+def robot_loader(path,
+                 urdf_filename,
+                 srdf_filename=None,
+                 urdf_subpath='robots',
+                 verbose=False,
+                 has_rotor_parameters=False,
+                 ref_posture='half_sitting',
+                 free_flyer=False):
+    """Helper function to load a robot."""
+    urdf_path = join(path, urdf_subpath, urdf_filename)
+    model_path = getModelPath(urdf_path)
+    robot = RobotWrapper.BuildFromURDF(join(model_path, urdf_path), [join(model_path, '../..')],
+                                       pin.JointModelFreeFlyer() if free_flyer else None)
+
+    if srdf_filename is not None:
+        robot.q0 = readParamsFromSrdf(robot.model, join(model_path, path, 'srdf', srdf_filename), verbose,
+                                      has_rotor_parameters, ref_posture)
+    if free_flyer:
+        addFreeFlyerJointLimits(robot.model)
+
+    return robot
+
+
 def loadANYmal(withArm=None):
     if withArm is None:
         URDF_FILENAME = "anymal.urdf"
@@ -60,256 +81,149 @@ def loadANYmal(withArm=None):
         URDF_FILENAME = "anymal-kinova.urdf"
         SRDF_FILENAME = "anymal-kinova.srdf"
         REF_POSTURE = "standing_with_arm_up"
-    URDF_SUBPATH = "/anymal_b_simple_description/robots/" + URDF_FILENAME
-    SRDF_SUBPATH = "/anymal_b_simple_description/srdf/" + SRDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                       pinocchio.JointModelFreeFlyer())
-    # Load SRDF file
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False, False, referencePose=REF_POSTURE)
-    # Add the free-flyer joint limits
-    addFreeFlyerJointLimits(robot.model)
-    return robot
 
+    return robot_loader('anymal_b_simple_description',
+                        URDF_FILENAME,
+                        SRDF_FILENAME,
+                        ref_posture=REF_POSTURE,
+                        free_flyer=True)
 
-def loadTalosArm():
-    URDF_FILENAME = "talos_left_arm.urdf"
-    URDF_SUBPATH = "/talos_data/robots/" + URDF_FILENAME
-    SRDF_FILENAME = "talos.srdf"
-    SRDF_SUBPATH = "/talos_data/srdf/" + SRDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)])
 
-    # Load SRDF file
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False)
-    return robot
+def loadTalos(legs=False, arm=False):
+    URDF_FILENAME = "talos_left_arm.urdf" if arm else "talos_reduced.urdf"
+    SRDF_FILENAME = "talos.srdf"
 
+    robot = robot_loader('talos_data', URDF_FILENAME, SRDF_FILENAME, free_flyer=not arm)
+
+    assert (robot.model.armature[:6] == 0.).all()
+
+    if legs:
+        legMaxId = 14
+        m1 = robot.model
+        m2 = pin.Model()
+        for j, M, name, parent, Y in zip(m1.joints, m1.jointPlacements, m1.names, m1.parents, m1.inertias):
+            if j.id < legMaxId:
+                jid = m2.addJoint(parent, getattr(pin, j.shortname())(), M, name)
+                upperPos = m2.upperPositionLimit
+                lowerPos = m2.lowerPositionLimit
+                effort = m2.effortLimit
+                upperPos[m2.joints[jid].idx_q:m2.joints[jid].idx_q + j.nq] = m1.upperPositionLimit[j.idx_q:j.idx_q +
+                                                                                                   j.nq]
+                lowerPos[m2.joints[jid].idx_q:m2.joints[jid].idx_q + j.nq] = m1.lowerPositionLimit[j.idx_q:j.idx_q +
+                                                                                                   j.nq]
+                effort[m2.joints[jid].idx_v:m2.joints[jid].idx_v + j.nv] = m1.effortLimit[j.idx_v:j.idx_v + j.nv]
+                m2.upperPositionLimit = upperPos
+                m2.lowerPositionLimit = lowerPos
+                m2.effortLimit = effort
+                assert jid == j.id
+                m2.appendBodyToJoint(jid, Y, pin.SE3.Identity())
+
+        upperPos = m2.upperPositionLimit
+        upperPos[:7] = 1
+        m2.upperPositionLimit = upperPos
+        lowerPos = m2.lowerPositionLimit
+        lowerPos[:7] = -1
+        m2.lowerPositionLimit = lowerPos
+        effort = m2.effortLimit
+        effort[:6] = np.inf
+        m2.effortLimit = effort
+
+        # q2 = robot.q0[:19]
+        for f in m1.frames:
+            if f.parent < legMaxId:
+                m2.addFrame(f)
+
+        g2 = pin.GeometryModel()
+        for g in robot.visual_model.geometryObjects:
+            if g.parentJoint < 14:
+                g2.addGeometryObject(g)
+
+        robot.model = m2
+        robot.data = m2.createData()
+        robot.visual_model = g2
+        # robot.q0=q2
+        robot.visual_data = pin.GeometryData(g2)
+
+        # Load SRDF file
+        robot.q0 = robot.q0[:robot.model.nq]
+        model_path = getModelPath(join('talos_data/robots', URDF_FILENAME))
+        robot.q0 = readParamsFromSrdf(robot.model, join(model_path, 'talos_data/srdf', SRDF_FILENAME), False)
+
+        assert (m2.armature[:6] == 0.).all()
+        # Add the free-flyer joint limits to the new model
+        addFreeFlyerJointLimits(robot.model)
 
-def loadTalos():
-    URDF_FILENAME = "talos_reduced.urdf"
-    SRDF_FILENAME = "talos.srdf"
-    SRDF_SUBPATH = "/talos_data/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/talos_data/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                       pinocchio.JointModelFreeFlyer())
-    # Load SRDF file
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False)
-    assert ((robot.model.armature[:6] == 0.).all())
-    # Add the free-flyer joint limits
-    addFreeFlyerJointLimits(robot.model)
     return robot
 
 
 def loadTalosLegs():
-    robot = loadTalos()
-    URDF_FILENAME = "talos_reduced.urdf"
-    SRDF_FILENAME = "talos.srdf"
-    SRDF_SUBPATH = "/talos_data/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/talos_data/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-
-    legMaxId = 14
-    m1 = robot.model
-    m2 = pinocchio.Model()
-    for j, M, name, parent, Y in zip(m1.joints, m1.jointPlacements, m1.names, m1.parents, m1.inertias):
-        if j.id < legMaxId:
-            jid = m2.addJoint(parent, getattr(pinocchio, j.shortname())(), M, name)
-            upperPos = m2.upperPositionLimit
-            lowerPos = m2.lowerPositionLimit
-            effort = m2.effortLimit
-            upperPos[m2.joints[jid].idx_q:m2.joints[jid].idx_q + j.nq] = m1.upperPositionLimit[j.idx_q:j.idx_q + j.nq]
-            lowerPos[m2.joints[jid].idx_q:m2.joints[jid].idx_q + j.nq] = m1.lowerPositionLimit[j.idx_q:j.idx_q + j.nq]
-            effort[m2.joints[jid].idx_v:m2.joints[jid].idx_v + j.nv] = m1.effortLimit[j.idx_v:j.idx_v + j.nv]
-            m2.upperPositionLimit = upperPos
-            m2.lowerPositionLimit = lowerPos
-            m2.effortLimit = effort
-            assert (jid == j.id)
-            m2.appendBodyToJoint(jid, Y, pinocchio.SE3.Identity())
-
-    upperPos = m2.upperPositionLimit
-    upperPos[:7] = 1
-    m2.upperPositionLimit = upperPos
-    lowerPos = m2.lowerPositionLimit
-    lowerPos[:7] = -1
-    m2.lowerPositionLimit = lowerPos
-    effort = m2.effortLimit
-    effort[:6] = np.inf
-    m2.effortLimit = effort
-
-    # q2 = robot.q0[:19]
-    for f in m1.frames:
-        if f.parent < legMaxId:
-            m2.addFrame(f)
-
-    g2 = pinocchio.GeometryModel()
-    for g in robot.visual_model.geometryObjects:
-        if g.parentJoint < 14:
-            g2.addGeometryObject(g)
-
-    robot.model = m2
-    robot.data = m2.createData()
-    robot.visual_model = g2
-    # robot.q0=q2
-    robot.visual_data = pinocchio.GeometryData(g2)
-
-    # Load SRDF file
-    robot.q0 = robot.q0[:robot.model.nq]
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False)
-
-    assert ((m2.armature[:6] == 0.).all())
-    # Add the free-flyer joint limits
-    addFreeFlyerJointLimits(robot.model)
-    return robot
+    warnings.warn("`loadTalosLegs()` is deprecated. Please use `loadTalos(legs=True)`", DeprecationWarning, 2)
+    return loadTalos(legs=True)
+
+
+def loadTalosArm():
+    warnings.warn("`loadTalosArm()` is deprecated. Please use `loadTalos(arm=True)`", DeprecationWarning, 2)
+    return loadTalos(arm=True)
 
 
 def loadHyQ():
-    URDF_FILENAME = "hyq_no_sensors.urdf"
-    SRDF_FILENAME = "hyq.srdf"
-    SRDF_SUBPATH = "/hyq_description/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/hyq_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                       pinocchio.JointModelFreeFlyer())
-    # Load SRDF file
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False, False, "standing")
-    # Add the free-flyer joint limits
-    addFreeFlyerJointLimits(robot.model)
-    return robot
+    return robot_loader('hyq_description', "hyq_no_sensors.urdf", "hyq.srdf", ref_posture="standing", free_flyer=True)
 
 
 def loadSolo(solo=True):
-    if solo:
-        URDF_FILENAME = "solo.urdf"
-    else:
-        URDF_FILENAME = "solo12.urdf"
-    SRDF_FILENAME = "solo.srdf"
-    SRDF_SUBPATH = "/solo_description/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/solo_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                       pinocchio.JointModelFreeFlyer())
-    # Load SRDF file
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False, False, "standing")
-    # Add the free-flyer joint limits
-    addFreeFlyerJointLimits(robot.model)
-    return robot
+    return robot_loader('solo_description',
+                        "solo.urdf" if solo else "solo12.urdf",
+                        "solo.srdf",
+                        ref_posture="standing",
+                        free_flyer=True)
 
 
 def loadKinova():
-    URDF_FILENAME = "kinova.urdf"
-    SRDF_FILENAME = "kinova.srdf"
-    SRDF_SUBPATH = "/kinova_description/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/kinova_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)])
-    # Load SRDF file
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False, False, "arm_up")
-    return robot
+    return robot_loader('kinova_description', "kinova.urdf", "kinova.srdf", ref_posture="arm_up")
 
 
-def loadTiago():
-    URDF_FILENAME = "tiago.urdf"
-    #    SRDF_FILENAME = "tiago.srdf"
-    #    SRDF_SUBPATH = "/tiago_description/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/tiago_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)])
-    # Load SRDF file
-    #    robot.q0 = readParamsFromSrdf(robot.model, modelPath+SRDF_SUBPATH, False)
-    return robot
+def loadTiago(hand=True):
+    return robot_loader('tiago_description', "tiago.urdf" if hand else "tiago_no_hand.urdf")
 
 
 def loadTiagoNoHand():
-    URDF_FILENAME = "tiago_no_hand.urdf"
-    #    SRDF_FILENAME = "tiago.srdf"
-    #    SRDF_SUBPATH = "/tiago_description/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/tiago_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)])
-    # Load SRDF file
-    #    robot.q0 = readParamsFromSrdf(robot.model, modelPath+SRDF_SUBPATH, False)
-    return robot
+    warnings.warn("`loadTiagoNoHand()` is deprecated. Please use `loadTiago(hand=False)`", DeprecationWarning, 2)
+    return loadTiago(hand=False)
 
 
 def loadICub(reduced=True):
-    if reduced:
-        URDF_FILENAME = "icub_reduced.urdf"
-    else:
-        URDF_FILENAME = "icub.urdf"
-    SRDF_FILENAME = "icub.srdf"
-    SRDF_SUBPATH = "/icub_description/srdf/" + SRDF_FILENAME
-    URDF_SUBPATH = "/icub_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    # Load URDF file
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                       pinocchio.JointModelFreeFlyer())
-    # Load SRDF file
-    robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False, False)
-    # Add the free-flyer joint limits
-    addFreeFlyerJointLimits(robot.model)
-    return robot
+    return robot_loader('icub_description',
+                        "icub_reduced.urdf" if reduced else "icub.urdf",
+                        "icub.srdf",
+                        free_flyer=True)
 
 
 def loadPanda():
-    URDF_FILENAME = "panda.urdf"
-    URDF_SUBPATH = "/panda_description/urdf/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)])
-
-    return robot
+    return robot_loader('panda_description', "panda.urdf", urdf_subpath='urdf')
 
 
 def loadUR(robot=5, limited=False, gripper=False):
-    assert (not (gripper and (robot == 10 or limited)))
+    assert not (gripper and (robot == 10 or limited))
     URDF_FILENAME = "ur%i%s_%s.urdf" % (robot, "_joint_limited" if limited else '', 'gripper' if gripper else 'robot')
-    URDF_SUBPATH = "/ur_description/urdf/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)])
     if robot == 5 or robot == 3 and gripper:
         SRDF_FILENAME = "ur%i%s.srdf" % (robot, '_gripper' if gripper else '')
-        SRDF_SUBPATH = "/ur_description/srdf/" + SRDF_FILENAME
-        robot.q0 = readParamsFromSrdf(robot.model, modelPath + SRDF_SUBPATH, False, False, None)
-    return robot
+    else:
+        SRDF_FILENAME = None
+
+    return robot_loader('ur_description', URDF_FILENAME, SRDF_FILENAME, urdf_subpath='urdf', ref_posture=None)
 
 
 def loadHector():
-    URDF_FILENAME = "quadrotor_base.urdf"
-    URDF_SUBPATH = "/hector_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                       pinocchio.JointModelFreeFlyer())
-    return robot
+    return robot_loader('hector_description', "quadroto_base.urdf", free_flyer=True)
 
 
 def loadDoublePendulum():
-    URDF_FILENAME = "double_pendulum.urdf"
-    URDF_SUBPATH = "/double_pendulum_description/urdf/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)])
-    return robot
+    return robot_loader('double_pendulum_description', "double_pendulum.urdf", urdf_subpath='urdf')
 
 
 def loadRomeo():
-    URDF_FILENAME = "romeo.urdf"
-    URDF_SUBPATH = "/romeo_description/urdf/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    return RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                      pinocchio.JointModelFreeFlyer())
+    return robot_loader('romeo_description', "romeo.urdf", urdf_subpath='urdf', free_flyer=True)
 
 
 def loadIris():
-    URDF_FILENAME = "iris_simple.urdf"
-    URDF_SUBPATH = "/iris_description/robots/" + URDF_FILENAME
-    modelPath = getModelPath(URDF_SUBPATH)
-    robot = RobotWrapper.BuildFromURDF(modelPath + URDF_SUBPATH, [getVisualPath(modelPath)],
-                                       pinocchio.JointModelFreeFlyer())
-    return robot
+    return robot_loader('iris_description', "iris_simple.urdf", free_flyer=True)
diff --git a/unittest/test_load.py b/unittest/test_load.py
index 5ad3655c0eb811c0a158532b0cbdad27d1e61cd4..0b3c96eb1be70ca77490c1a988f344df2c2fe57c 100755
--- a/unittest/test_load.py
+++ b/unittest/test_load.py
@@ -48,19 +48,19 @@ class TalosTest(RobotTestCase):
 
 
 class TalosArmTest(RobotTestCase):
-    RobotTestCase.ROBOT = example_robot_data.loadTalosArm()
+    RobotTestCase.ROBOT = example_robot_data.loadTalos(arm=True)
     RobotTestCase.NQ = 7
     RobotTestCase.NV = 7
 
 
 class TalosArmFloatingTest(RobotTestCase):
-    RobotTestCase.ROBOT = example_robot_data.loadTalosArm()
+    RobotTestCase.ROBOT = example_robot_data.loadTalos(arm=True)
     RobotTestCase.NQ = 14
     RobotTestCase.NV = 13
 
 
 class TalosLegsTest(RobotTestCase):
-    RobotTestCase.ROBOT = example_robot_data.loadTalosLegs()
+    RobotTestCase.ROBOT = example_robot_data.loadTalos(legs=True)
     RobotTestCase.NQ = 19
     RobotTestCase.NV = 18
 
@@ -90,7 +90,7 @@ class TiagoTest(RobotTestCase):
 
 
 class TiagoNoHandTest(RobotTestCase):
-    RobotTestCase.ROBOT = example_robot_data.loadTiagoNoHand()
+    RobotTestCase.ROBOT = example_robot_data.loadTiago(hand=False)
     RobotTestCase.NQ = 14
     RobotTestCase.NV = 12