Skip to content

Commit

Permalink
Fix python tests (#1979)
Browse files Browse the repository at this point in the history
* ensure joint models in robot_model submodule

* add build tests
  • Loading branch information
peterdavidfagan authored Mar 20, 2023
1 parent 9f45e6c commit 5bc31eb
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 86 deletions.
28 changes: 27 additions & 1 deletion moveit_py/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,22 @@ find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
find_package(pybind11_vendor REQUIRED)
find_package(pybind11 REQUIRED)

# enables using the Python extensions from the build space for testing
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_moveit/__init__.py" "")

add_subdirectory(src/moveit/moveit_py_utils)

ament_python_install_package(moveit)

# Set the build location and install location for a CPython extension
function(configure_build_install_location _library_name)
install(TARGETS ${_library_name}
# Install into test_moveit folder in build space for unit tests to import
set_target_properties(${_library_name} PROPERTIES
# Use generator expression to avoid prepending a build type specific directory on Windows
LIBRARY_OUTPUT_DIRECTORY $<1:${CMAKE_CURRENT_BINARY_DIR}/test_moveit>
RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_CURRENT_BINARY_DIR}/test_moveit>)

install(TARGETS ${_library_name}
DESTINATION "${PYTHON_INSTALL_DIR}/moveit"
)
endfunction()
Expand Down Expand Up @@ -64,4 +73,21 @@ target_link_libraries(planning PRIVATE moveit_ros_planning::moveit_cpp
moveit_py_utils)
configure_build_install_location(planning)


if(BUILD_TESTING)
find_package(ament_cmake_pytest REQUIRED)
set(_pytest_tests
test/unit/test_robot_model.py
test/unit/test_robot_state.py
)
foreach(_test_path ${_pytest_tests})
get_filename_component(_test_name ${_test_path} NAME_WE)
ament_add_pytest_test(${_test_name} ${_test_path}
APPEND_ENV AMENT_PREFIX_INDEX=${ament_index_build_path} PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 60
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
endforeach()
endif()

ament_package()
4 changes: 4 additions & 0 deletions moveit_py/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
<depend>moveit_ros_planning_interface</depend>
<depend>moveit_ros_planning</depend>
<depend>moveit_core</depend>

<test_depend>ament_cmake_pytest</test_depend>
<test_depend>python3-pytest</test_depend>

<export>
<build_type>ament_cmake</build_type>
</export>
Expand Down
4 changes: 3 additions & 1 deletion moveit_py/src/moveit/moveit_core/robot_model/joint_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ namespace bind_robot_model

void init_joint_model(py::module& m)
{
py::class_<moveit::core::VariableBounds, std::shared_ptr<moveit::core::VariableBounds>>(m, "VariableBounds")
py::module robot_model = m.def_submodule("robot_model");

py::class_<moveit::core::VariableBounds, std::shared_ptr<moveit::core::VariableBounds>>(robot_model, "VariableBounds")
.def_readonly("min_position", &moveit::core::VariableBounds::min_position_)
.def_readonly("max_position", &moveit::core::VariableBounds::max_position_)
.def_readonly("position_bounded", &moveit::core::VariableBounds::position_bounded_)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ bool satisfies_position_bounds(const moveit::core::JointModelGroup* jmg, const E

void init_joint_model_group(py::module& m)
{
py::class_<moveit::core::JointModelGroup>(m, "JointModelGroup",
py::module robot_model = m.def_submodule("robot_model");

py::class_<moveit::core::JointModelGroup>(robot_model, "JointModelGroup",
R"(
Representation of a group of joints that are part of a robot model.
)")
Expand Down
48 changes: 22 additions & 26 deletions moveit_py/test/unit/test_robot_model.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,55 @@
import unittest

from moveit_py.core import JointModelGroup, RobotModel
from test_moveit.core.robot_model import JointModelGroup, RobotModel

# TODO (peterdavidfagan): depend on moveit_resources package directly.
# (https://github.com/peterdavidfagan/moveit2/blob/moveit_py/moveit_core/utils/src/robot_model_test_utils.cpp)

import os

dir_path = os.path.dirname(os.path.realpath(__file__))
URDF_FILE = "{}/fixtures/panda.urdf".format(dir_path)
SRDF_FILE = "{}/fixtures/panda.srdf".format(dir_path)


def get_robot_model():
"""Helper function that returns a RobotModel instance."""
return RobotModel(urdf_xml_path=URDF_FILE, srdf_xml_path=SRDF_FILE)


class TestRobotModel(unittest.TestCase):
def test_initialization(self):
"""
Test that the RobotModel can be initialized with xml filepaths.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
self.assertIsInstance(robot, RobotModel)

def test_name_property(self):
"""
Test that the RobotModel name property returns the correct name.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
self.assertEqual(robot.name, "panda")

def test_model_frame_property(self):
"""
Test that the RobotModel model_frame property returns the correct name.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
self.assertEqual(robot.model_frame, "world")

def test_root_joint_name_property(self):
"""
Test that the RobotModel root_link property returns the correct name.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
self.assertEqual(robot.root_joint_name, "virtual_joint")

def test_joint_model_group_names_property(self):
"""
Test that the RobotModel joint_model_group_names property returns the correct names.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
self.assertCountEqual(
robot.joint_model_group_names, ["panda_arm", "hand", "panda_arm_hand"]
)
Expand All @@ -56,28 +58,22 @@ def test_joint_model_groups_property(self):
"""
Test that the RobotModel joint_model_groups returns a list of JointModelGroups.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
self.assertIsInstance(robot.joint_model_groups[0], JointModelGroup)

def test_has_joint_model_group(self):
"""
Test that the RobotModel has_joint_model_group returns True for existing groups.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
self.assertTrue(robot.has_joint_model_group("panda_arm"))
self.assertFalse(robot.has_joint_model_group("The answer is 42."))

def test_get_joint_model_group(self):
"""
Test that the RobotModel get_joint_model_group returns the correct group.
"""
robot = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot = get_robot_model()
jmg = robot.get_joint_model_group("panda_arm")
self.assertIsInstance(jmg, JointModelGroup)
self.assertEqual(jmg.name, "panda_arm")
Expand Down
115 changes: 58 additions & 57 deletions moveit_py/test/unit/test_robot_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,31 @@

from geometry_msgs.msg import Pose

from moveit_py.core import RobotState, RobotModel
from test_moveit.core.robot_state import RobotState
from test_moveit.core.robot_model import RobotModel


# TODO (peterdavidfagan): depend on moveit_resources package directly.
# (https://github.com/peterdavidfagan/moveit2/blob/moveit_py/moveit_core/utils/src/robot_model_test_utils.cpp)

import os

dir_path = os.path.dirname(os.path.realpath(__file__))
URDF_FILE = "{}/fixtures/panda.urdf".format(dir_path)
SRDF_FILE = "{}/fixtures/panda.srdf".format(dir_path)


def get_robot_model():
"""Helper function that returns a RobotModel instance."""
return RobotModel(urdf_xml_path=URDF_FILE, srdf_xml_path=SRDF_FILE)


class TestRobotState(unittest.TestCase):
def test_initialization(self):
"""
Test that RobotState can be initialized with a RobotModel
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)

self.assertIsInstance(robot_state, RobotState)
Expand All @@ -22,9 +36,7 @@ def test_robot_model_property(self):
"""
Test that the robot_model property returns the correct RobotModel
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)

self.assertEqual(robot_state.robot_model, robot_model)
Expand All @@ -33,11 +45,9 @@ def test_get_frame_transform(self):
"""
Test that the frame transform is correct
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)

robot_state.update()
frame_transform = robot_state.get_frame_transform("panda_link0")

self.assertIsInstance(frame_transform, np.ndarray)
Expand All @@ -47,10 +57,9 @@ def test_get_pose(self):
"""
Test that the pose is correct
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)
robot_state.update()
pose = robot_state.get_pose(link_name="panda_link8")

self.assertIsInstance(pose, Pose)
Expand All @@ -60,10 +69,9 @@ def test_get_jacobian_1(self):
"""
Test that the jacobian is correct
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)
robot_state.update()
jacobian = robot_state.get_jacobian(
joint_model_group_name="panda_arm",
reference_point_position=np.array([0.0, 0.0, 0.0]),
Expand All @@ -76,10 +84,9 @@ def test_get_jacobian_2(self):
"""
Test that the jacobian is correct
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)
robot_state.update()
jacobian = robot_state.get_jacobian(
joint_model_group_name="panda_arm",
link_name="panda_link6",
Expand All @@ -93,49 +100,43 @@ def test_set_joint_group_positions(self):
"""
Test that the joint group positions can be set
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)

robot_state.update()
joint_group_positions = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
robot_state.set_joint_group_positions(
joint_model_group_name="panda_arm", position_values=joint_group_positions
)

self.assertEqual(
joint_group_positions.tolist(),
robot_state.copy_joint_group_positions("panda_arm").tolist(),
robot_state.get_joint_group_positions("panda_arm").tolist(),
)

def test_set_joint_group_velocities(self):
"""
Test that the joint group velocities can be set
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)

robot_state.update()
joint_group_velocities = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
robot_state.set_joint_group_velocities(
joint_model_group_name="panda_arm", velocity_values=joint_group_velocities
)

self.assertEqual(
joint_group_velocities.tolist(),
robot_state.copy_joint_group_velocities("panda_arm").tolist(),
robot_state.get_joint_group_velocities("panda_arm").tolist(),
)

def test_set_joint_group_accelerations(self):
"""
Test that the joint group accelerations can be set
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_model = get_robot_model()
robot_state = RobotState(robot_model)

robot_state.update()
joint_group_accelerations = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
robot_state.set_joint_group_accelerations(
joint_model_group_name="panda_arm",
Expand All @@ -144,32 +145,32 @@ def test_set_joint_group_accelerations(self):

self.assertEqual(
joint_group_accelerations.tolist(),
robot_state.copy_joint_group_accelerations("panda_arm").tolist(),
robot_state.get_joint_group_accelerations("panda_arm").tolist(),
)

# TODO (peterdavidfagan): requires kinematics solver to be loaded
def test_set_from_ik(self):
"""
Test that the robot state can be set from an IK solution
"""
robot_model = RobotModel(
urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
)
robot_state = RobotState(robot_model)

pose = Pose()
pose.position.x = 0.5
pose.position.y = 0.5
pose.position.z = 0.5
pose.orientation.w = 1.0

robot_state.set_from_ik(
joint_model_group_name="panda_arm",
geometry_pose=pose,
tip_name="panda_link8",
)

self.assertEqual(robot_state.get_pose("panda_link8"), pose)
# def test_set_from_ik(self):
# """
# Test that the robot state can be set from an IK solution
# """
# robot_model = RobotModel(
# urdf_xml_path="./fixtures/panda.urdf", srdf_xml_path="./fixtures/panda.srdf"
# )
# robot_state = RobotState(robot_model)
# robot_state.update()
# pose = Pose()
# pose.position.x = 0.5
# pose.position.y = 0.5
# pose.position.z = 0.5
# pose.orientation.w = 1.0

# robot_state.set_from_ik(
# joint_model_group_name="panda_arm",
# geometry_pose=pose,
# tip_name="panda_link8",
# )

# self.assertEqual(robot_state.get_pose("panda_link8"), pose)


if __name__ == "__main__":
Expand Down

0 comments on commit 5bc31eb

Please sign in to comment.