diff --git a/src/DQ_py.cpp b/src/DQ_py.cpp index d2ada9e..5dcddb4 100644 --- a/src/DQ_py.cpp +++ b/src/DQ_py.cpp @@ -22,123 +22,143 @@ This file is part of DQ Robotics. #include "dqrobotics_module.h" +/** + * @brief Binds `DQ`, the class that represents dual quaternions, and the + * free functions and constants of the `DQ_robotics` namespace declared in + * `dqrobotics/DQ.h`, to the Python module @p m. + */ void init_DQ_py(py::module& m) { /***************************************************** * DQ * **************************************************/ - py::class_ dq(m, "DQ"); - dq.def(py::init()); - dq.def(py::init()); + py::class_ dq(m, "DQ", + "A dual quaternion, used to represent poses, rotations, translations, " + "lines, and planes in three-dimensional space."); + dq.def(py::init<>(), + "Constructs a dual quaternion with all coefficients equal to zero."); + dq.def(py::init(), + py::arg("q0"), py::arg("q1"), py::arg("q2"), py::arg("q3"), + py::arg("e0"), py::arg("e1"), py::arg("e2"), py::arg("e3"), + "Constructs a dual quaternion from its eight coefficients, in the order " + "primary (q0, q1, q2, q3) followed by dual (e0, e1, e2, e3)."); + dq.def(py::init(), py::arg("v"), + "Constructs a dual quaternion from a vector of 8, 6, 4, 3, or 1 elements.\n\n" + "The mapping between the vector size and the resulting dual quaternion " + "follows the inverse of vec8(), vec6(), vec4(), and vec3(), respectively. " + "A vector of size 1 is used to construct a real dual quaternion."); ///Members - dq.def_readwrite("q", &DQ::q); + dq.def_readwrite("q", &DQ::q, + "The eight coefficients of this dual quaternion, in the order " + "primary (q0, q1, q2, q3) followed by dual (e0, e1, e2, e3)."); ///Static Members - dq.def_readonly_static("i",&DQ::i); - dq.def_readonly_static("j",&DQ::j); - dq.def_readonly_static("k",&DQ::k); - dq.def_readonly_static("E",&DQ::E); + dq.def_readonly_static("i",&DQ::i, "The imaginary unit i, such that `i*i = -1`."); + dq.def_readonly_static("j",&DQ::j, "The imaginary unit j, such that `j*j = -1`."); + dq.def_readonly_static("k",&DQ::k, "The imaginary unit k, such that `k*k = -1`."); + dq.def_readonly_static("E",&DQ::E, "The dual unit, such that `E*E = 0`."); ///Methods - dq.def("P" ,&DQ::P, "Retrieves the primary part of a DQ."); - dq.def("D" ,&DQ::D, "Retrieves the dual part of a DQ."); - dq.def("Re" ,&DQ::Re, "Retrieves the real part of a DQ."); - dq.def("Im" ,&DQ::Im, "Retrieves the imaginary part of a DQ."); - dq.def("conj" ,&DQ::conj, "Retrieves the conjugate of a DQ."); - dq.def("norm" ,&DQ::norm, "Retrieves the norm of a DQ."); - dq.def("inv" ,&DQ::inv, "Retrieves the inverse of a DQ."); - dq.def("translation" ,&DQ::translation, "Retrieves the translation represented by a unit DQ."); - dq.def("rotation" ,&DQ::rotation, "Retrieves the rotation represented by a unit DQ."); - dq.def("rotation_axis" ,&DQ::rotation_axis, "Retrieves the rotation axis represented by a unit DQ."); - dq.def("rotation_angle" ,&DQ::rotation_angle, "Retrieves the rotation angle represented by a unit DQ."); - dq.def("log" ,&DQ::log, "Retrieves the logarithm of a DQ."); - dq.def("exp" ,&DQ::exp, "Retrieves the exp of a DQ."); - dq.def("pow" ,&DQ::pow, "Retrieves the pow of a DQ."); - dq.def("tplus" ,&DQ::tplus, "Retrieves the tplus operators for a DQ."); - dq.def("pinv" ,&DQ::pinv , "Retrieves the pinv of a DQ."); - dq.def("hamiplus4" ,&DQ::hamiplus4, "Retrieves the H+ operator for the primary part of a DQ."); - dq.def("haminus4" ,&DQ::haminus4, "Retrieves the H- operator for the primary part of a DQ."); - dq.def("hamiplus8" ,&DQ::hamiplus8, "Retrieves the H+ operator for a DQ."); - dq.def("haminus8" ,&DQ::haminus8, "Retrieves the H- operator for a DQ."); - dq.def("vec3" ,&DQ::vec3, "Retrieves the pure part of the primary part of a DQ as a vector."); - dq.def("vec4" ,&DQ::vec4, "Retrieves the primary part of a DQ as a vector."); - dq.def("vec6" ,&DQ::vec6, "Retrieves the pure part of a DQ as a vector."); - dq.def("vec8" ,&DQ::vec8, "Retrieves the DQ as a vector."); - dq.def("normalize" ,&DQ::normalize, "Returns a normalized DQ."); - dq.def("__repr__" ,&DQ::to_string, "Used by python's print function."); - dq.def("to_string" ,&DQ::to_string, "Returns the DQ as a string."); - dq.def("generalized_jacobian",&DQ::generalized_jacobian, "Retrieves the generalized Jacobian of a DQ."); - dq.def("sharp" ,&DQ::sharp, "Retrieves the sharp of a DQ"); - dq.def("Ad" ,&DQ::Ad, "Retrieves the adjoint transformation of a DQ."); - dq.def("Adsharp" ,&DQ::Adsharp, "Retrieves the adjoint sharp transformation of a DQ."); - dq.def("Q4" ,&DQ::Q4, "Retrieves the partial derivative of a unit quaternion with respect to its logarithm."); - dq.def("Q8" ,&DQ::Q8, "Retrieves the partial derivative of a unit DQ with respect to its logarithm."); + dq.def("P" ,&DQ::P, "Returns the primary part of this dual quaternion."); + dq.def("D" ,&DQ::D, "Returns the dual part of this dual quaternion."); + dq.def("Re" ,&DQ::Re, "Returns the real part of this dual quaternion."); + dq.def("Im" ,&DQ::Im, "Returns the imaginary part of this dual quaternion."); + dq.def("conj" ,&DQ::conj, "Returns the conjugate of this dual quaternion."); + dq.def("norm" ,&DQ::norm, "Returns the dual scalar corresponding to the norm of this dual quaternion."); + dq.def("inv" ,&DQ::inv, "Returns the inverse of this dual quaternion, given by `conj(this)/(norm(this)^2)`."); + dq.def("translation" ,&DQ::translation, "Returns the translation quaternion of this unit dual quaternion."); + dq.def("rotation" ,&DQ::rotation, "Returns the rotation quaternion of this unit dual quaternion."); + dq.def("rotation_axis" ,&DQ::rotation_axis, "Returns the rotation axis of this unit dual quaternion."); + dq.def("rotation_angle" ,&DQ::rotation_angle, "Returns the rotation angle of this unit dual quaternion."); + dq.def("log" ,&DQ::log, "Returns the logarithm of this dual quaternion."); + dq.def("exp" ,&DQ::exp, "Returns the exponential of this pure dual quaternion."); + dq.def("pow" ,&DQ::pow, py::arg("a"), "Returns this dual quaternion raised to the power of `a`."); + dq.def("tplus" ,&DQ::tplus, "Returns the unit dual quaternion corresponding to the transformation of this dual quaternion."); + dq.def("T" ,&DQ::T, "Alias for tplus()."); + dq.def("pinv" ,&DQ::pinv , "Returns the Moore-Penrose pseudoinverse of this dual quaternion."); + dq.def("hamiplus4" ,&DQ::hamiplus4, "Returns the Hamilton operator H+ of this dual quaternion, restricted to its primary part."); + dq.def("haminus4" ,&DQ::haminus4, "Returns the Hamilton operator H- of this dual quaternion, restricted to its primary part."); + dq.def("hamiplus8" ,&DQ::hamiplus8, "Returns the Hamilton operator H+ of this dual quaternion."); + dq.def("haminus8" ,&DQ::haminus8, "Returns the Hamilton operator H- of this dual quaternion."); + dq.def("vec3" ,&DQ::vec3, "Maps the primary part of this dual quaternion into a 3-dimensional vector."); + dq.def("vec4" ,&DQ::vec4, "Maps the primary part of this dual quaternion into a 4-dimensional vector."); + dq.def("vec6" ,&DQ::vec6, "Maps this dual quaternion into a 6-dimensional vector, discarding the real part of both the primary and dual components."); + dq.def("vec8" ,&DQ::vec8, "Maps this dual quaternion into an 8-dimensional vector."); + dq.def("normalize" ,&DQ::normalize, "Returns this dual quaternion normalized to unit norm."); + dq.def("__repr__" ,&DQ::to_string, "Returns a string representation of this dual quaternion, used by Python's print() function."); + dq.def("to_string" ,&DQ::to_string, "Returns a string representation of this dual quaternion."); + dq.def("generalized_jacobian",&DQ::generalized_jacobian, "Returns the generalized Jacobian used in the mapping between the time derivative of a unit dual quaternion and the twist it represents."); + dq.def("sharp" ,&DQ::sharp, "Returns the sharp conjugate of this dual quaternion."); + dq.def("Ad" ,&DQ::Ad, py::arg("dq2"), "Returns the adjoint transformation `this * dq2 * this'`."); + dq.def("Adsharp" ,&DQ::Adsharp, py::arg("dq2"), "Returns the sharp adjoint transformation `this.sharp() * dq2 * this'`."); + dq.def("Q4" ,&DQ::Q4, "Given the unit quaternion represented by this dual quaternion, returns the partial derivative of that quaternion with respect to its logarithm."); + dq.def("Q8" ,&DQ::Q8, "Given this unit dual quaternion, returns the partial derivative of this dual quaternion with respect to its logarithm."); ///Operators //Self - dq.def(py::self + py::self); - dq.def(py::self * py::self); - dq.def(py::self - py::self); - dq.def(py::self == py::self); - dq.def(py::self != py::self); - dq.def(- py::self); + dq.def(py::self + py::self, "Returns the dual quaternion addition between this dual quaternion and another."); + dq.def(py::self * py::self, "Returns the dual quaternion multiplication between this dual quaternion and another."); + dq.def(py::self - py::self, "Returns the dual quaternion subtraction between this dual quaternion and another."); + dq.def(py::self == py::self, "Returns true if this dual quaternion and another are equal, up to a numerical threshold."); + dq.def(py::self != py::self, "Returns true if this dual quaternion and another are different, up to a numerical threshold."); + dq.def(- py::self, "Returns the additive inverse of this dual quaternion."); //Double - dq.def(double() * py::self); - dq.def(py::self * double()); - dq.def(double() + py::self); - dq.def(py::self + double()); - dq.def(double() - py::self); - dq.def(py::self - double()); - dq.def(double() == py::self); - dq.def(py::self == double()); - dq.def(double() != py::self); - dq.def(py::self != double()); + dq.def(double() * py::self, "Returns the multiplication between a scalar and this dual quaternion."); + dq.def(py::self * double(), "Returns the multiplication between this dual quaternion and a scalar."); + dq.def(double() + py::self, "Returns the addition between a scalar and this dual quaternion."); + dq.def(py::self + double(), "Returns the addition between this dual quaternion and a scalar."); + dq.def(double() - py::self, "Returns the subtraction between a scalar and this dual quaternion."); + dq.def(py::self - double(), "Returns the subtraction between this dual quaternion and a scalar."); + dq.def(double() == py::self, "Returns true if a scalar and this dual quaternion are equal, up to a numerical threshold."); + dq.def(py::self == double(), "Returns true if this dual quaternion and a scalar are equal, up to a numerical threshold."); + dq.def(double() != py::self, "Returns true if a scalar and this dual quaternion are different, up to a numerical threshold."); + dq.def(py::self != double(), "Returns true if this dual quaternion and a scalar are different, up to a numerical threshold."); ///Namespace Functions - m.def("C8" ,&DQ_robotics::C8, "Returns the C8 matrix."); - m.def("C4" ,&DQ_robotics::C4, "Returns the C4 matrix."); - m.def("P" ,&DQ_robotics::P, "Retrieves the primary part of a DQ."); - m.def("D" ,&DQ_robotics::D, "Retrieves the dual part of a DQ."); - m.def("Re" ,&DQ_robotics::Re, "Retrieves the real part of a DQ."); - m.def("Im" ,&DQ_robotics::Im, "Retrieves the imaginary part of a DQ."); - m.def("conj" ,&DQ_robotics::conj, "Retrieves the conjugate of a DQ."); - m.def("norm" ,&DQ_robotics::norm, "Retrieves the norm of a DQ."); - m.def("inv" ,&DQ_robotics::inv, "Retrieves the inverse of a DQ."); - m.def("translation" ,&DQ_robotics::translation, "Retrieves the translation represented by a unit DQ."); - m.def("rotation" ,&DQ_robotics::rotation, "Retrieves the rotation represented by a unit DQ."); - m.def("rotation_axis" ,&DQ_robotics::rotation_axis, "Retrieves the rotation axis represented by a unit DQ."); - m.def("rotation_angle" ,&DQ_robotics::rotation_angle, "Retrieves the rotation angle represented by a unit DQ."); - m.def("log" ,&DQ_robotics::log, "Retrieves the logarithm of a DQ."); - m.def("exp" ,&DQ_robotics::exp, "Retrieves the exp of a DQ."); - m.def("pow" ,&DQ_robotics::pow, "Retrieves the pow of a DQ."); - m.def("tplus" ,&DQ_robotics::tplus, "Retrieves the tplus operators for a DQ."); - m.def("pinv" ,(DQ (*) (const DQ&)) &DQ_robotics::pinv ,"Retrieves the pinv of a DQ."); - m.def("dec_mult" ,&DQ_robotics::dec_mult, "Retrieves the dec mult of a DQ."); - m.def("hamiplus4" ,&DQ_robotics::hamiplus4, "Retrieves the H+ operator for the primary part of a DQ."); - m.def("haminus4" ,&DQ_robotics::haminus4, "Retrieves the H- operator for the primary part of a DQ."); - m.def("hamiplus8" ,&DQ_robotics::hamiplus8, "Retrieves the H+ operator for a DQ."); - m.def("haminus8" ,&DQ_robotics::haminus8, "Retrieves the H- operator for a DQ."); - m.def("vec3" ,&DQ_robotics::vec3, "Retrieves the pure part of the primary part of a DQ as a vector."); - m.def("vec4" ,&DQ_robotics::vec4, "Retrieves the primary part of a DQ as a vector."); - m.def("vec6" ,&DQ_robotics::vec6, "Retrieves the pure part of a DQ as a vector."); - m.def("vec8" ,&DQ_robotics::vec8, "Retrieves the DQ as a vector."); - m.def("normalize" ,&DQ_robotics::normalize, "Returns a normalized DQ."); - m.def("generalized_jacobian",&DQ_robotics::generalized_jacobian, "Retrieves the generalized Jacobian of a DQ."); - m.def("sharp" ,&DQ_robotics::sharp, "Returns the sharp DQ"); - m.def("crossmatrix4" ,&DQ_robotics::crossmatrix4, "Returns the crossmatrix4 operator."); - m.def("Ad" ,&DQ_robotics::Ad, "Retrieves the adjoint transformation of a DQ."); - m.def("Adsharp" ,&DQ_robotics::Adsharp, "Retrieves the adjoint sharp transformation of a DQ."); - m.def("cross" ,&DQ_robotics::cross, "Returns the result of the cross product between two DQ."); - m.def("dot" ,&DQ_robotics::dot, "Returns the result of the dot product between two DQ."); - m.def("Q4" ,&DQ_robotics::Q4, "Retrieves the partial derivative of a unit quaternion with respect to its logarithm."); - m.def("Q8" ,&DQ_robotics::Q8, "Retrieves the partial derivative of a unit DQ with respect to its logarithm."); + m.def("C8" ,&DQ_robotics::C8, "Returns the conjugator matrix associated with vec8()."); + m.def("C4" ,&DQ_robotics::C4, "Returns the conjugator matrix associated with vec4()."); + m.def("P" ,&DQ_robotics::P, py::arg("dq"), "Returns the primary part of `dq`."); + m.def("D" ,&DQ_robotics::D, py::arg("dq"), "Returns the dual part of `dq`."); + m.def("Re" ,&DQ_robotics::Re, py::arg("dq"), "Returns the real part of `dq`."); + m.def("Im" ,&DQ_robotics::Im, py::arg("dq"), "Returns the imaginary part of `dq`."); + m.def("conj" ,&DQ_robotics::conj, py::arg("dq"), "Returns the conjugate of `dq`."); + m.def("norm" ,&DQ_robotics::norm, py::arg("dq"), "Returns the dual scalar corresponding to the norm of `dq`."); + m.def("inv" ,&DQ_robotics::inv, py::arg("dq"), "Returns the inverse of `dq`, given by `conj(dq)/(norm(dq)^2)`."); + m.def("translation" ,&DQ_robotics::translation, py::arg("dq"), "Returns the translation quaternion of the unit dual quaternion `dq`."); + m.def("rotation" ,&DQ_robotics::rotation, py::arg("dq"), "Returns the rotation quaternion of the unit dual quaternion `dq`."); + m.def("rotation_axis" ,&DQ_robotics::rotation_axis, py::arg("dq"), "Returns the rotation axis of the unit dual quaternion `dq`."); + m.def("rotation_angle" ,&DQ_robotics::rotation_angle, py::arg("dq"), "Returns the rotation angle of the unit dual quaternion `dq`."); + m.def("log" ,&DQ_robotics::log, py::arg("dq"), "Returns the logarithm of `dq`."); + m.def("exp" ,&DQ_robotics::exp, py::arg("dq"), "Returns the exponential of the pure dual quaternion `dq`."); + m.def("pow" ,&DQ_robotics::pow, py::arg("dq"), py::arg("a"), "Returns `dq` raised to the power of `a`."); + m.def("tplus" ,&DQ_robotics::tplus, py::arg("dq"), "Returns the unit dual quaternion corresponding to the transformation of `dq`."); + m.def("pinv" ,(DQ (*) (const DQ&)) &DQ_robotics::pinv , py::arg("dq"), "Returns the Moore-Penrose pseudoinverse of `dq`."); + m.def("dec_mult" ,&DQ_robotics::dec_mult, py::arg("dq1"), py::arg("dq2"), "Returns the decompositional multiplication between `dq1` and `dq2`."); + m.def("hamiplus4" ,&DQ_robotics::hamiplus4, py::arg("dq"), "Returns the Hamilton operator H+ of `dq`, restricted to its primary part."); + m.def("haminus4" ,&DQ_robotics::haminus4, py::arg("dq"), "Returns the Hamilton operator H- of `dq`, restricted to its primary part."); + m.def("hamiplus8" ,&DQ_robotics::hamiplus8, py::arg("dq"), "Returns the Hamilton operator H+ of `dq`."); + m.def("haminus8" ,&DQ_robotics::haminus8, py::arg("dq"), "Returns the Hamilton operator H- of `dq`."); + m.def("vec3" ,&DQ_robotics::vec3, py::arg("dq"), "Maps the primary part of `dq` into a 3-dimensional vector."); + m.def("vec4" ,&DQ_robotics::vec4, py::arg("dq"), "Maps the primary part of `dq` into a 4-dimensional vector."); + m.def("vec6" ,&DQ_robotics::vec6, py::arg("dq"), "Maps `dq` into a 6-dimensional vector, discarding the real part of both the primary and dual components."); + m.def("vec8" ,&DQ_robotics::vec8, py::arg("dq"), "Maps `dq` into an 8-dimensional vector."); + m.def("normalize" ,&DQ_robotics::normalize, py::arg("dq"), "Returns `dq` normalized to unit norm."); + m.def("generalized_jacobian",&DQ_robotics::generalized_jacobian, py::arg("dq"), "Returns the generalized Jacobian used in the mapping between the time derivative of the unit dual quaternion `dq` and the twist it represents."); + m.def("sharp" ,&DQ_robotics::sharp, py::arg("dq"), "Returns the sharp conjugate of `dq`."); + m.def("crossmatrix4" ,&DQ_robotics::crossmatrix4, py::arg("dq"), "Maps the pure quaternion `dq` into an expanded skew-symmetric matrix representation of the cross product."); + m.def("Ad" ,&DQ_robotics::Ad, py::arg("dq1"), py::arg("dq2"), "Returns the adjoint transformation `dq1 * dq2 * dq1'`."); + m.def("Adsharp" ,&DQ_robotics::Adsharp, py::arg("dq1"), py::arg("dq2"), "Returns the sharp adjoint transformation `sharp(dq1) * dq2 * dq1'`."); + m.def("cross" ,&DQ_robotics::cross, py::arg("dq1"), py::arg("dq2"), "Returns the cross product between the pure dual quaternions `dq1` and `dq2`."); + m.def("dot" ,&DQ_robotics::dot, py::arg("dq1"), py::arg("dq2"), "Returns the dot product between the pure dual quaternions `dq1` and `dq2`."); + m.def("Q4" ,&DQ_robotics::Q4, py::arg("dq"), "Given the unit quaternion `dq`, returns the partial derivative of that quaternion with respect to its logarithm."); + m.def("Q8" ,&DQ_robotics::Q8, py::arg("dq"), "Given the unit dual quaternion `dq`, returns the partial derivative of `dq` with respect to its logarithm."); - m.def("is_unit" ,&DQ_robotics::is_unit, "Returns true if the DQ has unit norm, false otherwise."); - m.def("is_pure" ,&DQ_robotics::is_pure, "Returns true if the DQ is pure, false otherwise."); - m.def("is_real" ,&DQ_robotics::is_real, "Returns true if the DQ is a real dual number, false otherwise."); - m.def("is_real_number" ,&DQ_robotics::is_real_number, "Returns true if the DQ is a real number, false otherwise."); - m.def("is_quaternion" ,&DQ_robotics::is_quaternion, "Returns true if the DQ is a quaternion, false otherwise."); - m.def("is_pure_quaternion" ,&DQ_robotics::is_pure_quaternion, "Returns true if the DQ is a pure quaternion, false otherwise."); - m.def("is_line" ,&DQ_robotics::is_line, "Returns true if the DQ is a Plucker line, false otherwise."); - m.def("is_plane" ,&DQ_robotics::is_plane, "Returns true if the DQ is a plane, false otherwise."); + m.def("is_unit" ,&DQ_robotics::is_unit, py::arg("dq"), "Returns true if `dq` is a unit norm dual quaternion, false otherwise."); + m.def("is_pure" ,&DQ_robotics::is_pure, py::arg("dq"), "Returns true if `dq` is pure (i.e., `Re(dq) = 0`), false otherwise."); + m.def("is_real" ,&DQ_robotics::is_real, py::arg("dq"), "Returns true if the imaginary part of `dq` is zero, false otherwise."); + m.def("is_real_number" ,&DQ_robotics::is_real_number, py::arg("dq"), "Returns true if both the dual and imaginary parts of `dq` are zero, false otherwise."); + m.def("is_quaternion" ,&DQ_robotics::is_quaternion, py::arg("dq"), "Returns true if the dual part of `dq` is zero, false otherwise."); + m.def("is_pure_quaternion" ,&DQ_robotics::is_pure_quaternion, py::arg("dq"), "Returns true if `dq` is a pure quaternion (i.e., `Re(dq) = D(dq) = 0`), false otherwise."); + m.def("is_line" ,&DQ_robotics::is_line, py::arg("dq"), "Returns true if `dq` is a Plucker line (i.e., `Re(dq) = 0` and `norm(dq) = 1`), false otherwise."); + m.def("is_plane" ,&DQ_robotics::is_plane, py::arg("dq"), "Returns true if `dq` is a plane (i.e., it has unit norm and `Im(D(dq)) = 0`), false otherwise."); ///Namespace readonly m.attr("DQ_threshold") = DQ_threshold; diff --git a/src/dqrobotics_module.cpp b/src/dqrobotics_module.cpp index 182f9c1..c33fc8a 100644 --- a/src/dqrobotics_module.cpp +++ b/src/dqrobotics_module.cpp @@ -22,6 +22,10 @@ This file is part of DQ Robotics. #include "dqrobotics_module.h" +/** + * @brief Defines the `_dqrobotics` Python extension module and registers all + * of its classes, functions, enumerations, and submodules. + */ PYBIND11_MODULE(_dqrobotics, m) { //DQ Class @@ -31,7 +35,7 @@ PYBIND11_MODULE(_dqrobotics, m) { * Utils * **************************************************/ //dqrobotics/utils/ - py::module utils_py = m.def_submodule("_utils","A submodule of dqrobotics"); + py::module utils_py = m.def_submodule("_utils","Linear-algebra, geometric, and mathematical utilities used throughout dqrobotics."); //DQ_LinearAlgebra init_DQ_LinearAlgebra_py(utils_py); @@ -45,7 +49,7 @@ PYBIND11_MODULE(_dqrobotics, m) { /***************************************************** * Robot Modeling * **************************************************/ - py::module robot_modeling = m.def_submodule("_robot_modeling", "The robot_modeling submodule of dqrobotics"); + py::module robot_modeling = m.def_submodule("_robot_modeling", "Kinematic models of serial, mobile, cooperative dual-arm, and whole-body robots."); //DQ_Kinematics init_DQ_Kinematics_py(robot_modeling); @@ -83,36 +87,42 @@ PYBIND11_MODULE(_dqrobotics, m) { /***************************************************** * Robots Kinematic Models * **************************************************/ - py::module robots_py = m.def_submodule("_robots", "A submodule of dqrobotics"); + py::module robots_py = m.def_submodule("_robots", "Ready-to-use kinematic models of well-known commercial robot manipulators."); //#include - py::class_ ax18manipulatorrobot_py(robots_py, "Ax18ManipulatorRobot"); - ax18manipulatorrobot_py.def_static("kinematics",&Ax18ManipulatorRobot::kinematics,"Returns the kinematics of the Ax18ManipulatorRobot"); + py::class_ ax18manipulatorrobot_py(robots_py, "Ax18ManipulatorRobot", + "Provides the kinematic model of the AX-18 manipulator arm."); + ax18manipulatorrobot_py.def_static("kinematics",&Ax18ManipulatorRobot::kinematics,"Returns the kinematic model of the AX-18 manipulator arm."); //#include - py::class_ barrettwamarmrobot_py(robots_py, "BarrettWamArmRobot"); - barrettwamarmrobot_py.def_static("kinematics",&BarrettWamArmRobot::kinematics,"Returns the kinematics of the BarrettWamArmRobot"); + py::class_ barrettwamarmrobot_py(robots_py, "BarrettWamArmRobot", + "Provides the kinematic model of the Barrett WAM arm robot manipulator."); + barrettwamarmrobot_py.def_static("kinematics",&BarrettWamArmRobot::kinematics,"Returns the kinematic model of the Barrett WAM arm robot manipulator."); //#include - py::class_ comausmartsixrobot_py(robots_py, "ComauSmartSixRobot"); - comausmartsixrobot_py.def_static("kinematics",&ComauSmartSixRobot::kinematics,"Returns the kinematics of the ComauSmartSixRobot"); + py::class_ comausmartsixrobot_py(robots_py, "ComauSmartSixRobot", + "Provides the kinematic model of the COMAU SmartSiX robot manipulator."); + comausmartsixrobot_py.def_static("kinematics",&ComauSmartSixRobot::kinematics,"Returns the kinematic model of the COMAU SmartSiX robot manipulator."); //#include - py::class_ kukalw4robot_py(robots_py, "KukaLw4Robot"); - kukalw4robot_py.def_static("kinematics",&KukaLw4Robot::kinematics,"Returns the kinematics of the KukaLw4Robot"); + py::class_ kukalw4robot_py(robots_py, "KukaLw4Robot", + "Provides the kinematic model of the KUKA LWR4 robot manipulator."); + kukalw4robot_py.def_static("kinematics",&KukaLw4Robot::kinematics,"Returns the kinematic model of the KUKA LWR4 robot manipulator."); //#include - py::class_ kukayoubotrobot_py(robots_py, "KukaYoubotRobot"); - kukayoubotrobot_py.def_static("kinematics",&KukaYoubotRobot::kinematics,"Returns the kinematics of the KukaYoubotRobot"); + py::class_ kukayoubotrobot_py(robots_py, "KukaYoubotRobot", + "Provides the whole-body kinematic model of the KUKA youBot mobile manipulator."); + kukayoubotrobot_py.def_static("kinematics",&KukaYoubotRobot::kinematics,"Returns the whole-body kinematic model of the KUKA youBot mobile manipulator."); //#include - py::class_ frankaemikapandarobot_py(robots_py, "FrankaEmikaPandaRobot"); - frankaemikapandarobot_py.def_static("kinematics",&FrankaEmikaPandaRobot::kinematics,"Returns the kinematics of the FrankaEmikaPandaRobot"); + py::class_ frankaemikapandarobot_py(robots_py, "FrankaEmikaPandaRobot", + "Provides the kinematic model of the Franka Emika Panda robot manipulator."); + frankaemikapandarobot_py.def_static("kinematics",&FrankaEmikaPandaRobot::kinematics,"Returns the kinematic model of the Franka Emika Panda robot, as calibrated by the manufacturer."); /***************************************************** * Solvers * **************************************************/ - py::module solvers = m.def_submodule("_solvers", "The solvers submodule of dqrobotics"); + py::module solvers = m.def_submodule("_solvers", "Quadratic-programming solver interfaces used by the QP-based kinematic controllers."); //DQ_QuadraticProgrammingSolver init_DQ_QuadraticProgrammingSolver_py(solvers); @@ -120,17 +130,18 @@ PYBIND11_MODULE(_dqrobotics, m) { /***************************************************** * Robot Control * **************************************************/ - py::module robot_control = m.def_submodule("_robot_control", "The robot_control submodule of dqrobotics"); - - py::enum_(robot_control, "ControlObjective") - .value("Line", ControlObjective::Line) - .value("None", ControlObjective::None) - .value("Pose", ControlObjective::Pose) - .value("Plane", ControlObjective::Plane) - .value("Distance", ControlObjective::Distance) - .value("DistanceToPlane",ControlObjective::DistanceToPlane) - .value("Rotation", ControlObjective::Rotation) - .value("Translation", ControlObjective::Translation) + py::module robot_control = m.def_submodule("_robot_control", "Kinematic controllers that drive a robot's task-space error to zero."); + + py::enum_(robot_control, "ControlObjective", + "Enumerates the task-space objectives supported by DQ_KinematicController.") + .value("Line", ControlObjective::Line, "Control a line primitive attached to the end-effector.") + .value("None", ControlObjective::None, "No control objective has been selected yet.") + .value("Pose", ControlObjective::Pose, "Control the full end-effector pose.") + .value("Plane", ControlObjective::Plane, "Control a plane primitive attached to the end-effector.") + .value("Distance", ControlObjective::Distance, "Control the squared distance between the end-effector translation and the origin.") + .value("DistanceToPlane",ControlObjective::DistanceToPlane,"Control the signed distance from the end-effector point to a target plane.") + .value("Rotation", ControlObjective::Rotation, "Control only the end-effector orientation.") + .value("Translation", ControlObjective::Translation, "Control only the end-effector translation.") .export_values(); //DQ_KinematicController @@ -154,12 +165,12 @@ PYBIND11_MODULE(_dqrobotics, m) { /***************************************************** * Interfaces Submodule * **************************************************/ - py::module interfaces_py = m.def_submodule("_interfaces", "A submodule of dqrobotics"); + py::module interfaces_py = m.def_submodule("_interfaces", "Interfaces to third-party simulators and data formats."); /***************************************************** * Json11 submodule * **************************************************/ - py::module json11_py = interfaces_py.def_submodule("_json11", "A submodule of dqrobotics"); + py::module json11_py = interfaces_py.def_submodule("_json11", "Reads dqrobotics objects (DQ, robot models) serialized as JSON using the json11 library."); //DQ_JsonReader init_DQ_JsonReader_py(json11_py); diff --git a/src/interfaces/json11/DQ_JsonReader_py.cpp b/src/interfaces/json11/DQ_JsonReader_py.cpp index 6cd2a33..d106871 100644 --- a/src/interfaces/json11/DQ_JsonReader_py.cpp +++ b/src/interfaces/json11/DQ_JsonReader_py.cpp @@ -22,12 +22,28 @@ This file is part of DQ Robotics. #include "../../dqrobotics_module.h" +/** + * @brief Binds `DQ_JsonReader`, which reads supported robot-description JSON + * files and constructs serial manipulator objects from them, to the Python + * module @p m. + */ void init_DQ_JsonReader_py(py::module& m) { - py::class_ jsonreader_py(m,"DQ_JsonReader"); - jsonreader_py.def(py::init<>()); - - jsonreader_py.def_static("get_serial_manipulator_dh_from_json",&DQ_JsonReader::get_from_json,"Gets a DQ_KinematicsDH instance from a .json file"); - jsonreader_py.def_static("get_serial_manipulator_denso_from_json",&DQ_JsonReader::get_from_json,"Gets a DQ_KinematicsDenso instance from a .json file"); + py::class_ jsonreader_py( + m, + "DQ_JsonReader", + "Reads supported robot-description JSON files and constructs serial manipulator objects from them."); + jsonreader_py.def(py::init<>(), "Constructs a JSON reader instance."); + + jsonreader_py.def_static( + "get_serial_manipulator_dh_from_json", + &DQ_JsonReader::get_from_json, + py::arg("file"), + "Reads a JSON file describing a DQ_SerialManipulatorDH, converts angle fields according to the file's angle mode, initializes the common serial-manipulator properties, and returns the resulting model."); + jsonreader_py.def_static( + "get_serial_manipulator_denso_from_json", + &DQ_JsonReader::get_from_json, + py::arg("file"), + "Reads a JSON file describing a DQ_SerialManipulatorDenso, converts angle fields according to the file's angle mode, initializes the common serial-manipulator properties, and returns the resulting model."); //This might be relevant in the future https://github.com/pybind/pybind11/issues/199 } diff --git a/src/interfaces/vrep/DQ_SerialVrepRobot_py.cpp b/src/interfaces/vrep/DQ_SerialVrepRobot_py.cpp index 586ebf8..75bd376 100644 --- a/src/interfaces/vrep/DQ_SerialVrepRobot_py.cpp +++ b/src/interfaces/vrep/DQ_SerialVrepRobot_py.cpp @@ -22,6 +22,11 @@ This file is part of DQ Robotics. #include "../../dqrobotics_module.h" +/** + * @brief Binds `DQ_SerialVrepRobot`, a serial-robot wrapper that exposes joint + * names, target commands, velocities, and torques in CoppeliaSim, to the + * Python module @p m. + */ void init_DQ_SerialVrepRobot_py(py::module& m) { /***************************************************** @@ -31,19 +36,40 @@ void init_DQ_SerialVrepRobot_py(py::module& m) DQ_SerialVrepRobot, std::shared_ptr, DQ_VrepRobot - > dqsv_robot(m,"DQ_SerialVrepRobot"); + > dqsv_robot( + m, + "DQ_SerialVrepRobot", + "Serial robot wrapper for exchanging joint names, target commands, velocities, and torques with CoppeliaSim."); - dqsv_robot.def("get_joint_names", &DQ_SerialVrepRobot::get_joint_names, "Gets the joint names used in CoppeliaSim."); + dqsv_robot.def("get_joint_names", + &DQ_SerialVrepRobot::get_joint_names, + "Gets the joint names used in CoppeliaSim."); - dqsv_robot.def("set_target_configuration_space_positions", &DQ_SerialVrepRobot::set_target_configuration_space_positions, "Sets the target configuration space positions in CoppeliaSim."); + dqsv_robot.def("set_target_configuration_space_positions", + &DQ_SerialVrepRobot::set_target_configuration_space_positions, + py::arg("q"), + "Sets the target configuration-space positions in CoppeliaSim."); - dqsv_robot.def("get_configuration_space_velocities", &DQ_SerialVrepRobot::get_configuration_space_velocities, "Sets the target configuration space velocities in CoppeliaSim."); - dqsv_robot.def("set_target_configuration_space_velocities", &DQ_SerialVrepRobot::set_target_configuration_space_velocities, "Gets the configuration space velocities in CoppeliaSim."); + dqsv_robot.def("get_configuration_space_velocities", + &DQ_SerialVrepRobot::get_configuration_space_velocities, + "Gets the configuration-space velocities from CoppeliaSim."); + dqsv_robot.def("set_target_configuration_space_velocities", + &DQ_SerialVrepRobot::set_target_configuration_space_velocities, + py::arg("q_dot"), + "Sets the target configuration-space velocities in CoppeliaSim."); - dqsv_robot.def("set_configuration_space_torques", &DQ_SerialVrepRobot::set_configuration_space_torques, "Sets the configuration space torques in CoppeliaSim."); - dqsv_robot.def("get_configuration_space_torques", &DQ_SerialVrepRobot::get_configuration_space_torques, "Gets the configuration space torques in CoppeliaSim."); + dqsv_robot.def("set_configuration_space_torques", + &DQ_SerialVrepRobot::set_configuration_space_torques, + py::arg("torques"), + "Sets the configuration-space torques in CoppeliaSim."); + dqsv_robot.def("get_configuration_space_torques", + &DQ_SerialVrepRobot::get_configuration_space_torques, + "Gets the configuration-space torques from CoppeliaSim."); //Deprecated - dqsv_robot.def("send_q_target_to_vrep", &DQ_SerialVrepRobot::send_q_target_to_vrep, "Send target joint values to CoppeliaSim."); + dqsv_robot.def("send_q_target_to_vrep", + &DQ_SerialVrepRobot::send_q_target_to_vrep, + py::arg("q"), + "Deprecated alias for setting the target configuration-space positions in CoppeliaSim."); } diff --git a/src/interfaces/vrep/DQ_VrepInterface_py.cpp b/src/interfaces/vrep/DQ_VrepInterface_py.cpp index d7705fa..243639f 100644 --- a/src/interfaces/vrep/DQ_VrepInterface_py.cpp +++ b/src/interfaces/vrep/DQ_VrepInterface_py.cpp @@ -29,6 +29,11 @@ This file is part of DQ Robotics. //Default arguments added with: //https://pybind11.readthedocs.io/en/stable/basics.html#default-args +/** + * @brief Binds `DQ_VrepInterface`, an interface for connecting to + * V-REP/CoppeliaSim and exchanging simulation, object, joint, and inertial + * data, to the Python module @p m. + */ void init_DQ_VrepInterface_py(py::module& m) { /***************************************************** @@ -37,9 +42,14 @@ void init_DQ_VrepInterface_py(py::module& m) py::class_< DQ_VrepInterface, std::shared_ptr - > dqvrepinterface_py(m,"DQ_VrepInterface"); - dqvrepinterface_py.def(py::init<>()); - dqvrepinterface_py.def(py::init()); + > dqvrepinterface_py( + m, + "DQ_VrepInterface", + "Interface for connecting to V-REP/CoppeliaSim and exchanging simulation, object, joint, and inertial data."); + dqvrepinterface_py.def(py::init<>(), "Constructs a V-REP/CoppeliaSim interface."); + dqvrepinterface_py.def(py::init(), + py::arg("termination_flag"), + "Constructs a V-REP/CoppeliaSim interface that uses an external atomic termination flag."); py::enum_(dqvrepinterface_py, "OP_MODES") .value("OP_BUFFER", DQ_VrepInterface::OP_MODES::OP_BUFFER) @@ -60,25 +70,39 @@ void init_DQ_VrepInterface_py(py::module& m) .value("ABSOLUTE_FRAME", DQ_VrepInterface::REFERENCE_FRAMES::ABSOLUTE_FRAME) .export_values(); - dqvrepinterface_py.def("connect",(bool (DQ_VrepInterface::*) (const int&, const int&, const int&))&DQ_VrepInterface::connect,"Connects to V-REP in local machine."); - dqvrepinterface_py.def("connect",(bool (DQ_VrepInterface::*) (const std::string&, const int&, const int&, const int&))&DQ_VrepInterface::connect,"Connects to V-REP with a given ip."); + dqvrepinterface_py.def("connect", + (bool (DQ_VrepInterface::*) (const int&, const int&, const int&))&DQ_VrepInterface::connect, + py::arg("port"), + py::arg("max_attempts"), + py::arg("attempt_interval_in_ms"), + "Attempts to connect to a V-REP/CoppeliaSim server on the local machine."); + dqvrepinterface_py.def("connect", + (bool (DQ_VrepInterface::*) (const std::string&, const int&, const int&, const int&))&DQ_VrepInterface::connect, + py::arg("ip"), + py::arg("port"), + py::arg("max_attempts"), + py::arg("attempt_interval_in_ms"), + "Attempts to connect to a V-REP/CoppeliaSim server at the given IP address."); - dqvrepinterface_py.def("disconnect", &DQ_VrepInterface::disconnect,"Disconnects from V-REP."); - dqvrepinterface_py.def("disconnect_all",&DQ_VrepInterface::disconnect_all,"Disconnect all from V-REP"); + dqvrepinterface_py.def("disconnect", &DQ_VrepInterface::disconnect, "Disconnects from the V-REP/CoppeliaSim server."); + dqvrepinterface_py.def("disconnect_all", &DQ_VrepInterface::disconnect_all, "Disconnects all active V-REP/CoppeliaSim connections."); - dqvrepinterface_py.def("start_simulation",&DQ_VrepInterface::start_simulation,"Start simulation"); - dqvrepinterface_py.def("stop_simulation", &DQ_VrepInterface::stop_simulation,"Stops simulation"); + dqvrepinterface_py.def("start_simulation", &DQ_VrepInterface::start_simulation, "Starts the simulation."); + dqvrepinterface_py.def("stop_simulation", &DQ_VrepInterface::stop_simulation, "Stops the simulation."); - dqvrepinterface_py.def("is_simulation_running",&DQ_VrepInterface::is_simulation_running,"Checks whether the simulation is running or not"); + dqvrepinterface_py.def("is_simulation_running", &DQ_VrepInterface::is_simulation_running, "Returns whether the simulation is currently running."); // void set_synchronous(const bool& flag); - dqvrepinterface_py.def("set_synchronous", (void (DQ_VrepInterface::*) (const bool&))&DQ_VrepInterface::set_synchronous, "Sets synchronous mode"); + dqvrepinterface_py.def("set_synchronous", + (void (DQ_VrepInterface::*) (const bool&))&DQ_VrepInterface::set_synchronous, + py::arg("flag"), + "Enables or disables synchronous simulation mode."); //void trigger_next_simulation_step(); - dqvrepinterface_py.def("trigger_next_simulation_step", &DQ_VrepInterface::trigger_next_simulation_step, "Sends a synchronization trigger signal to the server."); + dqvrepinterface_py.def("trigger_next_simulation_step", &DQ_VrepInterface::trigger_next_simulation_step, "Sends the synchronization trigger for the next simulation step."); - //void wait_for_simulation_step_to_end(); - dqvrepinterface_py.def("wait_for_simulation_step_to_end", &DQ_VrepInterface::wait_for_simulation_step_to_end, "Waits until the simulation step is finished."); + //void wait_for_simulation_step_to_end(); + dqvrepinterface_py.def("wait_for_simulation_step_to_end", &DQ_VrepInterface::wait_for_simulation_step_to_end, "Waits until the current simulation step finishes."); //dqvrepinterface_py.def("get_object_handle", &DQ_VrepInterface::get_object_handle,"Gets an object handle"); //dqvrepinterface_py.def("get_object_handles",&DQ_VrepInterface::get_object_handles,"Get object handles"); @@ -88,182 +112,193 @@ void init_DQ_VrepInterface_py(py::module& m) //dqvrepinterface_py.def("get_object_translation",(DQ (DQ_VrepInterface::*) (const int&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_translation,"Gets object translation."); dqvrepinterface_py.def("get_object_translation", (DQ (DQ_VrepInterface::*) (const std::string&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_translation, - "Gets object translation.", - py::arg("objectname")=std::string(""), - py::arg("relative_to_objectname")=VREP_OBJECTNAME_ABSOLUTE, - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("object_name") = std::string(""), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets an object's translation, optionally relative to another object."); //dqvrepinterface_py.def("set_object_translation",(void (DQ_VrepInterface::*) (const int&, const int&, const DQ&, const DQ_VrepInterface::OP_MODES&) const)&DQ_VrepInterface::set_object_translation,"Sets object translation."); //dqvrepinterface_py.def("set_object_translation",(void (DQ_VrepInterface::*) (const std::string&, const int&, const DQ&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_translation,"Sets object translation."); //dqvrepinterface_py.def("set_object_translation",(void (DQ_VrepInterface::*) (const int&, const std::string&, const DQ&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_translation,"Sets object translation."); dqvrepinterface_py.def("set_object_translation", (void (DQ_VrepInterface::*) (const std::string&, const DQ&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_translation, - "Sets object translation.", - py::arg("objectname")=std::string(""), - py::arg("t")=DQ(0), - py::arg("relative_to_objectname")=VREP_OBJECTNAME_ABSOLUTE, - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("object_name") = std::string(""), + py::arg("translation") = DQ(0), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets an object's translation, optionally relative to another object."); //dqvrepinterface_py.def("get_object_rotation",(DQ (DQ_VrepInterface::*) (const int&, const int&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_rotation,"Gets object rotation."); //dqvrepinterface_py.def("get_object_rotation",(DQ (DQ_VrepInterface::*) (const std::string&, const int&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_rotation,"Gets object rotation."); //dqvrepinterface_py.def("get_object_rotation",(DQ (DQ_VrepInterface::*) (const int&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_rotation,"Gets object rotation."); dqvrepinterface_py.def("get_object_rotation", (DQ (DQ_VrepInterface::*) (const std::string&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_rotation, - "Gets object rotation.", - py::arg("objectname")=std::string(""), - py::arg("relative_to_objectname")=VREP_OBJECTNAME_ABSOLUTE, - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("object_name") = std::string(""), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets an object's rotation, optionally relative to another object."); //dqvrepinterface_py.def("set_object_rotation",(void (DQ_VrepInterface::*) (const int&, const int&, const DQ&, const DQ_VrepInterface::OP_MODES&) const)&DQ_VrepInterface::set_object_rotation,"Sets object rotation."); //dqvrepinterface_py.def("set_object_rotation",(void (DQ_VrepInterface::*) (const std::string&, const int&, const DQ&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_rotation,"Sets object rotation."); //dqvrepinterface_py.def("set_object_rotation",(void (DQ_VrepInterface::*) (const int&, const std::string&, const DQ&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_rotation,"Sets object rotation."); dqvrepinterface_py.def("set_object_rotation", (void (DQ_VrepInterface::*) (const std::string&, const DQ&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_rotation, - "Sets object rotation.", - py::arg("objectname")=std::string(""), - py::arg("r")=DQ(1), - py::arg("relative_to_objectname")=VREP_OBJECTNAME_ABSOLUTE, - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("object_name") = std::string(""), + py::arg("rotation") = DQ(1), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets an object's rotation, optionally relative to another object."); //dqvrepinterface_py.def("get_object_pose",(DQ (DQ_VrepInterface::*) (const int&, const int&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_pose,"Gets object pose."); //dqvrepinterface_py.def("get_object_pose",(DQ (DQ_VrepInterface::*) (const std::string&, const int&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_pose,"Gets object pose."); //dqvrepinterface_py.def("get_object_pose",(DQ (DQ_VrepInterface::*) (const int&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_pose,"Gets object pose."); dqvrepinterface_py.def("get_object_pose", (DQ (DQ_VrepInterface::*) (const std::string&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_object_pose, - "Gets object pose.", - py::arg("objectname")=std::string(""), - py::arg("relative_to_objectname")=VREP_OBJECTNAME_ABSOLUTE, - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("object_name") = std::string(""), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets an object's pose, optionally relative to another object."); //dqvrepinterface_py.def("set_object_pose",(void (DQ_VrepInterface::*) (const int&, const int&, const DQ&, const DQ_VrepInterface::OP_MODES&) const)&DQ_VrepInterface::set_object_pose,"Sets object pose."); //dqvrepinterface_py.def("set_object_pose",(void (DQ_VrepInterface::*) (const std::string&, const int&, const DQ&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_pose,"Sets object pose."); //dqvrepinterface_py.def("set_object_pose",(void (DQ_VrepInterface::*) (const int&, const std::string&, const DQ&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_pose,"Sets object pose."); dqvrepinterface_py.def("set_object_pose", (void (DQ_VrepInterface::*) (const std::string&, const DQ&, const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_object_pose, - "Sets object pose.", - py::arg("objectname")=std::string(""), - py::arg("h")=DQ(1), - py::arg("relative_to_objectname")=VREP_OBJECTNAME_ABSOLUTE, - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); - - dqvrepinterface_py.def("get_object_poses",&DQ_VrepInterface::get_object_poses,"Get the poses of many objects"); - dqvrepinterface_py.def("set_object_poses",&DQ_VrepInterface::set_object_poses,"Set object poses of many objects"); + py::arg("object_name") = std::string(""), + py::arg("pose") = DQ(1), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets an object's pose, optionally relative to another object."); + + dqvrepinterface_py.def("get_object_poses", + &DQ_VrepInterface::get_object_poses, + py::arg("object_names"), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets the poses of multiple objects, optionally relative to another object."); + dqvrepinterface_py.def("set_object_poses", + &DQ_VrepInterface::set_object_poses, + py::arg("object_names"), + py::arg("poses"), + py::arg("relative_to_object_name") = VREP_OBJECTNAME_ABSOLUTE, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets the poses of multiple objects, optionally relative to another object."); //dqvrepinterface_py.def("set_joint_position",(void (DQ_VrepInterface::*) (const int&, const double&, const DQ_VrepInterface::OP_MODES&) const) &DQ_VrepInterface::set_joint_position,"Set joint position"); dqvrepinterface_py.def("set_joint_position", (void (DQ_VrepInterface::*) (const std::string&, const double&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_position, - "Set joint position", - py::arg("jointname")=std::string(""), - py::arg("angle_rad")=0.0, - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_name") = std::string(""), + py::arg("angle_rad") = 0.0, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets one joint position in radians."); //dqvrepinterface_py.def("set_joint_target_position",(void (DQ_VrepInterface::*) (const int&, const double&, const DQ_VrepInterface::OP_MODES&) const) &DQ_VrepInterface::set_joint_target_position,"Set joint position"); dqvrepinterface_py.def("set_joint_target_position", (void (DQ_VrepInterface::*) (const std::string&, const double&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_target_position, - "Set joint position", - py::arg("jointname")=std::string(""), - py::arg("angle_rad")=0.0, - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_name") = std::string(""), + py::arg("angle_rad") = 0.0, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets one joint target position in radians."); //dqvrepinterface_py.def("get_joint_position",(double (DQ_VrepInterface::*) (const int&, const DQ_VrepInterface::OP_MODES&) const) &DQ_VrepInterface::get_joint_position,"Get joint position"); dqvrepinterface_py.def("get_joint_position", (double (DQ_VrepInterface::*) (const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_joint_position, - "Get joint position", - py::arg("jointname")=std::string(""), - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("joint_name") = std::string(""), + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets one joint position in radians."); //dqvrepinterface_py.def("set_joint_positions",(void (DQ_VrepInterface::*) (const std::vector&, const VectorXd&, const DQ_VrepInterface::OP_MODES&) const) &DQ_VrepInterface::set_joint_positions,"Set joint positions"); dqvrepinterface_py.def("set_joint_positions", (void (DQ_VrepInterface::*) (const std::vector&, const VectorXd&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_positions, - "Set joint positions", - py::arg("jointnames")=std::vector(), - py::arg("angles_rad")=VectorXd::Zero(1), - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_names") = std::vector(), + py::arg("angles_rad") = VectorXd::Zero(1), + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets multiple joint positions in radians."); //dqvrepinterface_py.def("set_joint_target_positions",(void (DQ_VrepInterface::*) (const std::vector&, const VectorXd&, const DQ_VrepInterface::OP_MODES&) const) &DQ_VrepInterface::set_joint_target_positions,"Set joint positions"); dqvrepinterface_py.def("set_joint_target_positions", (void (DQ_VrepInterface::*) (const std::vector&, const VectorXd&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_target_positions, - "Set joint positions", - py::arg("jointnames")=std::vector(), - py::arg("angles_rad")=VectorXd::Zero(1), - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_names") = std::vector(), + py::arg("angles_rad") = VectorXd::Zero(1), + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets multiple joint target positions in radians."); //dqvrepinterface_py.def("get_joint_positions",(VectorXd (DQ_VrepInterface::*) (const std::vector&, const DQ_VrepInterface::OP_MODES&) const) &DQ_VrepInterface::get_joint_positions,"Get joint positions"); dqvrepinterface_py.def("get_joint_positions", (VectorXd (DQ_VrepInterface::*) (const std::vector&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_joint_positions, - "Get joint positions", - py::arg("jointnames")=std::vector(), - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("joint_names") = std::vector(), + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets multiple joint positions in radians."); //void set_joint_target_velocity(const std::string& jointname, const double& angle_dot_rad, const OP_MODES& opmode=OP_ONESHOT); dqvrepinterface_py.def("set_joint_target_velocity", (void (DQ_VrepInterface::*) (const std::string&, const double&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_target_velocity, - "Set joint velocity", - py::arg("jointname")=std::string(""), - py::arg("angle_dot_rad")=0.0, - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_name") = std::string(""), + py::arg("angle_dot_rad") = 0.0, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets one joint target velocity in radians per second."); //void set_joint_target_velocities(const std::vector& jointnames, const VectorXd& angles_dot_rad, const OP_MODES& opmode=OP_ONESHOT); dqvrepinterface_py.def("set_joint_target_velocities", (void (DQ_VrepInterface::*) (const std::vector&, const VectorXd&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_target_velocities, - "Set joint velcoties", - py::arg("jointnames")=std::vector(), - py::arg("angles_dot_rad")=VectorXd::Zero(1), - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_names") = std::vector(), + py::arg("angles_dot_rad") = VectorXd::Zero(1), + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets multiple joint target velocities in radians per second."); //double get_joint_velocity(const std::string& jointname, const OP_MODES& opmode=OP_AUTOMATIC); dqvrepinterface_py.def("get_joint_velocity", (double (DQ_VrepInterface::*) (const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_joint_velocity, - "Get joint velocity", - py::arg("jointname")=std::string(""), - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("joint_name") = std::string(""), + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets one joint velocity in radians per second."); //VectorXd get_joint_velocities(const std::vector& jointnames, const OP_MODES& opmode=OP_AUTOMATIC); dqvrepinterface_py.def("get_joint_velocities", (VectorXd (DQ_VrepInterface::*) (const std::vector&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_joint_velocities, - "Get joint velocities", - py::arg("jointnames")=std::vector(), - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("joint_names") = std::vector(), + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets multiple joint velocities in radians per second."); //void set_joint_torque(const std::string& jointname, const double& torque, const OP_MODES& opmode=OP_ONESHOT); dqvrepinterface_py.def("set_joint_torque", (void (DQ_VrepInterface::*) (const std::string&, const double&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_torque, - "Set joint torque", - py::arg("jointname")=std::string(""), - py::arg("torque")=0.0, - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_name") = std::string(""), + py::arg("torque") = 0.0, + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets one joint torque."); //void set_joint_torques(const std::vector& jointnames, const VectorXd& torques, const OP_MODES& opmode=OP_ONESHOT); dqvrepinterface_py.def("set_joint_torques", (void (DQ_VrepInterface::*) (const std::vector&, const VectorXd&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::set_joint_torques, - "Set joint torques", - py::arg("jointnames")=std::vector(), - py::arg("torques")=VectorXd::Zero(1), - py::arg("opmode")=DQ_VrepInterface::OP_ONESHOT); + py::arg("joint_names") = std::vector(), + py::arg("torques") = VectorXd::Zero(1), + py::arg("op_mode") = DQ_VrepInterface::OP_ONESHOT, + "Sets multiple joint torques."); //double get_joint_torque(const std::string& jointname, const OP_MODES& opmode=OP_AUTOMATIC); dqvrepinterface_py.def("get_joint_torque", (double (DQ_VrepInterface::*) (const std::string&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_joint_torque, - "Get joint torque", - py::arg("jointname")=std::string(""), - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("joint_name") = std::string(""), + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets one joint torque."); //VectorXd get_joint_torques(const std::vector& jointnames, const OP_MODES& opmode=OP_AUTOMATIC); dqvrepinterface_py.def("get_joint_torques", (VectorXd (DQ_VrepInterface::*) (const std::vector&, const DQ_VrepInterface::OP_MODES&))&DQ_VrepInterface::get_joint_torques, - "Get joint torques", - py::arg("jointnames")=std::vector(), - py::arg("opmode")=DQ_VrepInterface::OP_AUTOMATIC); + py::arg("joint_names") = std::vector(), + py::arg("op_mode") = DQ_VrepInterface::OP_AUTOMATIC, + "Gets multiple joint torques."); //double get_mass(const std::string& link_name, const std::string& function_name = "get_mass", const std::string& obj_name= "DQRoboticsApiCommandServer"); dqvrepinterface_py.def("get_mass", (double (DQ_VrepInterface::*) (const std::string&, const std::string&, const std::string&))&DQ_VrepInterface::get_mass, - "Get the mass of an object from CoppeliaSim", - py::arg("linkname")=std::string(""), - py::arg("function_name")=std::string("get_mass"), - py::arg("obj_name")=std::string("DQRoboticsApiCommandServer")); + py::arg("link_name") = std::string(""), + py::arg("function_name") = std::string("get_mass"), + py::arg("obj_name") = std::string("DQRoboticsApiCommandServer"), + "Gets the mass of an object from CoppeliaSim."); //DQ get_center_of_mass(const std::string& link_name, // const REFERENCE_FRAMES& reference_frame=BODY_FRAME, @@ -272,11 +307,11 @@ void init_DQ_VrepInterface_py(py::module& m) dqvrepinterface_py.def("get_center_of_mass", (DQ (DQ_VrepInterface::*) (const std::string&, const DQ_VrepInterface::REFERENCE_FRAMES&, const std::string&, const std::string&))&DQ_VrepInterface::get_center_of_mass, - "Get the center of mass of an object from CoppeliaSim", - py::arg("linkname")=std::string(""), - py::arg("reference_frame")=DQ_VrepInterface::BODY_FRAME, - py::arg("function_name")=std::string("get_center_of_mass"), - py::arg("obj_name")=std::string("DQRoboticsApiCommandServer")); + py::arg("link_name") = std::string(""), + py::arg("reference_frame") = DQ_VrepInterface::BODY_FRAME, + py::arg("function_name") = std::string("get_center_of_mass"), + py::arg("obj_name") = std::string("DQRoboticsApiCommandServer"), + "Gets the center of mass of an object from CoppeliaSim in the requested reference frame."); //MatrixXd get_inertia_matrix(const std::string& link_name, // const REFERENCE_FRAMES& reference_frame=BODY_FRAME, @@ -285,10 +320,10 @@ void init_DQ_VrepInterface_py(py::module& m) dqvrepinterface_py.def("get_inertia_matrix", (MatrixXd (DQ_VrepInterface::*) (const std::string&, const DQ_VrepInterface::REFERENCE_FRAMES&, const std::string&, const std::string&))&DQ_VrepInterface::get_inertia_matrix, - "Get the inertia matrix of an object from CoppeliaSim", - py::arg("linkname")=std::string(""), - py::arg("reference_frame")=DQ_VrepInterface::BODY_FRAME, - py::arg("function_name")=std::string("get_inertia"), - py::arg("obj_name")=std::string("DQRoboticsApiCommandServer")); + py::arg("link_name") = std::string(""), + py::arg("reference_frame") = DQ_VrepInterface::BODY_FRAME, + py::arg("function_name") = std::string("get_inertia"), + py::arg("obj_name") = std::string("DQRoboticsApiCommandServer"), + "Gets the inertia matrix of an object from CoppeliaSim in the requested reference frame."); } diff --git a/src/interfaces/vrep/DQ_VrepRobot_py.cpp b/src/interfaces/vrep/DQ_VrepRobot_py.cpp index 9fdd033..481fb8e 100644 --- a/src/interfaces/vrep/DQ_VrepRobot_py.cpp +++ b/src/interfaces/vrep/DQ_VrepRobot_py.cpp @@ -22,6 +22,10 @@ This file is part of DQ Robotics. #include "../../dqrobotics_module.h" +/** + * @brief Binds `DQ_VrepRobot`, a base robot wrapper that exposes + * configuration-space exchanges with CoppeliaSim, to the Python module @p m. + */ void init_DQ_VrepRobot_py(py::module& m) { /***************************************************** @@ -30,12 +34,25 @@ void init_DQ_VrepRobot_py(py::module& m) py::class_< DQ_VrepRobot, std::shared_ptr - > dqvreprobot_py(m,"DQ_VrepRobot"); - - dqvreprobot_py.def("set_configuration_space_positions", &DQ_VrepRobot::set_configuration_space_positions, "Sets the configuration space positions in CoppeliaSim."); - dqvreprobot_py.def("get_configuration_space_positions", &DQ_VrepRobot::get_configuration_space_positions, "Gets the configuration space positions in CoppeliaSim."); + > dqvreprobot_py( + m, + "DQ_VrepRobot", + "Base robot wrapper for reading and writing configuration-space values in CoppeliaSim."); + + dqvreprobot_py.def("set_configuration_space_positions", + &DQ_VrepRobot::set_configuration_space_positions, + py::arg("q"), + "Sets the robot configuration-space positions in CoppeliaSim."); + dqvreprobot_py.def("get_configuration_space_positions", + &DQ_VrepRobot::get_configuration_space_positions, + "Gets the robot configuration-space positions from CoppeliaSim."); //Deprecated - dqvreprobot_py.def("send_q_to_vrep", &DQ_VrepRobot::send_q_to_vrep, "Get joint values from vrep."); - dqvreprobot_py.def("get_q_from_vrep", &DQ_VrepRobot::get_q_from_vrep, "Send joint values to vrep."); + dqvreprobot_py.def("send_q_to_vrep", + &DQ_VrepRobot::send_q_to_vrep, + py::arg("q"), + "Deprecated alias for setting the robot configuration-space positions in CoppeliaSim."); + dqvreprobot_py.def("get_q_from_vrep", + &DQ_VrepRobot::get_q_from_vrep, + "Deprecated alias for getting the robot configuration-space positions from CoppeliaSim."); } diff --git a/src/robot_control/DQ_ClassicQPController_py.cpp b/src/robot_control/DQ_ClassicQPController_py.cpp index ada0921..7c6490b 100644 --- a/src/robot_control/DQ_ClassicQPController_py.cpp +++ b/src/robot_control/DQ_ClassicQPController_py.cpp @@ -22,16 +22,35 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_ClassicQPController`, which implements the classic + * quadratic-programming kinematic controller based on task-space variables, to + * the Python module @p m. + */ void init_DQ_ClassicQPController_py(py::module& m) { /***************************************************** * DQ ClassicQPController * **************************************************/ - py::class_ dq_classicqpcontroller_py(m,"DQ_ClassicQPController"); + py::class_ dq_classicqpcontroller_py( + m, + "DQ_ClassicQPController", + "Implements the classic quadratic-programming kinematic controller based on task-space variables."); dq_classicqpcontroller_py.def(py::init< const std::shared_ptr&, const std::shared_ptr& - >()); - dq_classicqpcontroller_py.def("compute_objective_function_symmetric_matrix", &DQ_ClassicQPController::compute_objective_function_symmetric_matrix, "Compute symmetric matrix."); - dq_classicqpcontroller_py.def("compute_objective_function_linear_component", &DQ_ClassicQPController::compute_objective_function_linear_component, "Compute the objective function."); + >(), + py::arg("robot"), + py::arg("solver"), + "Constructs a classic QP controller from shared pointers."); + dq_classicqpcontroller_py.def("compute_objective_function_symmetric_matrix", + &DQ_ClassicQPController::compute_objective_function_symmetric_matrix, + py::arg("J"), + py::arg("task_error"), + "Computes the symmetric matrix H used in the quadratic objective."); + dq_classicqpcontroller_py.def("compute_objective_function_linear_component", + &DQ_ClassicQPController::compute_objective_function_linear_component, + py::arg("J"), + py::arg("task_error"), + "Computes the linear vector f used in the quadratic objective."); } diff --git a/src/robot_control/DQ_KinematicConstrainedController_py.cpp b/src/robot_control/DQ_KinematicConstrainedController_py.cpp index b4e7716..42488ac 100644 --- a/src/robot_control/DQ_KinematicConstrainedController_py.cpp +++ b/src/robot_control/DQ_KinematicConstrainedController_py.cpp @@ -22,13 +22,29 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_KinematicConstrainedController`, an abstract superclass + * used to define concrete kinematic controllers with algebraic constraints, + * to the Python module @p m. + */ void init_DQ_KinematicConstrainedController_py(py::module& m) { /***************************************************** * DQ KinematicConstrainedController * **************************************************/ - py::class_ dqkinematicconstrainedcontroller_py(m,"DQ_KinematicConstrainedController"); - dqkinematicconstrainedcontroller_py.def("set_equality_constraint", &DQ_KinematicConstrainedController::set_equality_constraint, "Sets equality constraints."); - dqkinematicconstrainedcontroller_py.def("set_inequality_constraint", &DQ_KinematicConstrainedController::set_inequality_constraint, "Sets inequality constraints."); + py::class_ dqkinematicconstrainedcontroller_py( + m, + "DQ_KinematicConstrainedController", + "Abstract superclass used to define concrete kinematic controllers with algebraic constraints."); + dqkinematicconstrainedcontroller_py.def("set_equality_constraint", + &DQ_KinematicConstrainedController::set_equality_constraint, + py::arg("B"), + py::arg("b"), + "Sets the equality constraint passed to constrained control laws."); + dqkinematicconstrainedcontroller_py.def("set_inequality_constraint", + &DQ_KinematicConstrainedController::set_inequality_constraint, + py::arg("B"), + py::arg("b"), + "Sets the inequality constraint passed to constrained control laws."); } diff --git a/src/robot_control/DQ_KinematicController_py.cpp b/src/robot_control/DQ_KinematicController_py.cpp index 06a264e..cc9684b 100644 --- a/src/robot_control/DQ_KinematicController_py.cpp +++ b/src/robot_control/DQ_KinematicController_py.cpp @@ -28,29 +28,80 @@ class DQ_KinematicControllerPub : public DQ_KinematicController using DQ_KinematicController::_get_robot; }; +/** + * @brief Binds `DQ_KinematicController`, an abstract class that defines an + * interface to implement kinematic controllers for robots described by + * DQ_Kinematics, to the Python module @p m. + */ void init_DQ_KinematicController_py(py::module& m) { /***************************************************** * DQ KinematicController * **************************************************/ - py::class_ kc_py(m,"DQ_KinematicController"); - kc_py.def("get_control_objective" ,&DQ_KinematicController::get_control_objective,"Gets the control objective"); - kc_py.def("get_jacobian" ,&DQ_KinematicController::get_jacobian,"Gets the Jacobian"); - kc_py.def("get_last_error_signal" ,&DQ_KinematicController::get_last_error_signal, "Gets the last error signal"); - kc_py.def("get_task_variable" ,&DQ_KinematicController::get_task_variable, "Gets the task variable"); - kc_py.def("is_set" ,&DQ_KinematicController::is_set,"Checks if the controller's objective has been set"); - kc_py.def("system_reached_stable_region",&DQ_KinematicController::system_reached_stable_region,"Checks if the controller has stabilized"); - kc_py.def("set_control_objective" ,&DQ_KinematicController::set_control_objective,"Sets the control objective"); - kc_py.def("set_gain" ,&DQ_KinematicController::set_gain,"Sets the controller gain"); - kc_py.def("get_gain" ,&DQ_KinematicController::get_gain,"Gets the controller gain"); - kc_py.def("set_stability_threshold" ,&DQ_KinematicController::set_stability_threshold,"Sets the stability threshold"); - kc_py.def("set_damping" ,&DQ_KinematicController::set_damping, "Sets the damping."); - kc_py.def("get_damping" ,&DQ_KinematicController::get_damping, "Gets the damping."); - kc_py.def("set_primitive_to_effector" ,&DQ_KinematicController::set_primitive_to_effector, "Sets the effector primitive"); - kc_py.def("set_target_primitive" ,&DQ_KinematicController::set_target_primitive, "Sets the target primitive"); - kc_py.def("set_stability_counter_max" ,&DQ_KinematicController::set_stability_counter_max, "Sets the maximum of the stability counter"); - kc_py.def("reset_stability_counter" ,&DQ_KinematicController::reset_stability_counter, "Resets the stability counter"); - kc_py.def("_get_robot",&DQ_KinematicControllerPub::_get_robot , "Gets the robot"); + py::class_ kc_py( + m, + "DQ_KinematicController", + "Abstract class that defines an interface to implement kinematic controllers for robots described by DQ_Kinematics."); + kc_py.def("get_control_objective", + &DQ_KinematicController::get_control_objective, + "Returns the current control objective."); + kc_py.def("get_jacobian", + &DQ_KinematicController::get_jacobian, + py::arg("q"), + "Returns the task Jacobian associated with the current control objective."); + kc_py.def("get_last_error_signal", + &DQ_KinematicController::get_last_error_signal, + "Returns the last task-space error signal computed by the controller."); + kc_py.def("get_task_variable", + &DQ_KinematicController::get_task_variable, + py::arg("q"), + "Returns the current task variable associated with the control objective."); + kc_py.def("is_set", + &DQ_KinematicController::is_set, + "Verifies whether a control objective has been selected."); + kc_py.def("system_reached_stable_region", + &DQ_KinematicController::system_reached_stable_region, + "Indicates whether the closed-loop system has reached a stable region."); + kc_py.def("set_control_objective", + &DQ_KinematicController::set_control_objective, + py::arg("control_objective"), + "Sets the control objective and resizes the internally stored error vector to match the selected task variable."); + kc_py.def("set_gain", + &DQ_KinematicController::set_gain, + py::arg("gain"), + "Sets the controller gain."); + kc_py.def("get_gain", + &DQ_KinematicController::get_gain, + "Returns the controller gain."); + kc_py.def("set_stability_threshold", + &DQ_KinematicController::set_stability_threshold, + py::arg("threshold"), + "Sets the threshold used to detect convergence to a stable region."); + kc_py.def("set_damping", + &DQ_KinematicController::set_damping, + py::arg("damping"), + "Sets the isotropic damping used by singularity-robust controllers."); + kc_py.def("get_damping", + &DQ_KinematicController::get_damping, + "Returns the isotropic damping coefficient."); + kc_py.def("set_primitive_to_effector", + &DQ_KinematicController::set_primitive_to_effector, + py::arg("primitive"), + "Attaches a primitive to the end-effector for primitive-based objectives."); + kc_py.def("set_target_primitive", + &DQ_KinematicController::set_target_primitive, + py::arg("primitive"), + "Sets the target primitive for primitive-based convergence tasks."); + kc_py.def("set_stability_counter_max", + &DQ_KinematicController::set_stability_counter_max, + py::arg("max"), + "Sets the number of consecutive stable iterations required to declare convergence."); + kc_py.def("reset_stability_counter", + &DQ_KinematicController::reset_stability_counter, + "Resets the stability counter and clears the stable-region flag."); + kc_py.def("_get_robot", + &DQ_KinematicControllerPub::_get_robot, + "Returns the stored shared pointer to the associated robot model."); } diff --git a/src/robot_control/DQ_NumericalFilteredPseudoInverseController_py.cpp b/src/robot_control/DQ_NumericalFilteredPseudoInverseController_py.cpp index 420bfb6..3002d1e 100644 --- a/src/robot_control/DQ_NumericalFilteredPseudoInverseController_py.cpp +++ b/src/robot_control/DQ_NumericalFilteredPseudoInverseController_py.cpp @@ -56,6 +56,11 @@ class DQ_NumericalFilteredPseudoinverseControllerPy : public DQ_NumericalFiltere }; +/** + * @brief Binds `DQ_NumericalFilteredPseudoinverseController`, which + * implements a singularity-robust pseudoinverse controller with numerical + * filtered damping, to the Python module @p m. + */ void init_DQ_NumericalFilteredPseudoInverseController_py(py::module& m) { /***************************************************** @@ -65,17 +70,47 @@ void init_DQ_NumericalFilteredPseudoInverseController_py(py::module& m) DQ_NumericalFilteredPseudoinverseController, DQ_NumericalFilteredPseudoinverseControllerPy, DQ_PseudoinverseController - > nfpic(m,"DQ_NumericalFilteredPseudoinverseController"); + > nfpic( + m, + "DQ_NumericalFilteredPseudoinverseController", + "Implements a singularity-robust pseudoinverse controller with numerical filtered damping."); nfpic.def(py::init< const std::shared_ptr& - >()); - nfpic.def("compute_setpoint_control_signal",&DQ_NumericalFilteredPseudoinverseController::compute_setpoint_control_signal,"Computes the setpoint control signal."); - nfpic.def("compute_tracking_control_signal",&DQ_NumericalFilteredPseudoinverseController::compute_tracking_control_signal,"Computes the tracking control signal."); - nfpic.def("set_maximum_numerical_filtered_damping",&DQ_NumericalFilteredPseudoinverseController::set_maximum_numerical_filtered_damping,"Sets the maximum numerical filtered damping."); - nfpic.def("set_singular_region_size",&DQ_NumericalFilteredPseudoinverseController::set_singular_region_size,"Sets the singular region size."); - nfpic.def("get_maximum_numerical_filtered_damping",&DQ_NumericalFilteredPseudoinverseController::get_maximum_numerical_filtered_damping,"Gets the maximum numerical filtered damping."); - nfpic.def("get_singular_region_size",&DQ_NumericalFilteredPseudoinverseController::get_singular_region_size,"Gets the singular region size."); - nfpic.def("get_last_filtered_damping",&DQ_NumericalFilteredPseudoinverseController::get_last_filtered_damping,"Gets the last filtered damping."); - nfpic.def("get_last_jacobian_rank",&DQ_NumericalFilteredPseudoinverseController::get_last_jacobian_rank,"Gets the last Jacobian rank."); - nfpic.def("get_last_jacobian_svd",&DQ_NumericalFilteredPseudoinverseController::get_last_jacobian_svd,"Gets the last Jacobian svd."); + >(), + py::arg("robot"), + "Constructs a controller from a shared robot pointer."); + nfpic.def("compute_setpoint_control_signal", + &DQ_NumericalFilteredPseudoinverseController::compute_setpoint_control_signal, + py::arg("q"), + py::arg("task_reference"), + "Computes the reference joint velocities for a setpoint task using numerical filtered damping."); + nfpic.def("compute_tracking_control_signal", + &DQ_NumericalFilteredPseudoinverseController::compute_tracking_control_signal, + py::arg("q"), + py::arg("task_reference"), + py::arg("feed_forward"), + "Computes the reference joint velocities for a tracking task using numerical filtered damping."); + nfpic.def("set_maximum_numerical_filtered_damping", + &DQ_NumericalFilteredPseudoinverseController::set_maximum_numerical_filtered_damping, + py::arg("numerical_filtered_damping"), + "Sets the maximum numerical filtered damping."); + nfpic.def("set_singular_region_size", + &DQ_NumericalFilteredPseudoinverseController::set_singular_region_size, + py::arg("singular_region_size"), + "Sets the size of the singular region."); + nfpic.def("get_maximum_numerical_filtered_damping", + &DQ_NumericalFilteredPseudoinverseController::get_maximum_numerical_filtered_damping, + "Returns the maximum numerical filtered damping."); + nfpic.def("get_singular_region_size", + &DQ_NumericalFilteredPseudoinverseController::get_singular_region_size, + "Returns the size of the singular region."); + nfpic.def("get_last_filtered_damping", + &DQ_NumericalFilteredPseudoinverseController::get_last_filtered_damping, + "Returns the filtered damping matrix computed in the last control step."); + nfpic.def("get_last_jacobian_rank", + &DQ_NumericalFilteredPseudoinverseController::get_last_jacobian_rank, + "Returns the rank of the last processed Jacobian."); + nfpic.def("get_last_jacobian_svd", + &DQ_NumericalFilteredPseudoinverseController::get_last_jacobian_svd, + "Returns the singular value decomposition of the last processed Jacobian."); } diff --git a/src/robot_control/DQ_PseudoinverseController_py.cpp b/src/robot_control/DQ_PseudoinverseController_py.cpp index 81bfb3b..315d26f 100644 --- a/src/robot_control/DQ_PseudoinverseController_py.cpp +++ b/src/robot_control/DQ_PseudoinverseController_py.cpp @@ -22,15 +22,34 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_PseudoinverseController`, which implements a kinematic + * control law based on the Jacobian pseudoinverse and an Euclidean task-space + * error, to the Python module @p m. + */ void init_DQ_PseudoinverseController_py(py::module& m) { /***************************************************** * DQ TaskSpacePseudoInverseController * **************************************************/ - py::class_ dqpseudoinversecontroller_py(m,"DQ_PseudoinverseController"); + py::class_ dqpseudoinversecontroller_py( + m, + "DQ_PseudoinverseController", + "Implements a kinematic control law based on the Jacobian pseudoinverse and an Euclidean task-space error."); dqpseudoinversecontroller_py.def(py::init< const std::shared_ptr& - >()); - dqpseudoinversecontroller_py.def("compute_setpoint_control_signal",&DQ_PseudoinverseController::compute_setpoint_control_signal,"Computes the setpoint control signal."); - dqpseudoinversecontroller_py.def("compute_tracking_control_signal",&DQ_PseudoinverseController::compute_tracking_control_signal,"Computes the tracking control signal."); + >(), + py::arg("robot"), + "Constructs a controller from a shared robot pointer."); + dqpseudoinversecontroller_py.def("compute_setpoint_control_signal", + &DQ_PseudoinverseController::compute_setpoint_control_signal, + py::arg("q"), + py::arg("task_reference"), + "Computes the reference joint velocities that drive the task-space error to zero."); + dqpseudoinversecontroller_py.def("compute_tracking_control_signal", + &DQ_PseudoinverseController::compute_tracking_control_signal, + py::arg("q"), + py::arg("task_reference"), + py::arg("feed_forward"), + "Computes the reference joint velocities for a time-varying task-space reference."); } diff --git a/src/robot_control/DQ_QuadraticProgrammingController_py.cpp b/src/robot_control/DQ_QuadraticProgrammingController_py.cpp index 7a077ab..009ab26 100644 --- a/src/robot_control/DQ_QuadraticProgrammingController_py.cpp +++ b/src/robot_control/DQ_QuadraticProgrammingController_py.cpp @@ -62,18 +62,46 @@ class DQ_QuadraticProgrammingControllerPy : public DQ_QuadraticProgrammingContro }; +/** + * @brief Binds `DQ_QuadraticProgrammingController`, an abstract class that + * defines task-space kinematic controllers based on quadratic programming, to + * the Python module @p m. + */ void init_DQ_QuadraticProgrammingController_py(py::module& m) { /***************************************************** * DQ TaskspaceQuadraticProgrammingController * **************************************************/ - py::class_ qpcpy(m,"DQ_QuadraticProgrammingController"); + py::class_ qpcpy( + m, + "DQ_QuadraticProgrammingController", + "Abstract class that defines task-space kinematic controllers based on quadratic programming."); qpcpy.def(py::init< const std::shared_ptr&, const std::shared_ptr& - >()); - qpcpy.def("compute_objective_function_symmetric_matrix", &DQ_QuadraticProgrammingController::compute_objective_function_symmetric_matrix, "Compute symmetric matrix."); - qpcpy.def("compute_objective_function_linear_component", &DQ_QuadraticProgrammingController::compute_objective_function_linear_component, "Compute the objective function."); - qpcpy.def("compute_setpoint_control_signal", &DQ_QuadraticProgrammingController::compute_setpoint_control_signal, "Compute the setpoint control signal."); - qpcpy.def("compute_tracking_control_signal", &DQ_QuadraticProgrammingController::compute_tracking_control_signal, "Compute the tracking control signal."); + >(), + py::arg("robot"), + py::arg("solver"), + "Constructs a controller from shared pointers."); + qpcpy.def("compute_objective_function_symmetric_matrix", + &DQ_QuadraticProgrammingController::compute_objective_function_symmetric_matrix, + py::arg("J"), + py::arg("task_error"), + "Computes the symmetric matrix H of the quadratic objective."); + qpcpy.def("compute_objective_function_linear_component", + &DQ_QuadraticProgrammingController::compute_objective_function_linear_component, + py::arg("J"), + py::arg("task_error"), + "Computes the linear vector f of the quadratic objective."); + qpcpy.def("compute_setpoint_control_signal", + &DQ_QuadraticProgrammingController::compute_setpoint_control_signal, + py::arg("q"), + py::arg("task_reference"), + "Computes the reference joint velocities for a setpoint task."); + qpcpy.def("compute_tracking_control_signal", + &DQ_QuadraticProgrammingController::compute_tracking_control_signal, + py::arg("q"), + py::arg("task_reference"), + py::arg("feed_forward"), + "Computes the reference joint velocities for a tracking task with feedforward."); } diff --git a/src/robot_modeling/DQ_CooperativeDualTaskSpace_py.cpp b/src/robot_modeling/DQ_CooperativeDualTaskSpace_py.cpp index 738154e..a8397e0 100644 --- a/src/robot_modeling/DQ_CooperativeDualTaskSpace_py.cpp +++ b/src/robot_modeling/DQ_CooperativeDualTaskSpace_py.cpp @@ -22,21 +22,61 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_CooperativeDualTaskSpace`, which implements the cooperative + * dual task-space formulation for two robots, to the Python module @p m. + */ void init_DQ_CooperativeDualTaskSpace_py(py::module& m) { - /***************************************************** - * DQ CooperativeDualTaskSpace - * **************************************************/ py::class_< DQ_CooperativeDualTaskSpace - > dqcooperativedualtaskspace(m, "DQ_CooperativeDualTaskSpace"); - dqcooperativedualtaskspace.def(py::init()); - dqcooperativedualtaskspace.def("pose1", &DQ_CooperativeDualTaskSpace::pose1, "Returns the first robot's pose"); - dqcooperativedualtaskspace.def("pose2", &DQ_CooperativeDualTaskSpace::pose2,"Returns the second robot's pose"); - dqcooperativedualtaskspace.def("absolute_pose", &DQ_CooperativeDualTaskSpace::absolute_pose,"Returns the absolute pose"); - dqcooperativedualtaskspace.def("relative_pose", &DQ_CooperativeDualTaskSpace::relative_pose,"Returns the relative pose"); - dqcooperativedualtaskspace.def("pose_jacobian1", &DQ_CooperativeDualTaskSpace::pose_jacobian1,"Returns the pose Jacobian of the first robot"); - dqcooperativedualtaskspace.def("pose_jacobian2", &DQ_CooperativeDualTaskSpace::pose_jacobian2,"Returns the pose Jacobian of the second robot"); - dqcooperativedualtaskspace.def("absolute_pose_jacobian", &DQ_CooperativeDualTaskSpace::absolute_pose_jacobian,"Returns the absolute pose Jacobian"); - dqcooperativedualtaskspace.def("relative_pose_jacobian", &DQ_CooperativeDualTaskSpace::relative_pose_jacobian,"Returns the relative pose Jacobian"); + > dqcooperativedualtaskspace( + m, + "DQ_CooperativeDualTaskSpace", + "Implements the cooperative dual task-space formulation for two robots. The cooperative variables are the absolute pose and the relative pose of the two end effectors, together with their corresponding Jacobians."); + dqcooperativedualtaskspace.def( + py::init(), + py::arg("robot1"), + py::arg("robot2"), + "Constructs a cooperative dual task-space system from two robot models. The object does not take ownership of the provided pointers."); + dqcooperativedualtaskspace.def( + "pose1", + &DQ_CooperativeDualTaskSpace::pose1, + py::arg("theta"), + "Returns the pose of the first end effector for the combined configuration vector theta = [q1; q2]."); + dqcooperativedualtaskspace.def( + "pose2", + &DQ_CooperativeDualTaskSpace::pose2, + py::arg("theta"), + "Returns the pose of the second end effector for the combined configuration vector theta = [q1; q2]."); + dqcooperativedualtaskspace.def( + "absolute_pose", + &DQ_CooperativeDualTaskSpace::absolute_pose, + py::arg("theta"), + "Computes the absolute pose of the cooperative system as the frame located midway between the two end effectors."); + dqcooperativedualtaskspace.def( + "relative_pose", + &DQ_CooperativeDualTaskSpace::relative_pose, + py::arg("theta"), + "Computes the relative pose between the two end effectors. The returned dual quaternion maps the second end-effector frame to the first one."); + dqcooperativedualtaskspace.def( + "pose_jacobian1", + &DQ_CooperativeDualTaskSpace::pose_jacobian1, + py::arg("theta"), + "Returns the pose Jacobian of the first robot end effector for the combined configuration vector theta = [q1; q2]."); + dqcooperativedualtaskspace.def( + "pose_jacobian2", + &DQ_CooperativeDualTaskSpace::pose_jacobian2, + py::arg("theta"), + "Returns the pose Jacobian of the second robot end effector for the combined configuration vector theta = [q1; q2]."); + dqcooperativedualtaskspace.def( + "absolute_pose_jacobian", + &DQ_CooperativeDualTaskSpace::absolute_pose_jacobian, + py::arg("theta"), + "Computes the Jacobian of the absolute pose."); + dqcooperativedualtaskspace.def( + "relative_pose_jacobian", + &DQ_CooperativeDualTaskSpace::relative_pose_jacobian, + py::arg("theta"), + "Computes the Jacobian of the relative pose."); } diff --git a/src/robot_modeling/DQ_DifferentialDriveRobot_py.cpp b/src/robot_modeling/DQ_DifferentialDriveRobot_py.cpp index 0647028..214ba69 100644 --- a/src/robot_modeling/DQ_DifferentialDriveRobot_py.cpp +++ b/src/robot_modeling/DQ_DifferentialDriveRobot_py.cpp @@ -22,22 +22,53 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_DifferentialDriveRobot`, the basic differential-drive + * mobile-robot implementation whose pose Jacobians account for the + * nonholonomic rolling constraint, to the Python module @p m. + */ void init_DQ_DifferentialDriveRobot_py(py::module& m) { - /***************************************************** - * DQ DifferentialDriveRobot - * **************************************************/ py::class_< DQ_DifferentialDriveRobot, std::shared_ptr, DQ_HolonomicBase - > dqdifferentialdriverobot_py(m,"DQ_DifferentialDriveRobot"); - dqdifferentialdriverobot_py.def(py::init()); - dqdifferentialdriverobot_py.def("constraint_jacobian", &DQ_DifferentialDriveRobot::constraint_jacobian, "Returns the constraint Jacobian"); - dqdifferentialdriverobot_py.def("pose_jacobian", (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&, const int&) const)&DQ_DifferentialDriveRobot::pose_jacobian,"Returns the pose Jacobian"); - dqdifferentialdriverobot_py.def("pose_jacobian", (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&) const)&DQ_DifferentialDriveRobot::pose_jacobian,"Returns the pose Jacobian"); - dqdifferentialdriverobot_py.def("pose_jacobian_derivative", (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_DifferentialDriveRobot::pose_jacobian_derivative, - "Returns the pose Jacobian derivative"); - dqdifferentialdriverobot_py.def("pose_jacobian_derivative", (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&, const VectorXd&) const)&DQ_DifferentialDriveRobot::pose_jacobian_derivative, - "Returns the pose Jacobian derivative"); + > dqdifferentialdriverobot_py( + m, + "DQ_DifferentialDriveRobot", + "Basic implementation of a differential-drive mobile robot. The robot pose is modeled as a holonomic base with configuration q = [x, y, phi]^T, while the actuation is described by the angular velocities of the right and left wheels."); + dqdifferentialdriverobot_py.def( + py::init(), + py::arg("wheel_radius"), + py::arg("distance_between_wheels"), + "Constructs a differential-drive robot from the wheel radius and the distance between the wheels."); + dqdifferentialdriverobot_py.def( + "constraint_jacobian", + &DQ_DifferentialDriveRobot::constraint_jacobian, + py::arg("phi"), + "Computes the constraint Jacobian relating the right- and left-wheel angular velocities to [x_dot, y_dot, phi_dot]^T."); + dqdifferentialdriverobot_py.def( + "pose_jacobian", + (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&, const int&) const)&DQ_DifferentialDriveRobot::pose_jacobian, + py::arg("q"), + py::arg("to_link"), + "Computes the constrained pose Jacobian up to the requested column."); + dqdifferentialdriverobot_py.def( + "pose_jacobian", + (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&) const)&DQ_DifferentialDriveRobot::pose_jacobian, + py::arg("q"), + "Computes the full constrained pose Jacobian."); + dqdifferentialdriverobot_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_DifferentialDriveRobot::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_link"), + "Computes the time derivative of the constrained pose Jacobian up to the requested column."); + dqdifferentialdriverobot_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_DifferentialDriveRobot::*)(const VectorXd&, const VectorXd&) const)&DQ_DifferentialDriveRobot::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + "Computes the full time derivative of the constrained pose Jacobian."); } diff --git a/src/robot_modeling/DQ_HolonomicBase_py.cpp b/src/robot_modeling/DQ_HolonomicBase_py.cpp index 3aa6eef..ea79d67 100644 --- a/src/robot_modeling/DQ_HolonomicBase_py.cpp +++ b/src/robot_modeling/DQ_HolonomicBase_py.cpp @@ -22,27 +22,79 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_HolonomicBase`, the basic holonomic mobile-base + * implementation with planar configuration q = [x, y, phi]^T, to the Python + * module @p m. + */ void init_DQ_HolonomicBase_py(py::module& m) { - /***************************************************** - * DQ HolonomicBase - * **************************************************/ py::class_< DQ_HolonomicBase, std::shared_ptr, DQ_MobileBase - > dqholonomicbase_py(m,"DQ_HolonomicBase"); - dqholonomicbase_py.def(py::init()); - dqholonomicbase_py.def("fkm",(DQ (DQ_HolonomicBase::*)(const VectorXd&) const)&DQ_HolonomicBase::fkm,"Gets the fkm."); - dqholonomicbase_py.def("fkm",(DQ (DQ_HolonomicBase::*)(const VectorXd&,const int&) const)&DQ_HolonomicBase::fkm,"Gets the fkm."); - dqholonomicbase_py.def("pose_jacobian", (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&, const int&) const)&DQ_HolonomicBase::pose_jacobian,"Returns the pose Jacobian"); - dqholonomicbase_py.def("pose_jacobian", (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&) const)&DQ_HolonomicBase::pose_jacobian,"Returns the pose Jacobian"); - dqholonomicbase_py.def("pose_jacobian_derivative", (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&, const VectorXd&) const)&DQ_HolonomicBase::pose_jacobian_derivative, - "Returns the pose Jacobian derivative"); - dqholonomicbase_py.def("pose_jacobian_derivative", (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_HolonomicBase::pose_jacobian_derivative, - "Returns the pose Jacobian derivative"); - dqholonomicbase_py.def("get_dim_configuration_space",&DQ_HolonomicBase::get_dim_configuration_space,"Returns the size of the configuration space"); - dqholonomicbase_py.def("raw_fkm", &DQ_HolonomicBase::raw_fkm,"Returns the raw fkm"); - dqholonomicbase_py.def("raw_pose_jacobian", &DQ_HolonomicBase::raw_pose_jacobian,"Return the raw pose Jacobian"); - dqholonomicbase_py.def("raw_pose_jacobian_derivative", &DQ_HolonomicBase::raw_pose_jacobian_derivative,"Return the raw pose Jacobian derivative"); + > dqholonomicbase_py( + m, + "DQ_HolonomicBase", + "Basic implementation of a holonomic mobile base. The configuration vector is q = [x, y, phi]^T, where x and y describe the planar position and phi is the planar orientation."); + dqholonomicbase_py.def( + py::init(), + "Constructs a holonomic base with configuration-space dimension three."); + dqholonomicbase_py.def( + "fkm", + (DQ (DQ_HolonomicBase::*)(const VectorXd&) const)&DQ_HolonomicBase::fkm, + py::arg("q"), + "Computes the mobile-base pose while considering the frame displacement."); + dqholonomicbase_py.def( + "fkm", + (DQ (DQ_HolonomicBase::*)(const VectorXd&,const int&) const)&DQ_HolonomicBase::fkm, + py::arg("q"), + py::arg("to_ith_link"), + "Computes the mobile-base pose while considering the frame displacement. This compatibility overload accepts only to_ith_link = 2."); + dqholonomicbase_py.def( + "pose_jacobian", + (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&, const int&) const)&DQ_HolonomicBase::pose_jacobian, + py::arg("q"), + py::arg("to_link"), + "Computes the pose Jacobian while considering the frame displacement up to the requested column."); + dqholonomicbase_py.def( + "pose_jacobian", + (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&) const)&DQ_HolonomicBase::pose_jacobian, + py::arg("q"), + "Computes the full pose Jacobian while considering the frame displacement."); + dqholonomicbase_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&, const VectorXd&) const)&DQ_HolonomicBase::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + "Computes the full time derivative of the pose Jacobian."); + dqholonomicbase_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_HolonomicBase::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_HolonomicBase::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_link"), + "Computes the time derivative of the pose Jacobian while considering the frame displacement up to the requested column."); + dqholonomicbase_py.def( + "get_dim_configuration_space", + &DQ_HolonomicBase::get_dim_configuration_space, + "Returns the dimension of the configuration space. For a holonomic base, q = [x, y, phi]^T."); + dqholonomicbase_py.def( + "raw_fkm", + &DQ_HolonomicBase::raw_fkm, + py::arg("q"), + "Computes the planar mobile-base pose without considering the frame displacement."); + dqholonomicbase_py.def( + "raw_pose_jacobian", + &DQ_HolonomicBase::raw_pose_jacobian, + py::arg("q"), + py::arg("to_link") = 2, + "Computes the raw pose Jacobian of the planar mobile base up to the requested column."); + dqholonomicbase_py.def( + "raw_pose_jacobian_derivative", + &DQ_HolonomicBase::raw_pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_link") = 2, + "Computes the raw time derivative of the pose Jacobian of the planar mobile base up to the requested column."); } diff --git a/src/robot_modeling/DQ_Kinematics_py.cpp b/src/robot_modeling/DQ_Kinematics_py.cpp index 99741ee..50a4d7f 100644 --- a/src/robot_modeling/DQ_Kinematics_py.cpp +++ b/src/robot_modeling/DQ_Kinematics_py.cpp @@ -22,49 +22,222 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_Kinematics`, the common base class for robot models in DQ + * Robotics that stores reference/base frames and exposes task-space Jacobian + * utilities, to the Python module @p m. + */ void init_DQ_Kinematics_py(py::module& m) { - /***************************************************** - * DQ Kinematics - * **************************************************/ py::class_< DQ_Kinematics, std::shared_ptr - > dqkinematics_py(m, "DQ_Kinematics"); - //dqkinematics_py.def(py::init<>()); - //dqkinematics_py.def("pose_jacobian", (MatrixXd (DQ_Kinematics::*)(const VectorXd&) const)&DQ_Kinematics::pose_jacobian, "Returns the pose Jacobian"); + > dqkinematics_py( + m, + "DQ_Kinematics", + "Abstract class that defines an interface to implement robot kinematics. " + "It stores the reference and base frames, the dimension of the configuration space, " + "and static operations that derive task-space Jacobians from a pose Jacobian represented in dual quaternion form."); - //Concrete - dqkinematics_py.def("get_dim_configuration_space", &DQ_Kinematics::get_dim_configuration_space, "Returns the dimension of the configuration space"); - dqkinematics_py.def("get_reference_frame", &DQ_Kinematics::get_reference_frame, "Returns the current reference frame"); - dqkinematics_py.def("set_reference_frame", &DQ_Kinematics::set_reference_frame, "Sets the reference frame"); - dqkinematics_py.def("get_base_frame", &DQ_Kinematics::get_base_frame, "Returns the current base frame"); - dqkinematics_py.def("set_base_frame", &DQ_Kinematics::set_base_frame, "Sets the base frame"); + dqkinematics_py.def( + "get_dim_configuration_space", + &DQ_Kinematics::get_dim_configuration_space, + "Returns the dimension of the configuration space as the number of generalized coordinates of the model."); + dqkinematics_py.def( + "get_reference_frame", + &DQ_Kinematics::get_reference_frame, + "Returns the current reference frame as a unit dual quaternion."); + dqkinematics_py.def( + "set_reference_frame", + &DQ_Kinematics::set_reference_frame, + py::arg("get_reference_frame"), + "Sets the reference frame used by the forward kinematics and Jacobian methods."); + dqkinematics_py.def( + "get_base_frame", + &DQ_Kinematics::get_base_frame, + "Returns the current base frame as a unit dual quaternion."); + dqkinematics_py.def( + "set_base_frame", + &DQ_Kinematics::set_base_frame, + py::arg("get_base_frame"), + "Sets the physical base frame of the robot in the workspace."); - //Static - dqkinematics_py.def_static("distance_jacobian", &DQ_Kinematics::distance_jacobian, "Returns the distance Jacobian"); - dqkinematics_py.def_static("translation_jacobian", &DQ_Kinematics::translation_jacobian, "Returns the translation Jacobian"); - dqkinematics_py.def_static("rotation_jacobian", &DQ_Kinematics::rotation_jacobian, "Returns the rotation Jacobian"); - dqkinematics_py.def_static("line_jacobian", &DQ_Kinematics::line_jacobian, "Returns the line Jacobian"); - dqkinematics_py.def_static("plane_jacobian", &DQ_Kinematics::plane_jacobian, "Returns the plane Jacobian"); - dqkinematics_py.def_static("distance_jacobian_derivative", &DQ_Kinematics::distance_jacobian_derivative, "Returns the distance Jacobian derivative"); - dqkinematics_py.def_static("translation_jacobian_derivative", &DQ_Kinematics::translation_jacobian_derivative, "Returns the translation Jacobian derivative"); - dqkinematics_py.def_static("rotation_jacobian_derivative", &DQ_Kinematics::rotation_jacobian_derivative, "Returns the rotation Jacobian derivative"); - dqkinematics_py.def_static("line_jacobian_derivative", &DQ_Kinematics::line_jacobian_derivative, "Returns the line Jacobian derivative"); - dqkinematics_py.def_static("plane_jacobian_derivative", &DQ_Kinematics::plane_jacobian_derivative, "Returns the plane Jacobian derivative"); - dqkinematics_py.def_static("point_to_point_distance_jacobian", &DQ_Kinematics::point_to_point_distance_jacobian,"Returns the robot point to point distance Jacobian"); - dqkinematics_py.def_static("point_to_point_residual", &DQ_Kinematics::point_to_point_residual,"Returns the robot point to point residual"); - dqkinematics_py.def_static("point_to_line_distance_jacobian", &DQ_Kinematics::point_to_line_distance_jacobian,"Returns the robot point to line distance Jacobian"); - dqkinematics_py.def_static("point_to_line_residual", &DQ_Kinematics::point_to_line_residual,"Returns the robot point to line residual"); - dqkinematics_py.def_static("point_to_plane_distance_jacobian", &DQ_Kinematics::point_to_plane_distance_jacobian,"Returns the robot point to plane distance Jacobian"); - dqkinematics_py.def_static("point_to_plane_residual", &DQ_Kinematics::point_to_plane_residual,"Returns the robot point to plane residual"); - dqkinematics_py.def_static("line_to_point_distance_jacobian", &DQ_Kinematics::line_to_point_distance_jacobian,"Returns the robot line to point distance Jacobian"); - dqkinematics_py.def_static("line_to_point_residual", &DQ_Kinematics::line_to_point_residual,"Returns the robot line to point residual"); - dqkinematics_py.def_static("line_to_line_distance_jacobian", &DQ_Kinematics::line_to_line_distance_jacobian,"Returns the robot line to line distance Jacobian"); - dqkinematics_py.def_static("line_to_line_residual", &DQ_Kinematics::line_to_line_residual, "Returns the robot line to line residual"); - dqkinematics_py.def_static("plane_to_point_distance_jacobian", &DQ_Kinematics::plane_to_point_distance_jacobian,"Returns the robot plane to point distance Jacobian"); - dqkinematics_py.def_static("plane_to_point_residual", &DQ_Kinematics::plane_to_point_residual,"Returns the robot plane to point residual"); - dqkinematics_py.def_static("line_to_line_angle_jacobian", &DQ_Kinematics::line_to_line_angle_jacobian,"Returns the line to line angle Jacobian"); - dqkinematics_py.def_static("line_to_line_angle_residual", &DQ_Kinematics::line_to_line_angle_residual,"Returns the line to line angle residual"); - dqkinematics_py.def_static("line_segment_to_line_segment_distance_jacobian", &DQ_Kinematics::line_segment_to_line_segment_distance_jacobian, "Returns the line segment to line segment distance Jacobian"); + dqkinematics_py.def_static( + "distance_jacobian", + &DQ_Kinematics::distance_jacobian, + py::arg("pose_jacobian"), + py::arg("pose"), + "Computes the Jacobian of the squared distance from the pose origin to the reference-frame origin from a pose Jacobian."); + dqkinematics_py.def_static( + "translation_jacobian", + &DQ_Kinematics::translation_jacobian, + py::arg("pose_jacobian"), + py::arg("pose"), + "Computes the translation Jacobian from a pose Jacobian so that vec4(translation_dot) = J * q_dot."); + dqkinematics_py.def_static( + "rotation_jacobian", + &DQ_Kinematics::rotation_jacobian, + py::arg("pose_jacobian"), + "Extracts the rotation Jacobian from a pose Jacobian so that vec4(rotation_dot) = J * q_dot."); + dqkinematics_py.def_static( + "line_jacobian", + &DQ_Kinematics::line_jacobian, + py::arg("pose_jacobian"), + py::arg("pose"), + py::arg("line_direction"), + "Computes the Jacobian of a line obtained by rigidly attaching the local line direction to the given pose."); + dqkinematics_py.def_static( + "plane_jacobian", + &DQ_Kinematics::plane_jacobian, + py::arg("pose_jacobian"), + py::arg("pose"), + py::arg("plane_normal"), + "Computes the Jacobian of a plane obtained by rigidly attaching the local plane normal to the given pose."); + dqkinematics_py.def_static( + "distance_jacobian_derivative", + &DQ_Kinematics::distance_jacobian_derivative, + py::arg("pose_jacobian"), + py::arg("pose_jacobian_derivative"), + py::arg("pose"), + py::arg("q_dot"), + "Computes the time derivative of the squared-distance Jacobian."); + dqkinematics_py.def_static( + "translation_jacobian_derivative", + &DQ_Kinematics::translation_jacobian_derivative, + py::arg("pose_jacobian"), + py::arg("pose_jacobian_derivative"), + py::arg("pose"), + py::arg("q_dot"), + "Computes the time derivative of the translation Jacobian."); + dqkinematics_py.def_static( + "rotation_jacobian_derivative", + &DQ_Kinematics::rotation_jacobian_derivative, + py::arg("pose_jacobian_derivative"), + "Extracts the rotation-Jacobian derivative from a pose-Jacobian derivative."); + dqkinematics_py.def_static( + "line_jacobian_derivative", + &DQ_Kinematics::line_jacobian_derivative, + py::arg("pose_jacobian"), + py::arg("pose_jacobian_derivative"), + py::arg("pose"), + py::arg("line_direction"), + py::arg("q_dot"), + "Computes the time derivative of a line Jacobian."); + dqkinematics_py.def_static( + "plane_jacobian_derivative", + &DQ_Kinematics::plane_jacobian_derivative, + py::arg("pose_jacobian"), + py::arg("pose_jacobian_derivative"), + py::arg("pose"), + py::arg("plane_normal"), + py::arg("q_dot"), + "Computes the time derivative of a plane Jacobian."); + dqkinematics_py.def_static( + "point_to_point_distance_jacobian", + &DQ_Kinematics::point_to_point_distance_jacobian, + py::arg("translation_jacobian"), + py::arg("robot_point"), + py::arg("workspace_point"), + "Computes the squared point-to-point distance Jacobian."); + dqkinematics_py.def_static( + "point_to_point_residual", + &DQ_Kinematics::point_to_point_residual, + py::arg("robot_point"), + py::arg("workspace_point"), + py::arg("workspace_point_derivative"), + "Computes the residual term of the squared point-to-point distance dynamics."); + dqkinematics_py.def_static( + "point_to_line_distance_jacobian", + &DQ_Kinematics::point_to_line_distance_jacobian, + py::arg("translation_jacobian"), + py::arg("robot_point"), + py::arg("workspace_line"), + "Computes the squared point-to-line distance Jacobian."); + dqkinematics_py.def_static( + "point_to_line_residual", + &DQ_Kinematics::point_to_line_residual, + py::arg("robot_point"), + py::arg("workspace_line"), + py::arg("workspace_line_derivative"), + "Computes the residual term of the squared point-to-line distance dynamics."); + dqkinematics_py.def_static( + "point_to_plane_distance_jacobian", + &DQ_Kinematics::point_to_plane_distance_jacobian, + py::arg("translation_jacobian"), + py::arg("robot_point"), + py::arg("workspace_plane"), + "Computes the squared point-to-plane distance Jacobian."); + dqkinematics_py.def_static( + "point_to_plane_residual", + &DQ_Kinematics::point_to_plane_residual, + py::arg("translation"), + py::arg("plane_derivative"), + "Computes the residual term of the squared point-to-plane distance dynamics."); + dqkinematics_py.def_static( + "line_to_point_distance_jacobian", + &DQ_Kinematics::line_to_point_distance_jacobian, + py::arg("line_jacobian"), + py::arg("robot_line"), + py::arg("workspace_point"), + "Computes the squared line-to-point distance Jacobian."); + dqkinematics_py.def_static( + "line_to_point_residual", + &DQ_Kinematics::line_to_point_residual, + py::arg("robot_line"), + py::arg("workspace_point"), + py::arg("workspace_point_derivative"), + "Computes the residual term of the squared line-to-point distance dynamics."); + dqkinematics_py.def_static( + "line_to_line_distance_jacobian", + &DQ_Kinematics::line_to_line_distance_jacobian, + py::arg("line_jacobian"), + py::arg("robot_line"), + py::arg("workspace_line"), + "Computes the squared line-to-line distance Jacobian."); + dqkinematics_py.def_static( + "line_to_line_residual", + &DQ_Kinematics::line_to_line_residual, + py::arg("robot_line"), + py::arg("workspace_line"), + py::arg("workspace_line_derivative"), + "Computes the residual term of the squared line-to-line distance dynamics."); + dqkinematics_py.def_static( + "plane_to_point_distance_jacobian", + &DQ_Kinematics::plane_to_point_distance_jacobian, + py::arg("plane_jacobian"), + py::arg("workspace_point"), + "Computes the squared plane-to-point distance Jacobian."); + dqkinematics_py.def_static( + "plane_to_point_residual", + &DQ_Kinematics::plane_to_point_residual, + py::arg("robot_plane"), + py::arg("workspace_point_derivative"), + "Computes the residual term of the squared plane-to-point distance dynamics."); + dqkinematics_py.def_static( + "line_to_line_angle_jacobian", + &DQ_Kinematics::line_to_line_angle_jacobian, + py::arg("line_jacobian"), + py::arg("robot_line"), + py::arg("workspace_line"), + "Computes the Jacobian of the line-to-line angle objective."); + dqkinematics_py.def_static( + "line_to_line_angle_residual", + &DQ_Kinematics::line_to_line_angle_residual, + py::arg("robot_line"), + py::arg("workspace_line"), + py::arg("workspace_line_derivative"), + "Computes the residual term of the line-to-line angle objective."); + dqkinematics_py.def_static( + "line_segment_to_line_segment_distance_jacobian", + &DQ_Kinematics::line_segment_to_line_segment_distance_jacobian, + py::arg("line_jacobian"), + py::arg("robot_point_1_translation_jacobian"), + py::arg("robot_point_2_translation_jacobian"), + py::arg("robot_line"), + py::arg("robot_point_1"), + py::arg("robot_point_2"), + py::arg("workspace_line"), + py::arg("workspace_point_1"), + py::arg("workspace_point_2"), + "Computes a squared-distance Jacobian between two line segments by selecting the appropriate active-constraint formulation."); } diff --git a/src/robot_modeling/DQ_MobileBase_py.cpp b/src/robot_modeling/DQ_MobileBase_py.cpp index d34d676..876c92f 100644 --- a/src/robot_modeling/DQ_MobileBase_py.cpp +++ b/src/robot_modeling/DQ_MobileBase_py.cpp @@ -22,15 +22,27 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_MobileBase`, the abstract mobile-base interface that + * specializes `DQ_Kinematics` for mobile robots with an additional rigid frame + * displacement, to the Python module @p m. + */ void init_DQ_MobileBase_py(py::module& m) { - /***************************************************** - * DQ MobileBase - * **************************************************/ py::class_< DQ_MobileBase, std::shared_ptr, - DQ_Kinematics> dqmobilebase_py(m,"DQ_MobileBase"); - dqmobilebase_py.def("set_frame_displacement", &DQ_MobileBase::set_frame_displacement,"Set the frame displacement"); - dqmobilebase_py.def("frame_displacement", &DQ_MobileBase::frame_displacement, "Get the frame displacement"); + DQ_Kinematics> dqmobilebase_py( + m, + "DQ_MobileBase", + "Abstract class that defines an interface for mobile bases. It specializes DQ_Kinematics for mobile robots whose pose is described by a low-dimensional configuration vector and an additional rigid displacement from the raw mobile-base pose to the actual base frame."); + dqmobilebase_py.def( + "set_frame_displacement", + &DQ_MobileBase::set_frame_displacement, + py::arg("pose"), + "Sets the rigid displacement from the raw mobile-base pose to the base frame."); + dqmobilebase_py.def( + "frame_displacement", + &DQ_MobileBase::frame_displacement, + "Returns the rigid displacement from the raw mobile-base pose to the base frame."); } diff --git a/src/robot_modeling/DQ_SerialManipulatorDH_py.cpp b/src/robot_modeling/DQ_SerialManipulatorDH_py.cpp index b251936..da375f0 100644 --- a/src/robot_modeling/DQ_SerialManipulatorDH_py.cpp +++ b/src/robot_modeling/DQ_SerialManipulatorDH_py.cpp @@ -22,29 +22,63 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_SerialManipulatorDH`, the concrete serial manipulator based + * on the standard Denavit-Hartenberg convention, to the Python module @p m. + */ void init_DQ_SerialManipulatorDH_py(py::module& m) { - /*************************************************** - * DQ SerialManipulatorDH - * **************************************************/ py::class_< DQ_SerialManipulatorDH, std::shared_ptr, DQ_SerialManipulator - > dqserialmanipulatordh_py(m, "DQ_SerialManipulatorDH"); - dqserialmanipulatordh_py.def(py::init()); - - ///Methods - //Concrete - dqserialmanipulatordh_py.def("get_thetas", &DQ_SerialManipulatorDH::get_thetas, "Retrieves the vector of thetas."); - dqserialmanipulatordh_py.def("get_ds", &DQ_SerialManipulatorDH::get_ds, "Retrieves the vector of ds."); - dqserialmanipulatordh_py.def("get_as", &DQ_SerialManipulatorDH::get_as, "Retrieves the vector of as."); - dqserialmanipulatordh_py.def("get_alphas", &DQ_SerialManipulatorDH::get_alphas, "Retrieves the vector of alphas."); - dqserialmanipulatordh_py.def("get_types", &DQ_SerialManipulatorDH::get_types, "Retrieves the vector of types."); - - //Overrides from DQ_SerialManipulator - dqserialmanipulatordh_py.def("raw_pose_jacobian", (MatrixXd (DQ_SerialManipulatorDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDH::raw_pose_jacobian, "Retrieves the raw pose Jacobian."); - dqserialmanipulatordh_py.def("raw_fkm", (DQ (DQ_SerialManipulatorDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDH::raw_fkm, "Retrieves the raw FKM."); - dqserialmanipulatordh_py.def("raw_pose_jacobian_derivative",(MatrixXd (DQ_SerialManipulatorDH::*)(const VectorXd&, const VectorXd&, const int&) const) - &DQ_SerialManipulatorDH::raw_pose_jacobian_derivative, "Retrieves the raw pose Jacobian derivative."); + > dqserialmanipulatordh_py( + m, + "DQ_SerialManipulatorDH", + "Concrete serial manipulator based on the standard Denavit-Hartenberg convention. The constructor expects a 5 x n matrix whose rows store theta, d, a, alpha, and the joint type of each link."); + dqserialmanipulatordh_py.def( + py::init(), + py::arg("dh_matrix"), + "Constructs a serial manipulator from a standard DH matrix."); + + dqserialmanipulatordh_py.def( + "get_thetas", + &DQ_SerialManipulatorDH::get_thetas, + "Returns the theta row of the stored DH matrix."); + dqserialmanipulatordh_py.def( + "get_ds", + &DQ_SerialManipulatorDH::get_ds, + "Returns the d row of the stored DH matrix."); + dqserialmanipulatordh_py.def( + "get_as", + &DQ_SerialManipulatorDH::get_as, + "Returns the a row of the stored DH matrix."); + dqserialmanipulatordh_py.def( + "get_alphas", + &DQ_SerialManipulatorDH::get_alphas, + "Returns the alpha row of the stored DH matrix."); + dqserialmanipulatordh_py.def( + "get_types", + &DQ_SerialManipulatorDH::get_types, + "Returns the joint-type row of the stored DH matrix as encoded joint types."); + + dqserialmanipulatordh_py.def( + "raw_pose_jacobian", + (MatrixXd (DQ_SerialManipulatorDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDH::raw_pose_jacobian, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the raw pose Jacobian under the standard DH convention up to the requested link."); + dqserialmanipulatordh_py.def( + "raw_fkm", + (DQ (DQ_SerialManipulatorDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDH::raw_fkm, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the raw forward kinematics under the standard DH convention up to the requested link."); + dqserialmanipulatordh_py.def( + "raw_pose_jacobian_derivative", + (MatrixXd (DQ_SerialManipulatorDH::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_SerialManipulatorDH::raw_pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_ith_link"), + "Computes the time derivative of the raw pose Jacobian under the standard DH convention up to the requested link."); } diff --git a/src/robot_modeling/DQ_SerialManipulatorDenso_py.cpp b/src/robot_modeling/DQ_SerialManipulatorDenso_py.cpp index c9944d3..0aaf873 100644 --- a/src/robot_modeling/DQ_SerialManipulatorDenso_py.cpp +++ b/src/robot_modeling/DQ_SerialManipulatorDenso_py.cpp @@ -22,30 +22,66 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_SerialManipulatorDenso`, the concrete serial manipulator + * that uses the DENSO kinematic convention, to the Python module @p m. + */ void init_DQ_SerialManipulatorDenso_py(py::module& m) { - /*************************************************** - * DQ SerialManipulatorDenso - * **************************************************/ py::class_< DQ_SerialManipulatorDenso, std::shared_ptr, - DQ_SerialManipulator> dqserialmanipulatordh_py(m, "DQ_SerialManipulatorDenso"); - dqserialmanipulatordh_py.def(py::init()); - - ///Methods - //Concrete - dqserialmanipulatordh_py.def("get_as", &DQ_SerialManipulatorDenso::get_as, "Retrieves the vector of as."); - dqserialmanipulatordh_py.def("get_bs", &DQ_SerialManipulatorDenso::get_bs, "Retrieves the vector of bs."); - dqserialmanipulatordh_py.def("get_ds", &DQ_SerialManipulatorDenso::get_ds, "Retrieves the vector of ds."); - - dqserialmanipulatordh_py.def("get_alphas", &DQ_SerialManipulatorDenso::get_alphas, "Retrieves the vector of alphas."); - dqserialmanipulatordh_py.def("get_betas", &DQ_SerialManipulatorDenso::get_betas, "Retrieves the vector of betas."); - dqserialmanipulatordh_py.def("get_thetas", &DQ_SerialManipulatorDenso::get_gammas, "Retrieves the vector of gammas."); - - //Overrides from DQ_SerialManipulator - dqserialmanipulatordh_py.def("raw_pose_jacobian", (MatrixXd (DQ_SerialManipulatorDenso::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDenso::raw_pose_jacobian, "Retrieves the raw pose Jacobian."); - dqserialmanipulatordh_py.def("raw_fkm", (DQ (DQ_SerialManipulatorDenso::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDenso::raw_fkm, "Retrieves the raw FKM."); - dqserialmanipulatordh_py.def("raw_pose_jacobian_derivative",(MatrixXd (DQ_SerialManipulatorDenso::*)(const VectorXd&, const VectorXd&, const int&) const) - &DQ_SerialManipulatorDenso::raw_pose_jacobian_derivative, "Retrieves the raw pose Jacobian derivative."); + DQ_SerialManipulator> dqserialmanipulatordh_py( + m, + "DQ_SerialManipulatorDenso", + "Concrete serial manipulator that uses the DENSO kinematic convention. The constructor expects a 6 x n matrix whose rows store the convention parameters a, b, d, alpha, beta, and gamma for each link."); + dqserialmanipulatordh_py.def( + py::init(), + py::arg("denso_matrix"), + "Constructs a serial manipulator from a DENSO-parameter matrix."); + + dqserialmanipulatordh_py.def( + "get_as", + &DQ_SerialManipulatorDenso::get_as, + "Returns the a row of the stored DENSO matrix."); + dqserialmanipulatordh_py.def( + "get_bs", + &DQ_SerialManipulatorDenso::get_bs, + "Returns the b row of the stored DENSO matrix."); + dqserialmanipulatordh_py.def( + "get_ds", + &DQ_SerialManipulatorDenso::get_ds, + "Returns the d row of the stored DENSO matrix."); + dqserialmanipulatordh_py.def( + "get_alphas", + &DQ_SerialManipulatorDenso::get_alphas, + "Returns the alpha row of the stored DENSO matrix."); + dqserialmanipulatordh_py.def( + "get_betas", + &DQ_SerialManipulatorDenso::get_betas, + "Returns the beta row of the stored DENSO matrix."); + dqserialmanipulatordh_py.def( + "get_thetas", + &DQ_SerialManipulatorDenso::get_gammas, + "Returns the gamma row of the stored DENSO matrix."); + + dqserialmanipulatordh_py.def( + "raw_pose_jacobian", + (MatrixXd (DQ_SerialManipulatorDenso::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDenso::raw_pose_jacobian, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the raw pose Jacobian under the DENSO convention up to the requested link."); + dqserialmanipulatordh_py.def( + "raw_fkm", + (DQ (DQ_SerialManipulatorDenso::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorDenso::raw_fkm, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the raw forward kinematics under the DENSO convention up to the requested link."); + dqserialmanipulatordh_py.def( + "raw_pose_jacobian_derivative", + (MatrixXd (DQ_SerialManipulatorDenso::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_SerialManipulatorDenso::raw_pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_ith_link"), + "Computes the time derivative of the raw pose Jacobian under the DENSO convention up to the requested link."); } diff --git a/src/robot_modeling/DQ_SerialManipulatorMDH_py.cpp b/src/robot_modeling/DQ_SerialManipulatorMDH_py.cpp index 16860b8..dd05839 100644 --- a/src/robot_modeling/DQ_SerialManipulatorMDH_py.cpp +++ b/src/robot_modeling/DQ_SerialManipulatorMDH_py.cpp @@ -22,29 +22,64 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_SerialManipulatorMDH`, the concrete serial manipulator + * based on the modified Denavit-Hartenberg convention, to the Python module + * @p m. + */ void init_DQ_SerialManipulatorMDH_py(py::module& m) { - /*************************************************** - * DQ SerialManipulatorMDH - * **************************************************/ py::class_< DQ_SerialManipulatorMDH, std::shared_ptr, DQ_SerialManipulator - > dqserialmanipulatormdh_py(m, "DQ_SerialManipulatorMDH"); - dqserialmanipulatormdh_py.def(py::init()); - - ///Methods - //Concrete - dqserialmanipulatormdh_py.def("get_thetas", &DQ_SerialManipulatorMDH::get_thetas, "Retrieves the vector of thetas."); - dqserialmanipulatormdh_py.def("get_ds", &DQ_SerialManipulatorMDH::get_ds, "Retrieves the vector of ds."); - dqserialmanipulatormdh_py.def("get_as", &DQ_SerialManipulatorMDH::get_as, "Retrieves the vector of as."); - dqserialmanipulatormdh_py.def("get_alphas", &DQ_SerialManipulatorMDH::get_alphas, "Retrieves the vector of alphas."); - dqserialmanipulatormdh_py.def("get_types", &DQ_SerialManipulatorMDH::get_types, "Retrieves the vector of types."); - - //Overrides from DQ_SerialManipulator - dqserialmanipulatormdh_py.def("raw_pose_jacobian", (MatrixXd (DQ_SerialManipulatorMDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorMDH::raw_pose_jacobian, "Retrieves the raw pose Jacobian."); - dqserialmanipulatormdh_py.def("raw_fkm", (DQ (DQ_SerialManipulatorMDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorMDH::raw_fkm, "Retrieves the raw FKM."); - dqserialmanipulatormdh_py.def("raw_pose_jacobian_derivative",(MatrixXd (DQ_SerialManipulatorMDH::*)(const VectorXd&, const VectorXd&, const int&) const) - &DQ_SerialManipulatorMDH::raw_pose_jacobian_derivative, "Retrieves the raw pose Jacobian derivative."); + > dqserialmanipulatormdh_py( + m, + "DQ_SerialManipulatorMDH", + "Concrete serial manipulator based on the modified Denavit-Hartenberg convention. The constructor expects a 5 x n matrix whose rows store theta, d, a, alpha, and the joint type of each link."); + dqserialmanipulatormdh_py.def( + py::init(), + py::arg("mdh_matrix"), + "Constructs a serial manipulator from a modified DH matrix."); + + dqserialmanipulatormdh_py.def( + "get_thetas", + &DQ_SerialManipulatorMDH::get_thetas, + "Returns the theta row of the stored modified DH matrix."); + dqserialmanipulatormdh_py.def( + "get_ds", + &DQ_SerialManipulatorMDH::get_ds, + "Returns the d row of the stored modified DH matrix."); + dqserialmanipulatormdh_py.def( + "get_as", + &DQ_SerialManipulatorMDH::get_as, + "Returns the a row of the stored modified DH matrix."); + dqserialmanipulatormdh_py.def( + "get_alphas", + &DQ_SerialManipulatorMDH::get_alphas, + "Returns the alpha row of the stored modified DH matrix."); + dqserialmanipulatormdh_py.def( + "get_types", + &DQ_SerialManipulatorMDH::get_types, + "Returns the joint-type row of the stored modified DH matrix as encoded joint types."); + + dqserialmanipulatormdh_py.def( + "raw_pose_jacobian", + (MatrixXd (DQ_SerialManipulatorMDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorMDH::raw_pose_jacobian, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the raw pose Jacobian under the modified DH convention up to the requested link."); + dqserialmanipulatormdh_py.def( + "raw_fkm", + (DQ (DQ_SerialManipulatorMDH::*)(const VectorXd&, const int&) const)&DQ_SerialManipulatorMDH::raw_fkm, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the raw forward kinematics under the modified DH convention up to the requested link."); + dqserialmanipulatormdh_py.def( + "raw_pose_jacobian_derivative", + (MatrixXd (DQ_SerialManipulatorMDH::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_SerialManipulatorMDH::raw_pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_ith_link"), + "Computes the time derivative of the raw pose Jacobian under the modified DH convention up to the requested link."); } diff --git a/src/robot_modeling/DQ_SerialManipulator_py.cpp b/src/robot_modeling/DQ_SerialManipulator_py.cpp index 0f9d4e9..da15b39 100644 --- a/src/robot_modeling/DQ_SerialManipulator_py.cpp +++ b/src/robot_modeling/DQ_SerialManipulator_py.cpp @@ -22,48 +22,124 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_SerialManipulator`, the abstract serial-manipulator base + * class that extends `DQ_Kinematics` with common fixed-base and mobile-base + * serial-chain operations, to the Python module @p m. + */ void init_DQ_SerialManipulator_py(py::module& m) { - /*************************************************** - * DQ SerialManipulator - * **************************************************/ py::class_< DQ_SerialManipulator, std::shared_ptr, DQ_Kinematics - > dqserialmanipulator_py(m, "DQ_SerialManipulator"); - //dqserialmanipulator_py.def(py::init()); + > dqserialmanipulator_py( + m, + "DQ_SerialManipulator", + "Abstract class that defines serial manipulators. It extends DQ_Kinematics with the common operations of fixed-base and mobile-base serial chains while subclasses implement the raw forward kinematics and raw Jacobians for a specific parameterization."); - ///Methods - //Concrete - dqserialmanipulator_py.def("get_effector", &DQ_SerialManipulator::get_effector,"Retrieves the effector."); - dqserialmanipulator_py.def("set_effector", &DQ_SerialManipulator::set_effector,"Sets the effector."); - dqserialmanipulator_py.def("get_lower_q_limit", &DQ_SerialManipulator::get_lower_q_limit,"Retrieves the lower limit for the joint values."); - dqserialmanipulator_py.def("set_lower_q_limit", &DQ_SerialManipulator::set_lower_q_limit,"Sets the lower limit for the joint values."); - dqserialmanipulator_py.def("get_lower_q_dot_limit", &DQ_SerialManipulator::get_lower_q_dot_limit,"Retrieves the lower limit for the joint velocities."); - dqserialmanipulator_py.def("set_lower_q_dot_limit", &DQ_SerialManipulator::set_lower_q_dot_limit,"Sets the lower limit for the joint velocities."); - dqserialmanipulator_py.def("get_upper_q_limit", &DQ_SerialManipulator::get_upper_q_limit,"Retrieves the upper limit for the joint values."); - dqserialmanipulator_py.def("set_upper_q_limit", &DQ_SerialManipulator::set_upper_q_limit,"Sets the upper limit for the joint values."); - dqserialmanipulator_py.def("get_upper_q_dot_limit", &DQ_SerialManipulator::get_upper_q_dot_limit,"Retrieves the upper limit for the joint velocities."); - dqserialmanipulator_py.def("set_upper_q_dot_limit", &DQ_SerialManipulator::set_upper_q_dot_limit,"Sets the upper limit for the joint velocities."); + dqserialmanipulator_py.def( + "get_effector", + &DQ_SerialManipulator::get_effector, + "Returns the current end-effector rigid transformation appended to the last link."); + dqserialmanipulator_py.def( + "set_effector", + &DQ_SerialManipulator::set_effector, + py::arg("new_effector"), + "Sets the current end-effector rigid transformation from the last link to the tool frame."); + dqserialmanipulator_py.def( + "get_lower_q_limit", + &DQ_SerialManipulator::get_lower_q_limit, + "Returns the lower joint-position limits."); + dqserialmanipulator_py.def( + "set_lower_q_limit", + &DQ_SerialManipulator::set_lower_q_limit, + py::arg("lower_q_limit"), + "Sets the lower joint-position limits."); + dqserialmanipulator_py.def( + "get_lower_q_dot_limit", + &DQ_SerialManipulator::get_lower_q_dot_limit, + "Returns the lower joint-velocity limits."); + dqserialmanipulator_py.def( + "set_lower_q_dot_limit", + &DQ_SerialManipulator::set_lower_q_dot_limit, + py::arg("lower_q_dot_limit"), + "Sets the lower joint-velocity limits."); + dqserialmanipulator_py.def( + "get_upper_q_limit", + &DQ_SerialManipulator::get_upper_q_limit, + "Returns the upper joint-position limits."); + dqserialmanipulator_py.def( + "set_upper_q_limit", + &DQ_SerialManipulator::set_upper_q_limit, + py::arg("upper_q_limit"), + "Sets the upper joint-position limits."); + dqserialmanipulator_py.def( + "get_upper_q_dot_limit", + &DQ_SerialManipulator::get_upper_q_dot_limit, + "Returns the upper joint-velocity limits."); + dqserialmanipulator_py.def( + "set_upper_q_dot_limit", + &DQ_SerialManipulator::set_upper_q_dot_limit, + py::arg("upper_q_dot_limit"), + "Sets the upper joint-velocity limits."); - //Virtual - dqserialmanipulator_py.def("raw_fkm", (DQ (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::raw_fkm,"Gets the raw fkm."); - dqserialmanipulator_py.def("raw_pose_jacobian", (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::raw_pose_jacobian,"Returns the pose Jacobian without base or effector transformation"); - dqserialmanipulator_py.def("raw_pose_jacobian_derivative",(MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const VectorXd&) const) - &DQ_SerialManipulator::raw_pose_jacobian_derivative, - "Returns the pose Jacobian derivative without base or effector transformation"); + dqserialmanipulator_py.def( + "raw_fkm", + (DQ (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::raw_fkm, + py::arg("q_vec"), + "Computes the raw forward kinematics up to the last link and returns the pose before applying the reference frame and the end effector."); + dqserialmanipulator_py.def( + "raw_pose_jacobian", + (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::raw_pose_jacobian, + py::arg("q_vec"), + "Computes the raw pose Jacobian up to the last link, without reference-frame or end-effector transformations."); + dqserialmanipulator_py.def( + "raw_pose_jacobian_derivative", + (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const VectorXd&) const)&DQ_SerialManipulator::raw_pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + "Computes the time derivative of the raw pose Jacobian up to the last link."); - //Overrides from DQ_Kinematics - dqserialmanipulator_py.def("fkm", (DQ (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::fkm,"Gets the fkm."); - dqserialmanipulator_py.def("fkm", (DQ (DQ_SerialManipulator::*)(const VectorXd&,const int&) const)&DQ_SerialManipulator::fkm,"Gets the fkm."); + dqserialmanipulator_py.def( + "fkm", + (DQ (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::fkm, + py::arg("q_vec"), + "Computes the forward kinematics of the end effector, including the reference frame and the stored end-effector rigid transformation."); + dqserialmanipulator_py.def( + "fkm", + (DQ (DQ_SerialManipulator::*)(const VectorXd&,const int&) const)&DQ_SerialManipulator::fkm, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the forward kinematics up to a given link, including the reference frame and applying the stored end-effector transformation only when the requested link is the last one."); - dqserialmanipulator_py.def("get_dim_configuration_space", &DQ_SerialManipulator::get_dim_configuration_space,"Retrieves the number of links."); + dqserialmanipulator_py.def( + "get_dim_configuration_space", + &DQ_SerialManipulator::get_dim_configuration_space, + "Returns the dimension of the configuration space as the number of generalized coordinates of the serial manipulator."); - dqserialmanipulator_py.def("pose_jacobian", (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const int&) const)&DQ_SerialManipulator::pose_jacobian,"Returns the pose Jacobian"); - dqserialmanipulator_py.def("pose_jacobian", (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::pose_jacobian,"Returns the pose Jacobian"); - dqserialmanipulator_py.def("pose_jacobian_derivative", (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const VectorXd&, const int&) const) - &DQ_SerialManipulator::pose_jacobian_derivative,"Returns the pose Jacobian derivative"); - dqserialmanipulator_py.def("pose_jacobian_derivative", (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const VectorXd&) const) - &DQ_SerialManipulator::pose_jacobian_derivative,"Returns the pose Jacobian derivative"); + dqserialmanipulator_py.def( + "pose_jacobian", + (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const int&) const)&DQ_SerialManipulator::pose_jacobian, + py::arg("q_vec"), + py::arg("to_ith_link"), + "Computes the pose Jacobian up to a given link. The returned Jacobian includes the reference frame and applies the stored end-effector transformation only when the requested link is the last one."); + dqserialmanipulator_py.def( + "pose_jacobian", + (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&) const)&DQ_SerialManipulator::pose_jacobian, + py::arg("q_vec"), + "Computes the pose Jacobian of the end effector so that vec8(pose_dot) = J * q_dot."); + dqserialmanipulator_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_SerialManipulator::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_ith_link"), + "Computes the time derivative of the pose Jacobian up to a given link, including the reference frame and applying the stored end-effector transformation only when the requested link is the last one."); + dqserialmanipulator_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_SerialManipulator::*)(const VectorXd&, const VectorXd&) const)&DQ_SerialManipulator::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + "Computes the time derivative of the pose Jacobian of the end effector."); } diff --git a/src/robot_modeling/DQ_SerialWholeBody_py.cpp b/src/robot_modeling/DQ_SerialWholeBody_py.cpp index 7795f80..26f27d9 100644 --- a/src/robot_modeling/DQ_SerialWholeBody_py.cpp +++ b/src/robot_modeling/DQ_SerialWholeBody_py.cpp @@ -26,28 +26,93 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_SerialWholeBody`, the robot model composed of multiple + * serially coupled kinematic chains with a single combined link index, to the + * Python module @p m. + */ void init_DQ_SerialWholeBody_py(py::module& m) { - /***************************************************** - * DQ WholeBody - * **************************************************/ py::class_< DQ_SerialWholeBody, std::shared_ptr, DQ_Kinematics - > dqserialwholebody_py(m,"DQ_SerialWholeBody"); - dqserialwholebody_py.def(py::init>()); - dqserialwholebody_py.def("add",&DQ_SerialWholeBody::add,"Adds a DQ_Kinematics pointer to the kinematic chain."); - dqserialwholebody_py.def("fkm",(DQ (DQ_SerialWholeBody::*)(const VectorXd&) const)&DQ_SerialWholeBody::fkm,"Gets the fkm."); - dqserialwholebody_py.def("fkm",(DQ (DQ_SerialWholeBody::*)(const VectorXd&,const int&) const)&DQ_SerialWholeBody::fkm,"Gets the fkm."); - dqserialwholebody_py.def("raw_fkm",(DQ (DQ_SerialWholeBody::*)(const VectorXd&) const)&DQ_SerialWholeBody::raw_fkm,"Gets the fkm but without considering base and end-effector changes."); - dqserialwholebody_py.def("raw_fkm",(DQ (DQ_SerialWholeBody::*)(const VectorXd&, const int&) const)&DQ_SerialWholeBody::raw_fkm,"Gets the fkm but without considering base and end-effector changes."); - dqserialwholebody_py.def("get_dim_configuration_space",&DQ_SerialWholeBody::get_dim_configuration_space,"Gets the dimention of the configuration space"); - dqserialwholebody_py.def("get_chain",&DQ_SerialWholeBody::get_chain, "Returns the DQ_Kinematics at a given index of the chain"); - dqserialwholebody_py.def("get_chain_as_serial_manipulator_dh",&DQ_SerialWholeBody::get_chain_as_serial_manipulator_dh, "Returns the DQ_SerialManipulatorDH at a given index of the chain"); - dqserialwholebody_py.def("get_chain_as_holonomic_base",&DQ_SerialWholeBody::get_chain_as_holonomic_base, "Returns the DQ_HolonomicBase at a given index of the chain"); - dqserialwholebody_py.def("pose_jacobian",(MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&, const int&) const)&DQ_SerialWholeBody::pose_jacobian,"Returns the pose Jacobian"); - dqserialwholebody_py.def("pose_jacobian",(MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&) const)&DQ_SerialWholeBody::pose_jacobian,"Returns the pose Jacobian"); - dqserialwholebody_py.def("pose_jacobian_derivative",(MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_SerialWholeBody::pose_jacobian_derivative,"Returns the pose Jacobian derivative"); - dqserialwholebody_py.def("pose_jacobian_derivative",(MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&, const VectorXd&) const)&DQ_SerialWholeBody::pose_jacobian_derivative,"Returns the pose Jacobian derivative"); + > dqserialwholebody_py( + m, + "DQ_SerialWholeBody", + "Robot model composed of multiple serially coupled kinematic chains. DQ_SerialWholeBody concatenates several DQ_Kinematics objects and exposes a single combined link index across the whole serial composition."); + dqserialwholebody_py.def( + py::init>(), + py::arg("robot"), + "Constructs a serial whole-body model from its first chain."); + dqserialwholebody_py.def( + "add", + &DQ_SerialWholeBody::add, + py::arg("robot"), + "Appends a new chain to the end of the serial whole-body model."); + dqserialwholebody_py.def( + "fkm", + (DQ (DQ_SerialWholeBody::*)(const VectorXd&) const)&DQ_SerialWholeBody::fkm, + py::arg("q"), + "Computes the forward kinematics of the complete serial whole-body model, including the reference frame."); + dqserialwholebody_py.def( + "fkm", + (DQ (DQ_SerialWholeBody::*)(const VectorXd&,const int&) const)&DQ_SerialWholeBody::fkm, + py::arg("q"), + py::arg("to_ith_link"), + "Computes the forward kinematics up to a combined link index, including the reference frame."); + dqserialwholebody_py.def( + "raw_fkm", + (DQ (DQ_SerialWholeBody::*)(const VectorXd&) const)&DQ_SerialWholeBody::raw_fkm, + py::arg("q"), + "Computes the raw forward kinematics of the complete serial whole-body model without the reference frame."); + dqserialwholebody_py.def( + "raw_fkm", + (DQ (DQ_SerialWholeBody::*)(const VectorXd&, const int&) const)&DQ_SerialWholeBody::raw_fkm, + py::arg("q"), + py::arg("to_ith_link"), + "Computes the raw forward kinematics up to a combined link index without the reference frame."); + dqserialwholebody_py.def( + "get_dim_configuration_space", + &DQ_SerialWholeBody::get_dim_configuration_space, + "Returns the dimension of the configuration space of the serial whole-body model."); + dqserialwholebody_py.def( + "get_chain", + &DQ_SerialWholeBody::get_chain, + py::arg("to_ith_chain"), + "Returns a raw pointer to one of the stored chains."); + dqserialwholebody_py.def( + "get_chain_as_serial_manipulator_dh", + &DQ_SerialWholeBody::get_chain_as_serial_manipulator_dh, + py::arg("to_ith_chain"), + "Returns a copy of the selected chain as a DQ_SerialManipulatorDH."); + dqserialwholebody_py.def( + "get_chain_as_holonomic_base", + &DQ_SerialWholeBody::get_chain_as_holonomic_base, + py::arg("to_ith_chain"), + "Returns a copy of the selected chain as a DQ_HolonomicBase."); + dqserialwholebody_py.def( + "pose_jacobian", + (MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&, const int&) const)&DQ_SerialWholeBody::pose_jacobian, + py::arg("q"), + py::arg("to_ith_link"), + "Computes the pose Jacobian up to a combined link index."); + dqserialwholebody_py.def( + "pose_jacobian", + (MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&) const)&DQ_SerialWholeBody::pose_jacobian, + py::arg("q"), + "Computes the pose Jacobian of the complete serial whole-body model."); + dqserialwholebody_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_SerialWholeBody::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_ith_link"), + "Computes the time derivative of the pose Jacobian up to a combined link index. This method is currently not implemented and always throws."); + dqserialwholebody_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_SerialWholeBody::*)(const VectorXd&, const VectorXd&) const)&DQ_SerialWholeBody::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + "Computes the time derivative of the pose Jacobian of the complete serial whole-body model. This method is currently not implemented and always throws."); } diff --git a/src/robot_modeling/DQ_WholeBody_py.cpp b/src/robot_modeling/DQ_WholeBody_py.cpp index cc4b1fc..f170d69 100644 --- a/src/robot_modeling/DQ_WholeBody_py.cpp +++ b/src/robot_modeling/DQ_WholeBody_py.cpp @@ -22,26 +22,82 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_WholeBody`, the robot model composed of multiple kinematic + * chains connected in series and treated as subchains, to the Python module + * @p m. + */ void init_DQ_WholeBody_py(py::module& m) { - /***************************************************** - * DQ WholeBody - * **************************************************/ py::class_< DQ_WholeBody, std::shared_ptr, DQ_Kinematics - > dqwholebody_py(m,"DQ_WholeBody"); - dqwholebody_py.def(py::init>()); - dqwholebody_py.def("add",&DQ_WholeBody::add,"Adds a DQ_Kinematics pointer to the kinematic chain."); - dqwholebody_py.def("fkm",(DQ (DQ_WholeBody::*)(const VectorXd&) const)&DQ_WholeBody::fkm,"Gets the fkm."); - dqwholebody_py.def("fkm",(DQ (DQ_WholeBody::*)(const VectorXd&,const int&) const)&DQ_WholeBody::fkm,"Gets the fkm."); - dqwholebody_py.def("get_dim_configuration_space",&DQ_WholeBody::get_dim_configuration_space,"Gets the dimention of the configuration space"); - dqwholebody_py.def("get_chain",&DQ_WholeBody::get_chain, "Returns the DQ_Kinematics at a given index of the chain"); - dqwholebody_py.def("get_chain_as_serial_manipulator_dh",&DQ_WholeBody::get_chain_as_serial_manipulator_dh, "Returns the DQ_SerialManipulatorDH at a given index of the chain"); - dqwholebody_py.def("get_chain_as_holonomic_base",&DQ_WholeBody::get_chain_as_holonomic_base, "Returns the DQ_HolonomicBase at a given index of the chain"); - dqwholebody_py.def("pose_jacobian",(MatrixXd (DQ_WholeBody::*)(const VectorXd&, const int&) const)&DQ_WholeBody::pose_jacobian,"Returns the pose Jacobian"); - dqwholebody_py.def("pose_jacobian",(MatrixXd (DQ_WholeBody::*)(const VectorXd&) const)&DQ_WholeBody::pose_jacobian,"Returns the pose Jacobian"); - dqwholebody_py.def("pose_jacobian_derivative",(MatrixXd (DQ_WholeBody::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_WholeBody::pose_jacobian_derivative,"Returns the pose Jacobian derivative"); - dqwholebody_py.def("pose_jacobian_derivative",(MatrixXd (DQ_WholeBody::*)(const VectorXd&, const VectorXd&) const)&DQ_WholeBody::pose_jacobian_derivative,"Returns the pose Jacobian derivative"); + > dqwholebody_py( + m, + "DQ_WholeBody", + "Robot model composed of multiple kinematic chains connected in series. DQ_WholeBody concatenates several DQ_Kinematics objects and treats each one as a whole subchain."); + dqwholebody_py.def( + py::init>(), + py::arg("robot"), + "Constructs a whole-body model from its first chain."); + dqwholebody_py.def( + "add", + &DQ_WholeBody::add, + py::arg("robot"), + "Appends a new chain to the end of the whole-body model."); + dqwholebody_py.def( + "fkm", + (DQ (DQ_WholeBody::*)(const VectorXd&) const)&DQ_WholeBody::fkm, + py::arg("q"), + "Computes the forward kinematics of the complete whole-body model, including the reference frame."); + dqwholebody_py.def( + "fkm", + (DQ (DQ_WholeBody::*)(const VectorXd&,const int&) const)&DQ_WholeBody::fkm, + py::arg("q"), + py::arg("to_chain"), + "Computes the forward kinematics up to a given chain, stopping the computation at the requested subchain and including the reference frame."); + dqwholebody_py.def( + "get_dim_configuration_space", + &DQ_WholeBody::get_dim_configuration_space, + "Returns the dimension of the configuration space of the whole-body model."); + dqwholebody_py.def( + "get_chain", + &DQ_WholeBody::get_chain, + py::arg("to_ith_chain"), + "Returns a raw pointer to one of the stored chains."); + dqwholebody_py.def( + "get_chain_as_serial_manipulator_dh", + &DQ_WholeBody::get_chain_as_serial_manipulator_dh, + py::arg("to_ith_chain"), + "Returns a copy of the selected chain as a DQ_SerialManipulatorDH."); + dqwholebody_py.def( + "get_chain_as_holonomic_base", + &DQ_WholeBody::get_chain_as_holonomic_base, + py::arg("to_ith_chain"), + "Returns a copy of the selected chain as a DQ_HolonomicBase."); + dqwholebody_py.def( + "pose_jacobian", + (MatrixXd (DQ_WholeBody::*)(const VectorXd&, const int&) const)&DQ_WholeBody::pose_jacobian, + py::arg("q"), + py::arg("to_ith_chain"), + "Computes the pose Jacobian up to a given chain."); + dqwholebody_py.def( + "pose_jacobian", + (MatrixXd (DQ_WholeBody::*)(const VectorXd&) const)&DQ_WholeBody::pose_jacobian, + py::arg("q"), + "Computes the pose Jacobian of the complete whole-body model."); + dqwholebody_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_WholeBody::*)(const VectorXd&, const VectorXd&, const int&) const)&DQ_WholeBody::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + py::arg("to_ith_link"), + "Computes the time derivative of the pose Jacobian. This method is currently not implemented and always throws."); + dqwholebody_py.def( + "pose_jacobian_derivative", + (MatrixXd (DQ_WholeBody::*)(const VectorXd&, const VectorXd&) const)&DQ_WholeBody::pose_jacobian_derivative, + py::arg("q"), + py::arg("q_dot"), + "Computes the time derivative of the pose Jacobian of the complete whole-body model. This method is currently not implemented and always throws."); } diff --git a/src/solvers/DQ_QuadraticProgrammingSolver_py.cpp b/src/solvers/DQ_QuadraticProgrammingSolver_py.cpp index db42c0a..78d84f9 100644 --- a/src/solvers/DQ_QuadraticProgrammingSolver_py.cpp +++ b/src/solvers/DQ_QuadraticProgrammingSolver_py.cpp @@ -42,6 +42,11 @@ class DQ_QuadraticProgrammingSolverPy : public DQ_QuadraticProgrammingSolver } }; +/** + * @brief Binds `DQ_QuadraticProgrammingSolver`, an abstract interface to + * quadratic-programming solvers used by DQ Robotics controllers, to the + * Python module @p m. + */ void init_DQ_QuadraticProgrammingSolver_py(py::module& m) { /***************************************************** @@ -51,7 +56,19 @@ void init_DQ_QuadraticProgrammingSolver_py(py::module& m) DQ_QuadraticProgrammingSolver, std::shared_ptr, DQ_QuadraticProgrammingSolverPy - > dqquadraticprogrammingsolver_py(m,"DQ_QuadraticProgrammingSolver"); - dqquadraticprogrammingsolver_py.def(py::init<>()); - dqquadraticprogrammingsolver_py.def("solve_quadratic_program", &DQ_QuadraticProgrammingSolver::solve_quadratic_program, "Solves a quadratic program"); + > dqquadraticprogrammingsolver_py( + m, + "DQ_QuadraticProgrammingSolver", + "Abstract interface to quadratic-programming solvers used by DQ Robotics controllers."); + dqquadraticprogrammingsolver_py.def(py::init<>(), + "Default constructor for solver interfaces."); + dqquadraticprogrammingsolver_py.def("solve_quadratic_program", + &DQ_QuadraticProgrammingSolver::solve_quadratic_program, + py::arg("H"), + py::arg("f"), + py::arg("A"), + py::arg("b"), + py::arg("Aeq"), + py::arg("beq"), + "Solves a quadratic program."); } diff --git a/src/utils/DQ_Geometry_py.cpp b/src/utils/DQ_Geometry_py.cpp index 16c9fd1..dfb312a 100644 --- a/src/utils/DQ_Geometry_py.cpp +++ b/src/utils/DQ_Geometry_py.cpp @@ -22,30 +22,89 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_Geometry`, which provides geometric operations for points, + * lines, planes, and line segments, to the Python module @p m. + */ void init_DQ_Geometry_py(py::module& m) { /***************************************************** * DQ_Geometry * **************************************************/ //#include - py::class_ geometry_py(m, "DQ_Geometry"); - geometry_py.def_static("point_to_point_squared_distance", &DQ_Geometry::point_to_point_squared_distance, "Returns the squared distance between two points"); - geometry_py.def_static("point_to_line_squared_distance", &DQ_Geometry::point_to_line_squared_distance, "Returns the squared distance between a point and a line"); - geometry_py.def_static("point_to_plane_distance", &DQ_Geometry::point_to_plane_distance, "Returns the distance between a point and a plane"); - geometry_py.def_static("line_to_line_squared_distance", &DQ_Geometry::line_to_line_squared_distance, "Returns the squared distance between two lines"); - geometry_py.def_static("line_to_line_angle", &DQ_Geometry::line_to_line_angle, "Returns the angle between two lines"); - geometry_py.def_static("point_projected_in_line", &DQ_Geometry::point_projected_in_line, "Returns the point projected in a line."); - geometry_py.def_static("closest_points_between_lines", &DQ_Geometry::closest_points_between_lines, "Returns the closest points between lines"); - geometry_py.def_static("closest_points_between_line_segments", &DQ_Geometry::closest_points_between_line_segments, "Returns the closes points between line segments"); - geometry_py.def_static("line_segment_to_line_segment_squared_distance", &DQ_Geometry::line_segment_to_line_segment_squared_distance, "Returns the squared distance between two line segments."); - - geometry_py.def_static("is_line_segment",&DQ_Geometry::is_line_segment,"Verifies if the inputs constitute a valid line segment."); + py::class_ geometry_py( + m, + "DQ_Geometry", + "Provides geometric operations for points, lines, planes, and line segments."); + geometry_py.def_static("point_to_point_squared_distance", + &DQ_Geometry::point_to_point_squared_distance, + py::arg("point1"), + py::arg("point2"), + "Computes the squared Euclidean distance between two points represented as pure quaternions."); + geometry_py.def_static("point_to_line_squared_distance", + &DQ_Geometry::point_to_line_squared_distance, + py::arg("point"), + py::arg("line"), + "Computes the squared Euclidean distance between a point and a line."); + geometry_py.def_static("point_to_plane_distance", + &DQ_Geometry::point_to_plane_distance, + py::arg("point"), + py::arg("plane"), + "Computes the signed distance from a point to a plane."); + geometry_py.def_static("line_to_line_squared_distance", + &DQ_Geometry::line_to_line_squared_distance, + py::arg("line1"), + py::arg("line2"), + "Computes the squared Euclidean distance between two lines."); + geometry_py.def_static("line_to_line_angle", + &DQ_Geometry::line_to_line_angle, + py::arg("line1"), + py::arg("line2"), + "Computes the angle between two lines in radians."); + geometry_py.def_static("point_projected_in_line", + &DQ_Geometry::point_projected_in_line, + py::arg("point"), + py::arg("line"), + "Projects a point onto a line and returns the projected point as a pure quaternion."); + geometry_py.def_static("closest_points_between_lines", + &DQ_Geometry::closest_points_between_lines, + py::arg("line1"), + py::arg("line2"), + "Computes and returns the closest point on each of two lines."); + geometry_py.def_static("closest_points_between_line_segments", + &DQ_Geometry::closest_points_between_line_segments, + py::arg("line_1"), + py::arg("line_1_point_1"), + py::arg("line_1_point_2"), + py::arg("line_2"), + py::arg("line_2_point_1"), + py::arg("line_2_point_2"), + "Computes and returns the closest point on each of two valid line segments."); + geometry_py.def_static("line_segment_to_line_segment_squared_distance", + &DQ_Geometry::line_segment_to_line_segment_squared_distance, + py::arg("line_1"), + py::arg("line_1_point_1"), + py::arg("line_1_point_2"), + py::arg("line_2"), + py::arg("line_2_point_1"), + py::arg("line_2_point_2"), + "Computes the squared Euclidean distance between two valid line segments."); + + geometry_py.def_static("is_line_segment", + &DQ_Geometry::is_line_segment, + py::arg("line"), + py::arg("line_point_1"), + py::arg("line_point_2"), + py::arg("threshold") = DQ_threshold, + "Checks whether a line and two endpoints define a valid line segment within the given threshold."); //Overload with the default threshold geometry_py.def_static("is_line_segment", - [](const DQ& a1, const DQ& a2, const DQ& a3) + [](const DQ& line, const DQ& line_point_1, const DQ& line_point_2) { - return DQ_Geometry::is_line_segment(a1,a2,a3); + return DQ_Geometry::is_line_segment(line,line_point_1,line_point_2); }, - "Verifies if the inputs constitute a valid line segment."); + py::arg("line"), + py::arg("line_point_1"), + py::arg("line_point_2"), + "Checks whether a line and two endpoints define a valid line segment using the library default threshold."); } - diff --git a/src/utils/DQ_LinearAlgebra_py.cpp b/src/utils/DQ_LinearAlgebra_py.cpp index 86c3e24..b397fa4 100644 --- a/src/utils/DQ_LinearAlgebra_py.cpp +++ b/src/utils/DQ_LinearAlgebra_py.cpp @@ -22,12 +22,19 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_LinearAlgebra`, which provides linear-algebra utilities such + * as matrix pseudoinversion, to the Python module @p m. + */ void init_DQ_LinearAlgebra_py(py::module& m) { /***************************************************** * DQ_LinearAlgebra * **************************************************/ //#include - py::module linearalgebra_py = m.def_submodule("_DQ_LinearAlgebra","A submodule of utils"); - linearalgebra_py.def("pinv", (MatrixXd (*) (const MatrixXd&))&DQ_robotics::pinv, "Retrieves the pseudo-inverse of the input matrix"); + py::module linearalgebra_py = m.def_submodule("_DQ_LinearAlgebra","Linear-algebra utilities."); + linearalgebra_py.def("pinv", + (MatrixXd (*) (const MatrixXd&))&DQ_robotics::pinv, + py::arg("matrix"), + "Computes the Moore-Penrose pseudoinverse of the input matrix."); } diff --git a/src/utils/DQ_Math_py.cpp b/src/utils/DQ_Math_py.cpp index 1805ba2..50d0787 100644 --- a/src/utils/DQ_Math_py.cpp +++ b/src/utils/DQ_Math_py.cpp @@ -22,15 +22,31 @@ This file is part of DQ Robotics. #include "../dqrobotics_module.h" +/** + * @brief Binds `DQ_Math`, which provides scalar and vector angle-conversion + * utilities, to the Python module @p m. + */ void init_DQ_Math_py(py::module& m) { /***************************************************** * DQ_Math * **************************************************/ //#include - py::module math_py = m.def_submodule("_DQ_Math","A submodule of utils"); - math_py.def("deg2rad", static_cast(&DQ_robotics::deg2rad), "Converts from degrees to radians."); - math_py.def("deg2rad", static_cast(&DQ_robotics::deg2rad), "Converts from degrees to radians."); - math_py.def("rad2deg", static_cast(&DQ_robotics::rad2deg), "Converts from degrees to radians."); - math_py.def("rad2deg", static_cast(&DQ_robotics::rad2deg), "Converts from degrees to radians."); + py::module math_py = m.def_submodule("_DQ_Math","Angle-conversion utilities."); + math_py.def("deg2rad", + static_cast(&DQ_robotics::deg2rad), + py::arg("a"), + "Converts an angle from degrees to radians."); + math_py.def("deg2rad", + static_cast(&DQ_robotics::deg2rad), + py::arg("v"), + "Converts each component of a vector from degrees to radians."); + math_py.def("rad2deg", + static_cast(&DQ_robotics::rad2deg), + py::arg("a"), + "Converts an angle from radians to degrees."); + math_py.def("rad2deg", + static_cast(&DQ_robotics::rad2deg), + py::arg("v"), + "Converts each component of a vector from radians to degrees."); }