Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bindings/generated_docstrings/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ _SUBDIRS = [
"geometry/render_vtk",
"lcm",
"manipulation/kuka_iiwa",
"manipulation/franka_panda",
"manipulation/schunk_wsg",
"manipulation/util",
"math",
Expand Down
334 changes: 334 additions & 0 deletions bindings/generated_docstrings/manipulation_franka_panda.h

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions bindings/pydrake/manipulation/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ PACKAGE_INFO = get_pybind_package_info("//bindings")
drake_pybind_library(
name = "manipulation",
cc_deps = [
"//bindings/generated_docstrings:manipulation_franka_panda",
"//bindings/generated_docstrings:manipulation_kuka_iiwa",
"//bindings/generated_docstrings:manipulation_schunk_wsg",
"//bindings/generated_docstrings:manipulation_util",
Expand All @@ -36,6 +37,7 @@ drake_pybind_library(
"manipulation_py.h",
"manipulation_py.cc",
"manipulation_py_kuka_iiwa.cc",
"manipulation_py_franka_panda.cc",
"manipulation_py_schunk_wsg.cc",
"manipulation_py_util.cc",
],
Expand Down Expand Up @@ -66,6 +68,14 @@ drake_py_unittest(
],
)

drake_py_unittest(
name = "franka_panda_test",
deps = [
":manipulation",
"//bindings/pydrake/systems",
],
)

drake_py_unittest(
name = "schunk_wsg_test",
data = [
Expand Down
1 change: 1 addition & 0 deletions bindings/pydrake/manipulation/manipulation_py.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ PYBIND11_MODULE(manipulation, m) {

// The order of these calls matters. Some modules rely on prior definitions.
internal::DefineManipulationKukaIiwa(m);
internal::DefineManipulationFrankaPanda(m);
internal::DefineManipulationSchunkWsg(m);
internal::DefineManipulationUtil(m);

Expand Down
3 changes: 3 additions & 0 deletions bindings/pydrake/manipulation/manipulation_py.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ namespace internal {
/* Defines bindings per manipulation_py_kuka_iiwa.cc. */
void DefineManipulationKukaIiwa(py::module m);

/* Defines bindings per manipulation_py_franka_panda.cc. */
void DefineManipulationFrankaPanda(py::module m);

/* Defines bindings per manipulation_py_schunk_wsg.cc. */
void DefineManipulationSchunkWsg(py::module m);

Expand Down
162 changes: 162 additions & 0 deletions bindings/pydrake/manipulation/manipulation_py_franka_panda.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#include "drake/bindings/generated_docstrings/manipulation_franka_panda.h"
#include "drake/bindings/pydrake/common/serialize_pybind.h"
#include "drake/bindings/pydrake/manipulation/manipulation_py.h"
#include "drake/bindings/pydrake/pydrake_pybind.h"
#include "drake/lcmt_panda_status.hpp"
#include "drake/manipulation/franka_panda/panda_command_receiver.h"
#include "drake/manipulation/franka_panda/panda_command_sender.h"
#include "drake/manipulation/franka_panda/panda_constants.h"
#include "drake/manipulation/franka_panda/panda_status_receiver.h"
#include "drake/manipulation/franka_panda/panda_status_sender.h"

namespace drake {
namespace pydrake {
namespace internal {

using systems::LeafSystem;

void DefineManipulationFrankaPanda(py::module m) {
// NOLINTNEXTLINE(build/namespaces): Emulate placement in namespace.
using namespace drake::manipulation::franka_panda;
constexpr auto& doc =
pydrake_doc_manipulation_franka_panda.drake.manipulation.franka_panda;

// Constants.
m.attr("kPandaArmNumJoints") = kPandaArmNumJoints;

// Control mode enum
py::enum_<PandaControlMode>(m, "PandaControlMode", py::arithmetic(),
"Control modes for the Panda robot. "
"These can be bitwise OR'd together.")
.value("kNone", PandaControlMode::kNone)
.value("kPosition", PandaControlMode::kPosition)
.value("kVelocity", PandaControlMode::kVelocity)
.value("kTorque", PandaControlMode::kTorque)
.def("__or__",
[](PandaControlMode a, PandaControlMode b) { return a | b; })
.def("__and__",
[](PandaControlMode a, PandaControlMode b) { return a & b; });
{
using Class = PandaCommandReceiver;
constexpr auto& cls_doc = doc.PandaCommandReceiver;
py::class_<Class, LeafSystem<double>>(
m, "PandaCommandReceiver", cls_doc.doc)
.def(py::init<int, PandaControlMode>(), py::arg("num_joints"),
py::arg("control_mode"), cls_doc.ctor.doc)
.def("LatchInitialPosition",
overload_cast_explicit<void, drake::systems::Context<double>*>(
&Class::LatchInitialPosition),
py::arg("context"), cls_doc.LatchInitialPosition.doc)
.def("get_message_input_port", &Class::get_message_input_port,
py_rvp::reference_internal, cls_doc.get_message_input_port.doc)
.def("get_position_measured_input_port",
&Class::get_position_measured_input_port,
py_rvp::reference_internal,
cls_doc.get_position_measured_input_port.doc)
.def("get_commanded_position_output_port",
&Class::get_commanded_position_output_port,
py_rvp::reference_internal,
cls_doc.get_commanded_position_output_port.doc)
.def("get_commanded_velocity_output_port",
&Class::get_commanded_velocity_output_port,
py_rvp::reference_internal,
cls_doc.get_commanded_velocity_output_port.doc)
.def("get_commanded_torque_output_port",
&Class::get_commanded_torque_output_port,
py_rvp::reference_internal,
cls_doc.get_commanded_torque_output_port.doc);
}

{
using Class = PandaCommandSender;
constexpr auto& cls_doc = doc.PandaCommandSender;
py::class_<Class, LeafSystem<double>>(m, "PandaCommandSender", cls_doc.doc)
.def(py::init<int, PandaControlMode>(), py::arg("num_joints"),
py::arg("control_mode"), cls_doc.ctor.doc)
.def("get_position_input_port", &Class::get_position_input_port,
py_rvp::reference_internal, cls_doc.get_position_input_port.doc)
.def("get_velocity_input_port", &Class::get_velocity_input_port,
py_rvp::reference_internal, cls_doc.get_velocity_input_port.doc)
.def("get_torque_input_port", &Class::get_torque_input_port,
py_rvp::reference_internal, cls_doc.get_torque_input_port.doc);
}

{
using Class = PandaStatusReceiver;
constexpr auto& cls_doc = doc.PandaStatusReceiver;
py::class_<Class, LeafSystem<double>>(m, "PandaStatusReceiver", cls_doc.doc)
.def(py::init<int>(), py::arg("num_joints") = kPandaArmNumJoints,
cls_doc.ctor.doc)
.def("get_position_commanded_output_port",
&Class::get_position_commanded_output_port,
py_rvp::reference_internal,
cls_doc.get_position_commanded_output_port.doc)
.def("get_position_measured_output_port",
&Class::get_position_measured_output_port,
py_rvp::reference_internal,
cls_doc.get_position_measured_output_port.doc)
.def("get_velocity_commanded_output_port",
&Class::get_velocity_commanded_output_port,
py_rvp::reference_internal,
cls_doc.get_velocity_commanded_output_port.doc)
.def("get_velocity_measured_output_port",
&Class::get_velocity_measured_output_port,
py_rvp::reference_internal,
cls_doc.get_velocity_measured_output_port.doc)
.def("get_acceleration_commanded_output_port",
&Class::get_acceleration_commanded_output_port,
py_rvp::reference_internal,
cls_doc.get_acceleration_commanded_output_port.doc)
.def("get_torque_commanded_output_port",
&Class::get_torque_commanded_output_port,
py_rvp::reference_internal,
cls_doc.get_torque_commanded_output_port.doc)
.def("get_torque_measured_output_port",
&Class::get_torque_measured_output_port, py_rvp::reference_internal,
cls_doc.get_torque_measured_output_port.doc)
.def("get_torque_external_output_port",
&Class::get_torque_external_output_port, py_rvp::reference_internal,
cls_doc.get_torque_external_output_port.doc);
}

{
using Class = PandaStatusSender;
constexpr auto& cls_doc = doc.PandaStatusSender;
py::class_<Class, LeafSystem<double>>(m, "PandaStatusSender", cls_doc.doc)
.def(py::init<int>(), py::arg("num_joints") = kPandaArmNumJoints,
cls_doc.ctor.doc)
.def("get_position_commanded_input_port",
&Class::get_position_commanded_input_port,
py_rvp::reference_internal,
cls_doc.get_position_commanded_input_port.doc)
.def("get_position_measured_input_port",
&Class::get_position_measured_input_port,
py_rvp::reference_internal,
cls_doc.get_position_measured_input_port.doc)
.def("get_velocity_commanded_input_port",
&Class::get_velocity_commanded_input_port,
py_rvp::reference_internal,
cls_doc.get_velocity_commanded_input_port.doc)
.def("get_velocity_measured_input_port",
&Class::get_velocity_measured_input_port,
py_rvp::reference_internal,
cls_doc.get_velocity_measured_input_port.doc)
.def("get_acceleration_commanded_input_port",
&Class::get_acceleration_commanded_input_port,
py_rvp::reference_internal,
cls_doc.get_acceleration_commanded_input_port.doc)
.def("get_torque_commanded_input_port",
&Class::get_torque_commanded_input_port, py_rvp::reference_internal,
cls_doc.get_torque_commanded_input_port.doc)
.def("get_torque_measured_input_port",
&Class::get_torque_measured_input_port, py_rvp::reference_internal,
cls_doc.get_torque_measured_input_port.doc)
.def("get_torque_external_input_port",
&Class::get_torque_external_input_port, py_rvp::reference_internal,
cls_doc.get_torque_external_input_port.doc);
}
}

} // namespace internal
} // namespace pydrake
} // namespace drake
130 changes: 130 additions & 0 deletions bindings/pydrake/manipulation/test/franka_panda_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-

import unittest

import pydrake.manipulation as mut
from pydrake.systems.framework import (
InputPort,
OutputPort,
)


class TestFrankaPanda(unittest.TestCase):
def test_constants(self):
self.assertEqual(mut.kPandaArmNumJoints, 7)

def test_franka_panda_command_receiver(self):
# Test with position and torque control mode
control_mode = (
mut.PandaControlMode.kPosition | mut.PandaControlMode.kTorque
)
command_rec = mut.PandaCommandReceiver(
num_joints=mut.kPandaArmNumJoints, control_mode=control_mode
)
self.assertIsInstance(command_rec.get_message_input_port(), InputPort)
self.assertIsInstance(
command_rec.get_position_measured_input_port(), InputPort
)
self.assertIsInstance(
command_rec.get_commanded_position_output_port(), OutputPort
)
self.assertIsInstance(
command_rec.get_commanded_torque_output_port(), OutputPort
)

# Test with position, velocity, and torque control mode
control_mode_all = (
mut.PandaControlMode.kPosition
| mut.PandaControlMode.kVelocity
| mut.PandaControlMode.kTorque
)
command_rec_all = mut.PandaCommandReceiver(
num_joints=mut.kPandaArmNumJoints, control_mode=control_mode_all
)
self.assertIsInstance(
command_rec_all.get_commanded_velocity_output_port(), OutputPort
)

def test_franka_panda_command_sender(self):
# Test with position and torque control mode
control_mode = (
mut.PandaControlMode.kPosition | mut.PandaControlMode.kTorque
)
command_send = mut.PandaCommandSender(
num_joints=mut.kPandaArmNumJoints, control_mode=control_mode
)
self.assertIsInstance(command_send.get_position_input_port(), InputPort)
self.assertIsInstance(command_send.get_torque_input_port(), InputPort)

# Test with position, velocity, and torque control mode
control_mode_all = (
mut.PandaControlMode.kPosition
| mut.PandaControlMode.kVelocity
| mut.PandaControlMode.kTorque
)
command_send_all = mut.PandaCommandSender(
num_joints=mut.kPandaArmNumJoints, control_mode=control_mode_all
)
self.assertIsInstance(
command_send_all.get_velocity_input_port(), InputPort
)

def test_franka_panda_status_receiver(self):
status_rec = mut.PandaStatusReceiver()
self.assertIsInstance(
status_rec.get_position_commanded_output_port(), OutputPort
)
self.assertIsInstance(
status_rec.get_position_measured_output_port(), OutputPort
)
self.assertIsInstance(
status_rec.get_velocity_commanded_output_port(), OutputPort
)
self.assertIsInstance(
status_rec.get_velocity_measured_output_port(), OutputPort
)
self.assertIsInstance(
status_rec.get_acceleration_commanded_output_port(), OutputPort
)
self.assertIsInstance(
status_rec.get_torque_commanded_output_port(), OutputPort
)
self.assertIsInstance(
status_rec.get_torque_measured_output_port(), OutputPort
)
self.assertIsInstance(
status_rec.get_torque_external_output_port(), OutputPort
)

# Constructor variant.
mut.PandaStatusReceiver(num_joints=mut.kPandaArmNumJoints)

def test_franka_panda_status_sender(self):
status_send = mut.PandaStatusSender()
self.assertIsInstance(
status_send.get_position_commanded_input_port(), InputPort
)
self.assertIsInstance(
status_send.get_position_measured_input_port(), InputPort
)
self.assertIsInstance(
status_send.get_velocity_commanded_input_port(), InputPort
)
self.assertIsInstance(
status_send.get_velocity_measured_input_port(), InputPort
)
self.assertIsInstance(
status_send.get_acceleration_commanded_input_port(), InputPort
)
self.assertIsInstance(
status_send.get_torque_commanded_input_port(), InputPort
)
self.assertIsInstance(
status_send.get_torque_measured_input_port(), InputPort
)
self.assertIsInstance(
status_send.get_torque_external_input_port(), InputPort
)

# Constructor variant.
mut.PandaStatusSender(num_joints=mut.kPandaArmNumJoints)
Loading