From 0a8357568085d43f5a7c518d8cb60958406d0484 Mon Sep 17 00:00:00 2001
From: egordv <40291783+egordv@users.noreply.github.com>
Date: Fri, 2 Feb 2024 11:28:21 +0300
Subject: [PATCH] Two frames contact pr (#218)
* TaskTwoFramesEquality and ContactTwoFramePositions added with appropriate bindings.
* getMotionTask type changed from TaskSE3Equality to TaskMotion to allow contacts use different motion tasks, not only TaskSE3Equality
* python demo of talos gripper with closed kinematic chain, using URDF/STLs in external repo
---------
Authored-by: @egordv
---
CMakeLists.txt | 19 +-
.../contacts/contact-two-frame-positions.cpp | 29 +++
.../python/tasks/task-two-frames-equality.cpp | 28 +++
demo/demo_quadruped.py | 3 +-
...id_talos_gripper_closed_kinematic_chain.py | 196 +++++++++++++++++
exercizes/ex_0_ur5_joint_space_control.py | 3 +-
exercizes/ex_4_walking.py | 3 +-
.../notebooks/Installation process.ipynb | 2 +-
...x_0_joint_space_inverse_dynamics_arm.ipynb | 2 +-
.../notebooks/ex_1_com_sin_track_talos.ipynb | 2 +-
.../ex_3_biped_balance_with_gui.ipynb | 2 +-
exercizes/tsid_biped.py | 1 -
exercizes/tsid_manipulator.py | 1 -
.../contacts/contact-two-frame-positions.hpp | 204 ++++++++++++++++++
.../python/contacts/contact-two-frames.hpp | 202 +++++++++++++++++
.../python/contacts/expose-contact.hpp | 3 +
.../python/formulations/formulation.hpp | 30 +++
.../bindings/python/tasks/expose-tasks.hpp | 3 +
.../python/tasks/task-two-frames-equality.hpp | 149 +++++++++++++
include/tsid/contacts/contact-base.hpp | 3 +-
.../contacts/contact-two-frame-positions.hpp | 119 ++++++++++
.../tsid/tasks/task-two-frames-equality.hpp | 123 +++++++++++
src/contacts/contact-two-frame-positions.cpp | 193 +++++++++++++++++
src/tasks/task-cop-equality.cpp | 6 +-
src/tasks/task-two-frames-equality.cpp | 181 ++++++++++++++++
tests/python/test_Constraint.py | 1 -
tests/python/test_Contact.py | 1 -
tests/python/test_ContactPoint.py | 1 -
tests/python/test_Deprecations.py | 1 -
tests/python/test_Formulation.py | 3 +-
tests/python/test_Gravity.py | 1 -
tests/python/test_RobotWrapper.py | 1 -
tests/python/test_Solvers.py | 1 -
tests/python/test_Tasks.py | 3 +-
tests/python/test_Trajectories.py | 1 -
35 files changed, 1489 insertions(+), 32 deletions(-)
create mode 100644 bindings/python/contacts/contact-two-frame-positions.cpp
create mode 100644 bindings/python/tasks/task-two-frames-equality.cpp
create mode 100644 demo/demo_tsid_talos_gripper_closed_kinematic_chain.py
create mode 100644 include/tsid/bindings/python/contacts/contact-two-frame-positions.hpp
create mode 100644 include/tsid/bindings/python/contacts/contact-two-frames.hpp
create mode 100644 include/tsid/bindings/python/tasks/task-two-frames-equality.hpp
create mode 100644 include/tsid/contacts/contact-two-frame-positions.hpp
create mode 100644 include/tsid/tasks/task-two-frames-equality.hpp
create mode 100644 src/contacts/contact-two-frame-positions.cpp
create mode 100644 src/tasks/task-two-frames-equality.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c45d6c2..11a6356d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -147,7 +147,8 @@ set(${PROJECT_NAME}_TASKS_HEADERS
include/tsid/tasks/task-joint-posture.hpp
include/tsid/tasks/task-joint-posVelAcc-bounds.hpp
include/tsid/tasks/task-capture-point-inequality.hpp
- include/tsid/tasks/task-angular-momentum-equality.hpp)
+ include/tsid/tasks/task-angular-momentum-equality.hpp
+ include/tsid/tasks/task-two-frames-equality.hpp)
set(${PROJECT_NAME}_CONTACTS_HEADERS
include/tsid/contacts/fwd.hpp
@@ -156,7 +157,8 @@ set(${PROJECT_NAME}_CONTACTS_HEADERS
include/tsid/contacts/contact-point.hpp
include/tsid/contacts/measured-force-base.hpp
include/tsid/contacts/measured-3Dforce.hpp
- include/tsid/contacts/measured-6Dwrench.hpp)
+ include/tsid/contacts/measured-6Dwrench.hpp
+ include/tsid/contacts/contact-two-frame-positions.hpp)
set(${PROJECT_NAME}_TRAJECTORIES_HEADERS
include/tsid/trajectories/fwd.hpp
@@ -264,12 +266,17 @@ set(${PROJECT_NAME}_TASKS_SOURCES
src/tasks/task-capture-point-inequality.cpp
src/tasks/task-motion.cpp
src/tasks/task-se3-equality.cpp
- src/tasks/task-angular-momentum-equality.cpp)
+ src/tasks/task-angular-momentum-equality.cpp
+ src/tasks/task-two-frames-equality.cpp)
set(${PROJECT_NAME}_CONTACTS_SOURCES
- src/contacts/contact-base.cpp src/contacts/contact-6d.cpp
- src/contacts/contact-point.cpp src/contacts/measured-force-base.cpp
- src/contacts/measured-3Dforce.cpp src/contacts/measured-6Dwrench.cpp)
+ src/contacts/contact-base.cpp
+ src/contacts/contact-6d.cpp
+ src/contacts/contact-point.cpp
+ src/contacts/measured-force-base.cpp
+ src/contacts/measured-3Dforce.cpp
+ src/contacts/measured-6Dwrench.cpp
+ src/contacts/contact-two-frame-positions.cpp)
set(${PROJECT_NAME}_TRAJECTORIES_SOURCES
src/trajectories/trajectory-se3.cpp
diff --git a/bindings/python/contacts/contact-two-frame-positions.cpp b/bindings/python/contacts/contact-two-frame-positions.cpp
new file mode 100644
index 00000000..5a148ccb
--- /dev/null
+++ b/bindings/python/contacts/contact-two-frame-positions.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#include "tsid/bindings/python/contacts/contact-two-frame-positions.hpp"
+#include "tsid/bindings/python/contacts/expose-contact.hpp"
+
+namespace tsid {
+namespace python {
+void exposeContactTwoFramePositions() {
+ ContactTwoFramePositionsPythonVisitor<
+ tsid::contacts::ContactTwoFramePositions>::
+ expose("ContactTwoFramePositions");
+}
+} // namespace python
+} // namespace tsid
diff --git a/bindings/python/tasks/task-two-frames-equality.cpp b/bindings/python/tasks/task-two-frames-equality.cpp
new file mode 100644
index 00000000..08c02227
--- /dev/null
+++ b/bindings/python/tasks/task-two-frames-equality.cpp
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#include "tsid/bindings/python/tasks/task-two-frames-equality.hpp"
+#include "tsid/bindings/python/tasks/expose-tasks.hpp"
+
+namespace tsid {
+namespace python {
+void exposeTaskTwoFramesEquality() {
+ TaskTwoFramesEqualityPythonVisitor<
+ tsid::tasks::TaskTwoFramesEquality>::expose("TaskTwoFramesEquality");
+}
+} // namespace python
+} // namespace tsid
diff --git a/demo/demo_quadruped.py b/demo/demo_quadruped.py
index 411eb0ad..b708671f 100644
--- a/demo/demo_quadruped.py
+++ b/demo/demo_quadruped.py
@@ -6,11 +6,10 @@
import gepetto.corbaserver
import numpy as np
import pinocchio as pin
+import tsid
from numpy import nan
from numpy.linalg import norm as norm
-import tsid
-
sys.path += [os.getcwd() + "/../exercizes"]
import matplotlib.pyplot as plt
import plot_utils as plut
diff --git a/demo/demo_tsid_talos_gripper_closed_kinematic_chain.py b/demo/demo_tsid_talos_gripper_closed_kinematic_chain.py
new file mode 100644
index 00000000..e48918d2
--- /dev/null
+++ b/demo/demo_tsid_talos_gripper_closed_kinematic_chain.py
@@ -0,0 +1,196 @@
+"""
+Simple demo of usage of ContactTwoFramePositions in TSID
+Make the Talos gripper model works with closed kinematic chains
+(c) MIPT
+"""
+import os
+import time
+
+import numpy as np
+import pinocchio as pin
+import tsid
+from numpy import nan
+from numpy.linalg import norm as norm
+
+np.set_printoptions(precision=3, linewidth=200, suppress=True)
+
+LINE_WIDTH = 60
+print("".center(LINE_WIDTH, "#"))
+print(
+ " Demo of TSID with Closed Kinematic Chains via ContactTwoFramePositions".center(
+ LINE_WIDTH, "#"
+ )
+)
+print("".center(LINE_WIDTH, "#"), "\n")
+
+w_ee = 1.0 # weight of end effector task
+w_posture = 1e-3 # weight of joint posture task
+
+kp_ee = 10.0 # proportional gain of end effector task
+kp_posture = 10.0 # proportional gain of joint posture task
+
+dt = 0.001 # controller time step
+PRINT_N = 500 # print every PRINT_N time steps
+DISPLAY_N = 25 # update robot configuration in viwewer every DISPLAY_N time steps
+N_SIMULATION = 6000 # number of time steps simulated
+
+# Loading Talos gripper model modified with extra links to mark the position of contact creation
+# Talos gripepr model (c) 2016, PAL Robotics, S.L.
+# Please use https://github.com/egordv/tsid_demo_closed_kinematic_chain repo for the model files
+
+filename = str(os.path.dirname(os.path.abspath(__file__)))
+path = filename + "../../tsid_demo_closed_kinematic_chain/models/talos_gripper"
+urdf = path + "../../tsid_demo_closed_kinematic_chain/urdf/talos_gripper_half.urdf"
+vector = pin.StdVec_StdString()
+vector.extend(item for item in path)
+
+robot = tsid.RobotWrapper(urdf, vector, False) # Load with fixed base
+
+# for viewer
+robot_display = pin.RobotWrapper.BuildFromURDF(urdf, [path])
+robot_display.initViewer(loadModel=True)
+
+model = robot.model()
+q = np.zeros(robot.nq)
+v = np.zeros(robot.nv)
+
+viz = pin.visualize.MeshcatVisualizer(
+ robot_display.model,
+ robot_display.collision_model,
+ robot_display.visual_model,
+)
+viz.initViewer(loadModel=True, open=True)
+
+t = 0.0 # time
+invdyn = tsid.InverseDynamicsFormulationAccForce("tsid", robot, False)
+invdyn.computeProblemData(t, q, v)
+data = invdyn.data()
+
+
+fingertip_name = "gripper_left_fingertip_3_link"
+H_fingertip_ref = robot.framePosition(invdyn.data(), model.getFrameId(fingertip_name))
+
+fingertipPositionTask = tsid.TaskSE3Equality(
+ "task-fingertip-position", robot, fingertip_name
+)
+fingertipPositionTask.useLocalFrame(False)
+fingertipPositionTask.setKp(kp_ee * np.ones(6))
+fingertipPositionTask.setKd(2.0 * np.sqrt(kp_ee) * np.ones(6))
+trajFingertipPosition = tsid.TrajectorySE3Constant(
+ "traj-fingertip-position", H_fingertip_ref
+)
+sampleFingertipPosition = trajFingertipPosition.computeNext()
+fingertipPositionTask.setReference(sampleFingertipPosition)
+invdyn.addMotionTask(fingertipPositionTask, w_ee, 1, 0.0)
+
+postureTask = tsid.TaskJointPosture("task-posture", robot)
+postureTask.setKp(kp_posture * np.ones(robot.nv))
+postureTask.setKd(2.0 * np.sqrt(kp_posture) * np.ones(robot.nv))
+invdyn.addMotionTask(postureTask, w_posture, 1, 0.0)
+
+
+# Creating a closed kinematic chain in TSID formulation by creating a contact between two frames, for which there are special links in URDF
+ContactTwoFramePositionsFingertipBottomAxis = tsid.ContactTwoFramePositions(
+ "contact-two-frame-positions-fingertip-bottom-axis",
+ robot,
+ "gripper_left_motor_single_link_ckc_axis",
+ "gripper_left_fingertip_3_link_ckc_axis",
+ -1000,
+ 1000,
+)
+twoFramesContact_Kp = 300
+ContactTwoFramePositionsFingertipBottomAxis.setKp(twoFramesContact_Kp * np.ones(3))
+ContactTwoFramePositionsFingertipBottomAxis.setKd(
+ 2.0 * np.sqrt(twoFramesContact_Kp) * np.ones(3)
+)
+
+twoFramesContact_w_forceRef = 1e-5
+invdyn.addRigidContact(
+ ContactTwoFramePositionsFingertipBottomAxis, twoFramesContact_w_forceRef, 1.0, 1
+)
+
+# Setting actuation to zero for passive joints in kinematic chain via TaskActuationBounds
+tau_max = model.effortLimit[-robot.na :]
+tau_max[
+ 0
+] = 0.0 # setting gripper_left_inner_single_joint to passive contstrainig it's actuation bounds to zero
+tau_max[
+ 1
+] = 0.0 # setting gripper_left_fingertip_3_joint to passive contstrainig it's actuation bounds to zero
+tau_min = -tau_max
+actuationBoundsTask = tsid.TaskActuationBounds("task-actuation-bounds", robot)
+actuationBoundsTask.setBounds(tau_min, tau_max)
+invdyn.addActuationTask(actuationBoundsTask, 1.0, 0, 0.0)
+
+q_ref = q
+trajPosture = tsid.TrajectoryEuclidianConstant("traj_joint", q_ref)
+
+print(
+ "Create QP solver with ",
+ invdyn.nVar,
+ " variables, ",
+ invdyn.nEq,
+ " equality and ",
+ invdyn.nIn,
+ " inequality constraints",
+)
+solver = tsid.SolverHQuadProgFast("qp solver")
+solver.resize(invdyn.nVar, invdyn.nEq, invdyn.nIn)
+
+offset = sampleFingertipPosition.pos()
+offset[:3] += np.array([0, -0.04, 0])
+amp = np.array([0.0, 0.04, 0.0])
+two_pi_f = 2 * np.pi * np.array([0.0, 0.5, 0.0])
+two_pi_f_amp = np.multiply(two_pi_f, amp)
+two_pi_f_squared_amp = np.multiply(two_pi_f, two_pi_f_amp)
+
+pEE = offset.copy()
+vEE = np.zeros(6)
+aEE = np.zeros(6)
+
+i = 0
+while True:
+ time_start = time.time()
+
+ # Setting gripper finger task target to sine motion
+ pEE[:3] = offset[:3] + amp * np.sin(two_pi_f * t)
+ vEE[:3] = two_pi_f_amp * np.cos(two_pi_f * t)
+ aEE[:3] = -two_pi_f_squared_amp * np.sin(two_pi_f * t)
+ sampleFingertipPosition.value(pEE)
+ sampleFingertipPosition.derivative(vEE)
+ sampleFingertipPosition.second_derivative(aEE)
+
+ fingertipPositionTask.setReference(sampleFingertipPosition)
+
+ samplePosture = trajPosture.computeNext()
+ postureTask.setReference(samplePosture)
+
+ # Computing HQP
+ HQPData = invdyn.computeProblemData(t, q, v)
+ if i == 0:
+ HQPData.print_all()
+
+ sol = solver.solve(HQPData)
+ if sol.status != 0:
+ print("[%d] QP problem could not be solved! Error code:" % (i), sol.status)
+ break
+
+ tau = invdyn.getActuatorForces(sol)
+ dv = invdyn.getAccelerations(sol)
+
+ if i % PRINT_N == 0:
+ print("Time %.3f" % (t))
+
+ v_mean = v + 0.5 * dt * dv
+ v += dt * dv
+ q = pin.integrate(robot.model(), q, dt * v_mean)
+ t += dt
+
+ if i % DISPLAY_N == 0:
+ viz.display(q)
+
+ time_spent = time.time() - time_start
+ if time_spent < dt:
+ time.sleep(dt - time_spent)
+
+ i = i + 1
diff --git a/exercizes/ex_0_ur5_joint_space_control.py b/exercizes/ex_0_ur5_joint_space_control.py
index 290e60f7..bee28a8e 100644
--- a/exercizes/ex_0_ur5_joint_space_control.py
+++ b/exercizes/ex_0_ur5_joint_space_control.py
@@ -7,12 +7,11 @@
import numpy as np
import pinocchio as pin
import plot_utils as plut
+import tsid
import ur5_conf as conf
from numpy import nan
from numpy.linalg import norm as norm
-import tsid
-
print("".center(conf.LINE_WIDTH, "#"))
print(" Joint Space Inverse Dynamics - Manipulator ".center(conf.LINE_WIDTH, "#"))
print("".center(conf.LINE_WIDTH, "#"), "\n")
diff --git a/exercizes/ex_4_walking.py b/exercizes/ex_4_walking.py
index fceec37c..18d0120c 100644
--- a/exercizes/ex_4_walking.py
+++ b/exercizes/ex_4_walking.py
@@ -4,12 +4,11 @@
import matplotlib.pyplot as plt
import numpy as np
import plot_utils as plut
+import tsid
from numpy import nan
from numpy.linalg import norm as norm
from tsid_biped import TsidBiped
-import tsid
-
print("".center(conf.LINE_WIDTH, "#"))
print(" Test Walking ".center(conf.LINE_WIDTH, "#"))
print("".center(conf.LINE_WIDTH, "#"), "\n")
diff --git a/exercizes/notebooks/Installation process.ipynb b/exercizes/notebooks/Installation process.ipynb
index de8bd7cc..0923bcf9 100644
--- a/exercizes/notebooks/Installation process.ipynb
+++ b/exercizes/notebooks/Installation process.ipynb
@@ -1,5 +1,5 @@
{
- "cells": [
+ "cells": [
{
"cell_type": "markdown",
"metadata": {},
diff --git a/exercizes/notebooks/ex_0_joint_space_inverse_dynamics_arm.ipynb b/exercizes/notebooks/ex_0_joint_space_inverse_dynamics_arm.ipynb
index 1e1642e7..04eee69d 100644
--- a/exercizes/notebooks/ex_0_joint_space_inverse_dynamics_arm.ipynb
+++ b/exercizes/notebooks/ex_0_joint_space_inverse_dynamics_arm.ipynb
@@ -1,5 +1,5 @@
{
- "cells": [
+ "cells": [
{
"cell_type": "markdown",
"metadata": {},
diff --git a/exercizes/notebooks/ex_1_com_sin_track_talos.ipynb b/exercizes/notebooks/ex_1_com_sin_track_talos.ipynb
index a5e1f8c4..1d707a61 100644
--- a/exercizes/notebooks/ex_1_com_sin_track_talos.ipynb
+++ b/exercizes/notebooks/ex_1_com_sin_track_talos.ipynb
@@ -1,5 +1,5 @@
{
- "cells": [
+ "cells": [
{
"cell_type": "markdown",
"metadata": {},
diff --git a/exercizes/notebooks/ex_3_biped_balance_with_gui.ipynb b/exercizes/notebooks/ex_3_biped_balance_with_gui.ipynb
index f6db703c..c63fad6d 100644
--- a/exercizes/notebooks/ex_3_biped_balance_with_gui.ipynb
+++ b/exercizes/notebooks/ex_3_biped_balance_with_gui.ipynb
@@ -1,5 +1,5 @@
{
- "cells": [
+ "cells": [
{
"cell_type": "code",
"execution_count": null,
diff --git a/exercizes/tsid_biped.py b/exercizes/tsid_biped.py
index d63d25ae..58a229c6 100644
--- a/exercizes/tsid_biped.py
+++ b/exercizes/tsid_biped.py
@@ -4,7 +4,6 @@
import numpy as np
import pinocchio as pin
-
import tsid
diff --git a/exercizes/tsid_manipulator.py b/exercizes/tsid_manipulator.py
index 93a7bc83..c8001270 100644
--- a/exercizes/tsid_manipulator.py
+++ b/exercizes/tsid_manipulator.py
@@ -6,7 +6,6 @@
import numpy as np
import numpy.matlib as matlib
import pinocchio as se3
-
import tsid
diff --git a/include/tsid/bindings/python/contacts/contact-two-frame-positions.hpp b/include/tsid/bindings/python/contacts/contact-two-frame-positions.hpp
new file mode 100644
index 00000000..f7de1315
--- /dev/null
+++ b/include/tsid/bindings/python/contacts/contact-two-frame-positions.hpp
@@ -0,0 +1,204 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#ifndef __tsid_python_contact_two_frame_positions_hpp__
+#define __tsid_python_contact_two_frame_positions_hpp__
+
+#include "tsid/bindings/python/fwd.hpp"
+
+#include "tsid/contacts/contact-two-frame-positions.hpp"
+#include "tsid/robots/robot-wrapper.hpp"
+#include "tsid/math/constraint-inequality.hpp"
+#include "tsid/math/constraint-equality.hpp"
+#include "tsid/math/constraint-base.hpp"
+
+namespace tsid {
+namespace python {
+namespace bp = boost::python;
+
+template
+struct ContactTwoFramePositionsPythonVisitor
+ : public boost::python::def_visitor<
+ ContactTwoFramePositionsPythonVisitor > {
+ template
+
+ void visit(PyClass& cl) const {
+ cl
+ .def(bp::init(
+ (bp::arg("name"), bp::arg("robot"), bp::arg("framename1"),
+ bp::arg("framename2"), bp::arg("minForce"), bp::arg("maxForce")),
+ "Default Constructor"))
+ .add_property("n_motion", &ContactTwoFramePositions::n_motion,
+ "return number of motion")
+ .add_property("n_force", &ContactTwoFramePositions::n_force,
+ "return number of force")
+ .add_property("name", &ContactTwoFramePositionsPythonVisitor::name,
+ "return name")
+ .def("computeMotionTask",
+ &ContactTwoFramePositionsPythonVisitor::computeMotionTask,
+ bp::args("t", "q", "v", "data"))
+ .def("computeForceTask",
+ &ContactTwoFramePositionsPythonVisitor::computeForceTask,
+ bp::args("t", "q", "v", "data"))
+ .def("computeForceRegularizationTask",
+ &ContactTwoFramePositionsPythonVisitor::
+ computeForceRegularizationTask,
+ bp::args("t", "q", "v", "data"))
+
+ .add_property(
+ "getForceGeneratorMatrix",
+ bp::make_function(
+ &ContactTwoFramePositionsPythonVisitor::getForceGeneratorMatrix,
+ bp::return_value_policy()))
+
+ .def("getNormalForce",
+ &ContactTwoFramePositionsPythonVisitor::getNormalForce,
+ bp::arg("vec"))
+ .add_property("getMinNormalForce",
+ &ContactTwoFramePositions::getMinNormalForce)
+ .add_property("getMaxNormalForce",
+ &ContactTwoFramePositions::getMaxNormalForce)
+
+ .add_property("Kp",
+ bp::make_function(
+ &ContactTwoFramePositionsPythonVisitor::Kp,
+ bp::return_value_policy()))
+ .add_property("Kd",
+ bp::make_function(
+ &ContactTwoFramePositionsPythonVisitor::Kd,
+ bp::return_value_policy()))
+ .def("setKp", &ContactTwoFramePositionsPythonVisitor::setKp,
+ bp::arg("Kp"))
+ .def("setKd", &ContactTwoFramePositionsPythonVisitor::setKd,
+ bp::arg("Kd"))
+ .def("setContactNormal",
+ &ContactTwoFramePositionsPythonVisitor::setContactNormal,
+ bp::args("vec"))
+ .def("setFrictionCoefficient",
+ &ContactTwoFramePositionsPythonVisitor::setFrictionCoefficient,
+ bp::args("friction_coeff"))
+ .def("setMinNormalForce",
+ &ContactTwoFramePositionsPythonVisitor::setMinNormalForce,
+ bp::args("min_force"))
+ .def("setMaxNormalForce",
+ &ContactTwoFramePositionsPythonVisitor::setMaxNormalForce,
+ bp::args("max_force"))
+ .def("setForceReference",
+ &ContactTwoFramePositionsPythonVisitor::setForceReference,
+ bp::args("f_vec"))
+ .def("setRegularizationTaskWeightVector",
+ &ContactTwoFramePositionsPythonVisitor::
+ setRegularizationTaskWeightVector,
+ bp::args("w_vec"));
+ }
+ static std::string name(ContactTwoFramePositions& self) {
+ std::string name = self.name();
+ return name;
+ }
+
+ static math::ConstraintEquality computeMotionTask(
+ ContactTwoFramePositions& self, const double t, const Eigen::VectorXd& q,
+ const Eigen::VectorXd& v, pinocchio::Data& data) {
+ self.computeMotionTask(t, q, v, data);
+ math::ConstraintEquality cons(self.getMotionConstraint().name(),
+ self.getMotionConstraint().matrix(),
+ self.getMotionConstraint().vector());
+ return cons;
+ }
+ static math::ConstraintInequality computeForceTask(
+ ContactTwoFramePositions& self, const double t, const Eigen::VectorXd& q,
+ const Eigen::VectorXd& v, const pinocchio::Data& data) {
+ self.computeForceTask(t, q, v, data);
+ math::ConstraintInequality cons(self.getForceConstraint().name(),
+ self.getForceConstraint().matrix(),
+ self.getForceConstraint().lowerBound(),
+ self.getForceConstraint().upperBound());
+ return cons;
+ }
+ static math::ConstraintEquality computeForceRegularizationTask(
+ ContactTwoFramePositions& self, const double t, const Eigen::VectorXd& q,
+ const Eigen::VectorXd& v, const pinocchio::Data& data) {
+ self.computeForceRegularizationTask(t, q, v, data);
+ math::ConstraintEquality cons(self.getForceRegularizationTask().name(),
+ self.getForceRegularizationTask().matrix(),
+ self.getForceRegularizationTask().vector());
+ return cons;
+ }
+
+ static const Eigen::MatrixXd& getForceGeneratorMatrix(
+ ContactTwoFramePositions& self) {
+ return self.getForceGeneratorMatrix();
+ }
+ static const Eigen::VectorXd& Kp(ContactTwoFramePositions& self) {
+ return self.Kp();
+ }
+ static const Eigen::VectorXd& Kd(ContactTwoFramePositions& self) {
+ return self.Kd();
+ }
+ static void setKp(ContactTwoFramePositions& self,
+ const ::Eigen::VectorXd Kp) {
+ return self.Kp(Kp);
+ }
+ static void setKd(ContactTwoFramePositions& self,
+ const ::Eigen::VectorXd Kd) {
+ return self.Kd(Kd);
+ }
+ static bool setContactTwoFramePositionss(
+ ContactTwoFramePositions& self,
+ const ::Eigen::MatrixXd ContactTwoFramePositionss) {
+ return self.setContactTwoFramePositionss(ContactTwoFramePositionss);
+ }
+ static bool setContactNormal(ContactTwoFramePositions& self,
+ const ::Eigen::VectorXd contactNormal) {
+ return self.setContactNormal(contactNormal);
+ }
+ static bool setFrictionCoefficient(ContactTwoFramePositions& self,
+ const double frictionCoefficient) {
+ return self.setFrictionCoefficient(frictionCoefficient);
+ }
+ static bool setMinNormalForce(ContactTwoFramePositions& self,
+ const double minNormalForce) {
+ return self.setMinNormalForce(minNormalForce);
+ }
+ static bool setMaxNormalForce(ContactTwoFramePositions& self,
+ const double maxNormalForce) {
+ return self.setMaxNormalForce(maxNormalForce);
+ }
+ static void setForceReference(ContactTwoFramePositions& self,
+ const ::Eigen::VectorXd f_ref) {
+ self.setForceReference(f_ref);
+ }
+ static void setRegularizationTaskWeightVector(ContactTwoFramePositions& self,
+ const ::Eigen::VectorXd w) {
+ self.setRegularizationTaskWeightVector(w);
+ }
+ static double getNormalForce(ContactTwoFramePositions& self,
+ Eigen::VectorXd f) {
+ return self.getNormalForce(f);
+ }
+ static void expose(const std::string& class_name) {
+ std::string doc = "ContactTwoFramePositions info.";
+ bp::class_(class_name.c_str(), doc.c_str(),
+ bp::no_init)
+ .def(ContactTwoFramePositionsPythonVisitor());
+ }
+};
+} // namespace python
+} // namespace tsid
+
+#endif // ifndef __tsid_python_contact_two_frame_positions_hpp__
diff --git a/include/tsid/bindings/python/contacts/contact-two-frames.hpp b/include/tsid/bindings/python/contacts/contact-two-frames.hpp
new file mode 100644
index 00000000..7889efb7
--- /dev/null
+++ b/include/tsid/bindings/python/contacts/contact-two-frames.hpp
@@ -0,0 +1,202 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#ifndef __tsid_python_contact_two_frames_hpp__
+#define __tsid_python_contact_two_frames_hpp__
+
+#include "tsid/bindings/python/fwd.hpp"
+
+#include "tsid/contacts/contact-two-frames.hpp"
+#include "tsid/robots/robot-wrapper.hpp"
+#include "tsid/math/constraint-inequality.hpp"
+#include "tsid/math/constraint-equality.hpp"
+#include "tsid/math/constraint-base.hpp"
+
+namespace tsid {
+namespace python {
+namespace bp = boost::python;
+
+template
+struct ContactTwoFramesPythonVisitor
+ : public boost::python::def_visitor<
+ ContactTwoFramesPythonVisitor > {
+ template
+
+ void visit(PyClass& cl) const {
+ cl
+ .def(bp::init(
+ (bp::arg("name"), bp::arg("robot"), bp::arg("framename1"),
+ bp::arg("framename2"), bp::arg("minForce"), bp::arg("maxForce")),
+ "Default Constructor"))
+ .add_property("n_motion", &ContactTwoFrames::n_motion,
+ "return number of motion")
+ .add_property("n_force", &ContactTwoFrames::n_force,
+ "return number of force")
+ .add_property("name", &ContactTwoFramesPythonVisitor::name,
+ "return name")
+ .def("computeMotionTask",
+ &ContactTwoFramesPythonVisitor::computeMotionTask,
+ bp::args("t", "q", "v", "data"))
+ .def("computeForceTask",
+ &ContactTwoFramesPythonVisitor::computeForceTask,
+ bp::args("t", "q", "v", "data"))
+ .def("computeForceRegularizationTask",
+ &ContactTwoFramesPythonVisitor::computeForceRegularizationTask,
+ bp::args("t", "q", "v", "data"))
+
+ .add_property(
+ "getForceGeneratorMatrix",
+ bp::make_function(
+ &ContactTwoFramesPythonVisitor::getForceGeneratorMatrix,
+ bp::return_value_policy()))
+
+ .def("getNormalForce", &ContactTwoFramesPythonVisitor::getNormalForce,
+ bp::arg("vec"))
+ .add_property("getMinNormalForce", &ContactTwoFrames::getMinNormalForce)
+ .add_property("getMaxNormalForce", &ContactTwoFrames::getMaxNormalForce)
+
+ .add_property("Kp",
+ bp::make_function(
+ &ContactTwoFramesPythonVisitor::Kp,
+ bp::return_value_policy()))
+ .add_property("Kd",
+ bp::make_function(
+ &ContactTwoFramesPythonVisitor::Kd,
+ bp::return_value_policy()))
+ .def("setKp", &ContactTwoFramesPythonVisitor::setKp, bp::arg("Kp"))
+ .def("setKd", &ContactTwoFramesPythonVisitor::setKd, bp::arg("Kd"))
+
+ .def("useLocalFrame", &ContactTwoFramesPythonVisitor::useLocalFrame,
+ bp::arg("local_frame"))
+
+ .def("setContactNormal",
+ &ContactTwoFramesPythonVisitor::setContactNormal, bp::args("vec"))
+ .def("setFrictionCoefficient",
+ &ContactTwoFramesPythonVisitor::setFrictionCoefficient,
+ bp::args("friction_coeff"))
+ .def("setMinNormalForce",
+ &ContactTwoFramesPythonVisitor::setMinNormalForce,
+ bp::args("min_force"))
+ .def("setMaxNormalForce",
+ &ContactTwoFramesPythonVisitor::setMaxNormalForce,
+ bp::args("max_force"))
+ .def("setReference", &ContactTwoFramesPythonVisitor::setReference,
+ bp::args("SE3"))
+ .def("setForceReference",
+ &ContactTwoFramesPythonVisitor::setForceReference,
+ bp::args("f_vec"))
+ .def("setRegularizationTaskWeightVector",
+ &ContactTwoFramesPythonVisitor::setRegularizationTaskWeightVector,
+ bp::args("w_vec"));
+ }
+ static std::string name(ContactTwoFrames& self) {
+ std::string name = self.name();
+ return name;
+ }
+
+ static math::ConstraintEquality computeMotionTask(ContactTwoFrames& self,
+ const double t,
+ const Eigen::VectorXd& q,
+ const Eigen::VectorXd& v,
+ pinocchio::Data& data) {
+ self.computeMotionTask(t, q, v, data);
+ math::ConstraintEquality cons(self.getMotionConstraint().name(),
+ self.getMotionConstraint().matrix(),
+ self.getMotionConstraint().vector());
+ return cons;
+ }
+ static math::ConstraintInequality computeForceTask(
+ ContactTwoFrames& self, const double t, const Eigen::VectorXd& q,
+ const Eigen::VectorXd& v, const pinocchio::Data& data) {
+ self.computeForceTask(t, q, v, data);
+ math::ConstraintInequality cons(self.getForceConstraint().name(),
+ self.getForceConstraint().matrix(),
+ self.getForceConstraint().lowerBound(),
+ self.getForceConstraint().upperBound());
+ return cons;
+ }
+ static math::ConstraintEquality computeForceRegularizationTask(
+ ContactTwoFrames& self, const double t, const Eigen::VectorXd& q,
+ const Eigen::VectorXd& v, const pinocchio::Data& data) {
+ self.computeForceRegularizationTask(t, q, v, data);
+ math::ConstraintEquality cons(self.getForceRegularizationTask().name(),
+ self.getForceRegularizationTask().matrix(),
+ self.getForceRegularizationTask().vector());
+ return cons;
+ }
+
+ static void useLocalFrame(ContactTwoFrames& self, const bool local_frame) {
+ self.useLocalFrame(local_frame);
+ }
+ static const Eigen::MatrixXd& getForceGeneratorMatrix(
+ ContactTwoFrames& self) {
+ return self.getForceGeneratorMatrix();
+ }
+ static const Eigen::VectorXd& Kp(ContactTwoFrames& self) { return self.Kp(); }
+ static const Eigen::VectorXd& Kd(ContactTwoFrames& self) { return self.Kd(); }
+ static void setKp(ContactTwoFrames& self, const ::Eigen::VectorXd Kp) {
+ return self.Kp(Kp);
+ }
+ static void setKd(ContactTwoFrames& self, const ::Eigen::VectorXd Kd) {
+ return self.Kd(Kd);
+ }
+ static bool setContactTwoFramess(ContactTwoFrames& self,
+ const ::Eigen::MatrixXd ContactTwoFramess) {
+ return self.setContactTwoFramess(ContactTwoFramess);
+ }
+ static bool setContactNormal(ContactTwoFrames& self,
+ const ::Eigen::VectorXd contactNormal) {
+ return self.setContactNormal(contactNormal);
+ }
+ static bool setFrictionCoefficient(ContactTwoFrames& self,
+ const double frictionCoefficient) {
+ return self.setFrictionCoefficient(frictionCoefficient);
+ }
+ static bool setMinNormalForce(ContactTwoFrames& self,
+ const double minNormalForce) {
+ return self.setMinNormalForce(minNormalForce);
+ }
+ static bool setMaxNormalForce(ContactTwoFrames& self,
+ const double maxNormalForce) {
+ return self.setMaxNormalForce(maxNormalForce);
+ }
+ static void setReference(ContactTwoFrames& self, const pinocchio::SE3& ref) {
+ self.setReference(ref);
+ }
+ static void setForceReference(ContactTwoFrames& self,
+ const ::Eigen::VectorXd f_ref) {
+ self.setForceReference(f_ref);
+ }
+ static void setRegularizationTaskWeightVector(ContactTwoFrames& self,
+ const ::Eigen::VectorXd w) {
+ self.setRegularizationTaskWeightVector(w);
+ }
+ static double getNormalForce(ContactTwoFrames& self, Eigen::VectorXd f) {
+ return self.getNormalForce(f);
+ }
+
+ static void expose(const std::string& class_name) {
+ std::string doc = "ContactTwoFrames info.";
+ bp::class_(class_name.c_str(), doc.c_str(), bp::no_init)
+ .def(ContactTwoFramesPythonVisitor());
+ }
+};
+} // namespace python
+} // namespace tsid
+
+#endif // ifndef __tsid_python_contact_two_frames_hpp__
diff --git a/include/tsid/bindings/python/contacts/expose-contact.hpp b/include/tsid/bindings/python/contacts/expose-contact.hpp
index 0db77646..01efac41 100644
--- a/include/tsid/bindings/python/contacts/expose-contact.hpp
+++ b/include/tsid/bindings/python/contacts/expose-contact.hpp
@@ -20,15 +20,18 @@
#include "tsid/bindings/python/contacts/contact-6d.hpp"
#include "tsid/bindings/python/contacts/contact-point.hpp"
+#include "tsid/bindings/python/contacts/contact-two-frame-positions.hpp"
namespace tsid {
namespace python {
void exposeContact6d();
void exposeContactPoint();
+void exposeContactTwoFramePositions();
inline void exposeContact() {
exposeContact6d();
exposeContactPoint();
+ exposeContactTwoFramePositions();
}
} // namespace python
diff --git a/include/tsid/bindings/python/formulations/formulation.hpp b/include/tsid/bindings/python/formulations/formulation.hpp
index a0992329..59652bfa 100644
--- a/include/tsid/bindings/python/formulations/formulation.hpp
+++ b/include/tsid/bindings/python/formulations/formulation.hpp
@@ -26,6 +26,7 @@
#include "tsid/bindings/python/solvers/HQPData.hpp"
#include "tsid/contacts/contact-6d.hpp"
#include "tsid/contacts/contact-point.hpp"
+#include "tsid/contacts/contact-two-frame-positions.hpp"
#include "tsid/tasks/task-joint-posture.hpp"
#include "tsid/tasks/task-se3-equality.hpp"
#include "tsid/tasks/task-com-equality.hpp"
@@ -34,6 +35,7 @@
#include "tsid/tasks/task-joint-bounds.hpp"
#include "tsid/tasks/task-joint-posVelAcc-bounds.hpp"
#include "tsid/tasks/task-angular-momentum-equality.hpp"
+#include "tsid/tasks/task-two-frames-equality.hpp"
namespace tsid {
namespace python {
@@ -65,6 +67,9 @@ struct InvDynPythonVisitor
bp::args("task", "weight", "priorityLevel", "transition duration"))
.def("addMotionTask", &InvDynPythonVisitor::addMotionTask_AM,
bp::args("task", "weight", "priorityLevel", "transition duration"))
+ .def("addMotionTask",
+ &InvDynPythonVisitor::addMotionTask_TwoFramesEquality,
+ bp::args("task", "weight", "priorityLevel", "transition duration"))
.def("addForceTask", &InvDynPythonVisitor::addForceTask_COP,
bp::args("task", "weight", "priorityLevel", "transition duration"))
.def("addActuationTask", &InvDynPythonVisitor::addActuationTask_Bounds,
@@ -96,6 +101,14 @@ struct InvDynPythonVisitor
&InvDynPythonVisitor::addRigidContactPointWithPriorityLevel,
bp::args("contact", "force_reg_weight", "motion_weight",
"priority_level"))
+ .def("addRigidContact",
+ &InvDynPythonVisitor::addRigidContactTwoFramePositions,
+ bp::args("contact", "force_reg_weight"))
+ .def("addRigidContact",
+ &InvDynPythonVisitor::
+ addRigidContactTwoFramePositionsWithPriorityLevel,
+ bp::args("contact", "force_reg_weight", "motion_weight",
+ "priority_level"))
.def("removeTask", &InvDynPythonVisitor::removeTask,
bp::args("task_name", "duration"))
.def("removeRigidContact", &InvDynPythonVisitor::removeRigidContact,
@@ -151,6 +164,11 @@ struct InvDynPythonVisitor
double transition_duration) {
return self.addMotionTask(task, weight, priorityLevel, transition_duration);
}
+ static bool addMotionTask_TwoFramesEquality(
+ T& self, tasks::TaskTwoFramesEquality& task, double weight,
+ unsigned int priorityLevel, double transition_duration) {
+ return self.addMotionTask(task, weight, priorityLevel, transition_duration);
+ }
static bool addForceTask_COP(T& self, tasks::TaskCopEquality& task,
double weight, unsigned int priorityLevel,
double transition_duration) {
@@ -203,6 +221,18 @@ struct InvDynPythonVisitor
return self.addRigidContact(contact, force_regularization_weight,
motion_weight, priority_level);
}
+ static bool addRigidContactTwoFramePositions(
+ T& self, contacts::ContactTwoFramePositions& contact,
+ double force_regularization_weight) {
+ return self.addRigidContact(contact, force_regularization_weight);
+ }
+ static bool addRigidContactTwoFramePositionsWithPriorityLevel(
+ T& self, contacts::ContactTwoFramePositions& contact,
+ double force_regularization_weight, double motion_weight,
+ const bool priority_level) {
+ return self.addRigidContact(contact, force_regularization_weight,
+ motion_weight, priority_level);
+ }
static bool removeTask(T& self, const std::string& task_name,
double transition_duration) {
return self.removeTask(task_name, transition_duration);
diff --git a/include/tsid/bindings/python/tasks/expose-tasks.hpp b/include/tsid/bindings/python/tasks/expose-tasks.hpp
index ebcd4176..ae2a67fe 100644
--- a/include/tsid/bindings/python/tasks/expose-tasks.hpp
+++ b/include/tsid/bindings/python/tasks/expose-tasks.hpp
@@ -26,6 +26,7 @@
#include "tsid/bindings/python/tasks/task-joint-bounds.hpp"
#include "tsid/bindings/python/tasks/task-joint-posVelAcc-bounds.hpp"
#include "tsid/bindings/python/tasks/task-am-equality.hpp"
+#include "tsid/bindings/python/tasks/task-two-frames-equality.hpp"
namespace tsid {
namespace python {
@@ -37,6 +38,7 @@ void exposeTaskActuationBounds();
void exposeTaskJointBounds();
void exposeTaskJointPosVelAccBounds();
void exposeTaskAMEquality();
+void exposeTaskTwoFramesEquality();
inline void exposeTasks() {
exposeTaskComEquality();
@@ -47,6 +49,7 @@ inline void exposeTasks() {
exposeTaskJointBounds();
exposeTaskJointPosVelAccBounds();
exposeTaskAMEquality();
+ exposeTaskTwoFramesEquality();
}
} // namespace python
diff --git a/include/tsid/bindings/python/tasks/task-two-frames-equality.hpp b/include/tsid/bindings/python/tasks/task-two-frames-equality.hpp
new file mode 100644
index 00000000..fdcef4b8
--- /dev/null
+++ b/include/tsid/bindings/python/tasks/task-two-frames-equality.hpp
@@ -0,0 +1,149 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#ifndef __tsid_python_task_frames_hpp__
+#define __tsid_python_task_frames_hpp__
+
+#include "tsid/bindings/python/fwd.hpp"
+
+#include "tsid/tasks/task-two-frames-equality.hpp"
+#include "tsid/robots/robot-wrapper.hpp"
+#include "tsid/trajectories/trajectory-base.hpp"
+#include "tsid/math/constraint-equality.hpp"
+#include "tsid/math/constraint-base.hpp"
+namespace tsid {
+namespace python {
+namespace bp = boost::python;
+
+template
+struct TaskTwoFramesEqualityPythonVisitor
+ : public boost::python::def_visitor<
+ TaskTwoFramesEqualityPythonVisitor > {
+ template
+
+ void visit(PyClass& cl) const {
+ cl.def(bp::init((bp::arg("name"), bp::arg("robot"),
+ bp::arg("framename1"), bp::arg("framename2")),
+ "Default Constructor"))
+ .add_property("dim", &TaskFrames::dim, "return dimension size")
+ .add_property(
+ "getDesiredAcceleration",
+ bp::make_function(
+ &TaskTwoFramesEqualityPythonVisitor::getDesiredAcceleration,
+ bp::return_value_policy()),
+ "Return Acc_desired")
+ .def("getAcceleration",
+ &TaskTwoFramesEqualityPythonVisitor::getAcceleration,
+ bp::arg("dv"))
+ .add_property("position_error",
+ bp::make_function(
+ &TaskTwoFramesEqualityPythonVisitor::position_error,
+ bp::return_value_policy()))
+ .add_property("velocity_error",
+ bp::make_function(
+ &TaskTwoFramesEqualityPythonVisitor::velocity_error,
+ bp::return_value_policy()))
+ .add_property("Kp",
+ bp::make_function(
+ &TaskTwoFramesEqualityPythonVisitor::Kp,
+ bp::return_value_policy()))
+ .add_property("Kd",
+ bp::make_function(
+ &TaskTwoFramesEqualityPythonVisitor::Kd,
+ bp::return_value_policy()))
+ .def("setKp", &TaskTwoFramesEqualityPythonVisitor::setKp, bp::arg("Kp"))
+ .def("setKd", &TaskTwoFramesEqualityPythonVisitor::setKd, bp::arg("Kd"))
+ .add_property("mask",
+ bp::make_function(
+ &TaskTwoFramesEqualityPythonVisitor::getMask,
+ bp::return_value_policy()),
+ "Return mask")
+ .def("setMask", &TaskTwoFramesEqualityPythonVisitor::setMask,
+ bp::arg("mask"))
+ .def("compute", &TaskTwoFramesEqualityPythonVisitor::compute,
+ bp::args("t", "q", "v", "data"))
+ .def("getConstraint",
+ &TaskTwoFramesEqualityPythonVisitor::getConstraint)
+ .add_property("frame_id1", &TaskFrames::frame_id1, "frame id 1 return")
+ .add_property("frame_id2", &TaskFrames::frame_id2, "frame id 2 return")
+ .add_property("name", &TaskTwoFramesEqualityPythonVisitor::name);
+ }
+ static std::string name(TaskFrames& self) {
+ std::string name = self.name();
+ return name;
+ }
+ static math::ConstraintEquality compute(TaskFrames& self, const double t,
+ const Eigen::VectorXd& q,
+ const Eigen::VectorXd& v,
+ pinocchio::Data& data) {
+ self.compute(t, q, v, data);
+ math::ConstraintEquality cons(self.getConstraint().name(),
+ self.getConstraint().matrix(),
+ self.getConstraint().vector());
+ return cons;
+ }
+ static math::ConstraintEquality getConstraint(const TaskFrames& self) {
+ math::ConstraintEquality cons(self.getConstraint().name(),
+ self.getConstraint().matrix(),
+ self.getConstraint().vector());
+ return cons;
+ }
+ static const Eigen::VectorXd& getDesiredAcceleration(const TaskFrames& self) {
+ return self.getDesiredAcceleration();
+ }
+ static Eigen::VectorXd getAcceleration(TaskFrames& self,
+ const Eigen::VectorXd dv) {
+ return self.getAcceleration(dv);
+ }
+ static const Eigen::VectorXd& position_error(const TaskFrames& self) {
+ return self.position_error();
+ }
+ static const Eigen::VectorXd& velocity_error(const TaskFrames& self) {
+ return self.velocity_error();
+ }
+ static const Eigen::VectorXd& Kp(TaskFrames& self) { return self.Kp(); }
+ static const Eigen::VectorXd& Kd(TaskFrames& self) { return self.Kd(); }
+ static void setKp(TaskFrames& self, const ::Eigen::VectorXd Kp) {
+ return self.Kp(Kp);
+ }
+ static void setKd(TaskFrames& self, const ::Eigen::VectorXd Kv) {
+ return self.Kd(Kv);
+ }
+ static void getMask(TaskFrames& self) { self.getMask(); }
+ static void setMask(TaskFrames& self, const ::Eigen::VectorXd mask) {
+ self.setMask(mask);
+ }
+ static Eigen::VectorXd frame_id1(TaskFrames& self) {
+ return self.frame_id1();
+ }
+ static Eigen::VectorXd frame_id2(TaskFrames& self) {
+ return self.frame_id2();
+ }
+
+ static void expose(const std::string& class_name) {
+ std::string doc = "TaskFrames info.";
+ bp::class_(class_name.c_str(), doc.c_str(), bp::no_init)
+ .def(TaskTwoFramesEqualityPythonVisitor());
+
+ // bp::register_ptr_to_python< boost::shared_ptr >();
+ }
+};
+} // namespace python
+} // namespace tsid
+
+#endif // ifndef __tsid_python_task_frames_hpp__
diff --git a/include/tsid/contacts/contact-base.hpp b/include/tsid/contacts/contact-base.hpp
index f683ea7f..f1f887fd 100644
--- a/include/tsid/contacts/contact-base.hpp
+++ b/include/tsid/contacts/contact-base.hpp
@@ -39,6 +39,7 @@ class ContactBase {
typedef math::Matrix Matrix;
typedef math::Matrix3x Matrix3x;
typedef tasks::TaskSE3Equality TaskSE3Equality;
+ typedef tasks::TaskMotion TaskMotion;
typedef pinocchio::Data Data;
typedef robots::RobotWrapper RobotWrapper;
@@ -71,7 +72,7 @@ class ContactBase {
virtual const ConstraintEquality& computeForceRegularizationTask(
const double t, ConstRefVector q, ConstRefVector v, const Data& data) = 0;
- virtual const TaskSE3Equality& getMotionTask() const = 0;
+ virtual const TaskMotion& getMotionTask() const = 0;
virtual const ConstraintBase& getMotionConstraint() const = 0;
virtual const ConstraintInequality& getForceConstraint() const = 0;
virtual const ConstraintEquality& getForceRegularizationTask() const = 0;
diff --git a/include/tsid/contacts/contact-two-frame-positions.hpp b/include/tsid/contacts/contact-two-frame-positions.hpp
new file mode 100644
index 00000000..890ac5f5
--- /dev/null
+++ b/include/tsid/contacts/contact-two-frame-positions.hpp
@@ -0,0 +1,119 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#ifndef __invdyn_contact_two_frame_positions_hpp__
+#define __invdyn_contact_two_frame_positions_hpp__
+
+#include "tsid/contacts/contact-base.hpp"
+#include "tsid/tasks/task-se3-equality.hpp"
+#include "tsid/tasks/task-two-frames-equality.hpp"
+#include "tsid/math/constraint-inequality.hpp"
+#include "tsid/math/constraint-equality.hpp"
+
+namespace tsid {
+namespace contacts {
+class ContactTwoFramePositions : public ContactBase {
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ typedef math::ConstRefMatrix ConstRefMatrix;
+ typedef math::ConstRefVector ConstRefVector;
+ typedef math::Matrix3x Matrix3x;
+ typedef math::Vector6 Vector6;
+ typedef math::Vector3 Vector3;
+ typedef math::Vector Vector;
+ typedef tasks::TaskTwoFramesEquality TaskTwoFramesEquality;
+ typedef tasks::TaskSE3Equality TaskSE3Equality;
+ typedef math::ConstraintInequality ConstraintInequality;
+ typedef math::ConstraintEquality ConstraintEquality;
+ typedef pinocchio::SE3 SE3;
+
+ ContactTwoFramePositions(const std::string& name, RobotWrapper& robot,
+ const std::string& frameName1,
+ const std::string& frameName2,
+ const double minNormalForce,
+ const double maxNormalForce);
+
+ /// Return the number of motion constraints
+ virtual unsigned int n_motion() const;
+
+ /// Return the number of force variables
+ virtual unsigned int n_force() const;
+
+ virtual const ConstraintBase& computeMotionTask(const double t,
+ ConstRefVector q,
+ ConstRefVector v, Data& data);
+
+ virtual const ConstraintInequality& computeForceTask(const double t,
+ ConstRefVector q,
+ ConstRefVector v,
+ const Data& data);
+
+ virtual const Matrix& getForceGeneratorMatrix();
+
+ virtual const ConstraintEquality& computeForceRegularizationTask(
+ const double t, ConstRefVector q, ConstRefVector v, const Data& data);
+
+ const TaskTwoFramesEquality& getMotionTask() const;
+ const ConstraintBase& getMotionConstraint() const;
+ const ConstraintInequality& getForceConstraint() const;
+ const ConstraintEquality& getForceRegularizationTask() const;
+ double getMotionTaskWeight() const;
+ const Matrix3x& getContactPoints() const;
+
+ double getNormalForce(ConstRefVector f) const;
+ double getMinNormalForce() const;
+ double getMaxNormalForce() const;
+
+ const Vector&
+ Kp(); // cannot be const because it set a member variable inside
+ const Vector&
+ Kd(); // cannot be const because it set a member variable inside
+ void Kp(ConstRefVector Kp);
+ void Kd(ConstRefVector Kp);
+
+ bool setContactNormal(ConstRefVector contactNormal);
+
+ bool setFrictionCoefficient(const double frictionCoefficient);
+ bool setMinNormalForce(const double minNormalForce);
+ bool setMaxNormalForce(const double maxNormalForce);
+ bool setMotionTaskWeight(const double w);
+ void setForceReference(ConstRefVector& f_ref);
+ void setRegularizationTaskWeightVector(ConstRefVector& w);
+
+ protected:
+ void updateForceInequalityConstraints();
+ void updateForceRegularizationTask();
+ void updateForceGeneratorMatrix();
+
+ TaskTwoFramesEquality m_motionTask;
+ ConstraintInequality m_forceInequality;
+ ConstraintEquality m_forceRegTask;
+ Vector3 m_fRef;
+ Vector3 m_weightForceRegTask;
+ Matrix3x m_contactPoints;
+ Vector m_Kp3, m_Kd3; // gain vectors to be returned by reference
+ double m_fMin;
+ double m_fMax;
+ double m_regularizationTaskWeight;
+ double m_motionTaskWeight;
+ Matrix m_forceGenMat;
+};
+} // namespace contacts
+} // namespace tsid
+
+#endif // ifndef __invdyn_contact_two_frame_positions_hpp__
diff --git a/include/tsid/tasks/task-two-frames-equality.hpp b/include/tsid/tasks/task-two-frames-equality.hpp
new file mode 100644
index 00000000..696d7de5
--- /dev/null
+++ b/include/tsid/tasks/task-two-frames-equality.hpp
@@ -0,0 +1,123 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#ifndef __invdyn_task_frames_equality_hpp__
+#define __invdyn_task_frames_equality_hpp__
+
+#include "tsid/tasks/task-motion.hpp"
+#include "tsid/trajectories/trajectory-base.hpp"
+#include "tsid/math/constraint-equality.hpp"
+
+#include
+#include
+
+namespace tsid {
+namespace tasks {
+
+class TaskTwoFramesEquality : public TaskMotion {
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+
+ typedef math::Index Index;
+ typedef trajectories::TrajectorySample TrajectorySample;
+ typedef math::Vector Vector;
+ typedef math::ConstraintEquality ConstraintEquality;
+ typedef pinocchio::Data Data;
+ typedef pinocchio::Data::Matrix6x Matrix6x;
+ typedef pinocchio::Motion Motion;
+ typedef pinocchio::SE3 SE3;
+
+ TaskTwoFramesEquality(const std::string& name, RobotWrapper& robot,
+ const std::string& frameName1,
+ const std::string& frameName2);
+
+ int dim() const;
+
+ const ConstraintBase& compute(const double t, ConstRefVector q,
+ ConstRefVector v, Data& data);
+
+ const ConstraintBase& getConstraint() const;
+
+ /** Return the desired task acceleration (after applying the specified mask).
+ * The value is expressed in local frame is the local_frame flag is true,
+ * otherwise it is expressed in a local world-oriented frame.
+ */
+ const Vector& getDesiredAcceleration() const;
+
+ /** Return the task acceleration (after applying the specified mask).
+ * The value is expressed in local frame is the local_frame flag is true,
+ * otherwise it is expressed in a local world-oriented frame.
+ */
+ Vector getAcceleration(ConstRefVector dv) const;
+
+ virtual void setMask(math::ConstRefVector mask);
+
+ /** Return the position tracking error (after applying the specified mask).
+ * The error is expressed in local frame is the local_frame flag is true,
+ * otherwise it is expressed in a local world-oriented frame.
+ */
+ const Vector& position_error() const;
+
+ /** Return the velocity tracking error (after applying the specified mask).
+ * The error is expressed in local frame is the local_frame flag is true,
+ * otherwise it is expressed in a local world-oriented frame.
+ */
+ const Vector& velocity_error() const;
+
+ const Vector& Kp() const;
+ const Vector& Kd() const;
+ void Kp(ConstRefVector Kp);
+ void Kd(ConstRefVector Kp);
+
+ Index frame_id1() const;
+ Index frame_id2() const;
+
+ /**
+ * @brief Specifies if the jacobian and desired acceloration should be
+ * expressed in the local frame or the local world-oriented frame.
+ *
+ * @param local_frame If true, represent jacobian and acceloration in the
+ * local frame. If false, represent them in the local world-oriented frame.
+ */
+ void useLocalFrame(bool local_frame);
+
+ protected:
+ std::string m_frame_name1;
+ std::string m_frame_name2;
+ Index m_frame_id1;
+ Index m_frame_id2;
+ Motion m_p_error, m_v_error;
+ Vector m_p_error_vec, m_v_error_vec;
+ Vector m_p_error_masked_vec, m_v_error_masked_vec;
+ Vector m_p, m_v;
+ Vector m_p_ref, m_v_ref_vec;
+ Motion m_v_ref, m_a_ref;
+ SE3 m_wMl1, m_wMl2;
+ Vector m_Kp;
+ Vector m_Kd;
+ Vector m_a_des, m_a_des_masked;
+ Motion m_drift;
+ Vector m_drift_masked;
+ Matrix6x m_J1, m_J2;
+ Matrix6x m_J1_rotated, m_J2_rotated;
+ ConstraintEquality m_constraint;
+};
+
+} // namespace tasks
+} // namespace tsid
+
+#endif // ifndef __invdyn_task_frames_equality_hpp__
diff --git a/src/contacts/contact-two-frame-positions.cpp b/src/contacts/contact-two-frame-positions.cpp
new file mode 100644
index 00000000..9a8e0c95
--- /dev/null
+++ b/src/contacts/contact-two-frame-positions.cpp
@@ -0,0 +1,193 @@
+//
+// Copyright (c) 2023 MIPT
+//
+// This file is part of tsid
+// tsid is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation, either version
+// 3 of the License, or (at your option) any later version.
+// tsid is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details. You should have
+// received a copy of the GNU Lesser General Public License along with
+// tsid If not, see
+// .
+//
+
+#include "tsid/math/utils.hpp"
+#include "tsid/contacts/contact-two-frame-positions.hpp"
+
+#include
+
+using namespace tsid;
+using namespace contacts;
+using namespace math;
+using namespace trajectories;
+using namespace tasks;
+
+ContactTwoFramePositions::ContactTwoFramePositions(
+ const std::string& name, RobotWrapper& robot, const std::string& frameName1,
+ const std::string& frameName2, const double minNormalForce,
+ const double maxNormalForce)
+ : ContactBase(name, robot),
+ m_motionTask(
+ name, robot, frameName1,
+ frameName2), // Actual motion task with type TaskTwoFramesEquality
+ m_forceInequality(name, 3, 3),
+ m_forceRegTask(name, 3, 3),
+ m_fMin(minNormalForce),
+ m_fMax(maxNormalForce) {
+ m_weightForceRegTask << 1, 1, 1;
+ m_forceGenMat.resize(3, 3);
+ m_fRef = Vector3::Zero();
+ m_contactPoints.resize(3, 1);
+ m_contactPoints.setZero();
+ updateForceGeneratorMatrix();
+ updateForceInequalityConstraints();
+ updateForceRegularizationTask();
+
+ // This contact has forceGenMat as 3x3 identity matrix, so it can be used only
+ // for emulating a ball joint between two frames The forces calculated will
+ // have only linear part (rotation will be unconstrained) So we need to set
+ // the appropriate mask for motion task (which can take into account rotation
+ // but we don't need it)
+ math::Vector motion_mask(6);
+ motion_mask << 1., 1., 1., 0., 0., 0.;
+ m_motionTask.setMask(motion_mask);
+}
+
+void ContactTwoFramePositions::updateForceInequalityConstraints() {
+ Matrix B = Matrix::Identity(3, 3); // Force "gluing" two frames together can
+ // be arbitrary in sign/direction
+ Vector lb = m_fMin * Vector::Ones(3);
+ Vector ub = m_fMax * Vector::Ones(3);
+
+ m_forceInequality.setMatrix(B);
+ m_forceInequality.setLowerBound(lb);
+ m_forceInequality.setUpperBound(ub);
+}
+
+double ContactTwoFramePositions::getNormalForce(ConstRefVector f) const {
+ return 0.0;
+}
+
+const Matrix3x& ContactTwoFramePositions::getContactPoints() const {
+ return m_contactPoints;
+}
+
+void ContactTwoFramePositions::setRegularizationTaskWeightVector(
+ ConstRefVector& w) {
+ m_weightForceRegTask = w;
+ updateForceRegularizationTask();
+}
+
+void ContactTwoFramePositions::updateForceRegularizationTask() {
+ typedef Eigen::Matrix Matrix3;
+ Matrix3 A = Matrix3::Zero();
+ A.diagonal() = m_weightForceRegTask;
+ m_forceRegTask.setMatrix(A);
+ m_forceRegTask.setVector(A * m_fRef);
+}
+
+void ContactTwoFramePositions::updateForceGeneratorMatrix() {
+ m_forceGenMat.setIdentity();
+}
+
+unsigned int ContactTwoFramePositions::n_motion() const {
+ return m_motionTask.dim();
+}
+unsigned int ContactTwoFramePositions::n_force() const { return 3; }
+
+const Vector& ContactTwoFramePositions::Kp() {
+ m_Kp3 = m_motionTask.Kp().head<3>();
+ return m_Kp3;
+}
+
+const Vector& ContactTwoFramePositions::Kd() {
+ m_Kd3 = m_motionTask.Kd().head<3>();
+ return m_Kd3;
+}
+
+void ContactTwoFramePositions::Kp(ConstRefVector Kp) {
+ assert(Kp.size() == 3);
+ Vector6 Kp6;
+ Kp6.head<3>() = Kp;
+ m_motionTask.Kp(Kp6);
+}
+
+void ContactTwoFramePositions::Kd(ConstRefVector Kd) {
+ assert(Kd.size() == 3);
+ Vector6 Kd6;
+ Kd6.head<3>() = Kd;
+ m_motionTask.Kd(Kd6);
+}
+
+bool ContactTwoFramePositions::setContactNormal(ConstRefVector contactNormal) {
+ return true;
+}
+
+bool ContactTwoFramePositions::setFrictionCoefficient(
+ const double frictionCoefficient) {
+ return true;
+}
+
+bool ContactTwoFramePositions::setMinNormalForce(const double minNormalForce) {
+ m_fMin = minNormalForce;
+ updateForceInequalityConstraints();
+ return true;
+}
+
+bool ContactTwoFramePositions::setMaxNormalForce(const double maxNormalForce) {
+ m_fMax = maxNormalForce;
+ updateForceInequalityConstraints();
+ return true;
+}
+
+void ContactTwoFramePositions::setForceReference(ConstRefVector& f_ref) {
+ m_fRef = f_ref;
+ updateForceRegularizationTask();
+}
+
+const ConstraintBase& ContactTwoFramePositions::computeMotionTask(
+ const double t, ConstRefVector q, ConstRefVector v, Data& data) {
+ return m_motionTask.compute(t, q, v, data);
+}
+
+const ConstraintInequality& ContactTwoFramePositions::computeForceTask(
+ const double, ConstRefVector, ConstRefVector, const Data&) {
+ return m_forceInequality;
+}
+
+const Matrix& ContactTwoFramePositions::getForceGeneratorMatrix() {
+ return m_forceGenMat;
+}
+
+const ConstraintEquality&
+ContactTwoFramePositions::computeForceRegularizationTask(const double,
+ ConstRefVector,
+ ConstRefVector,
+ const Data&) {
+ return m_forceRegTask;
+}
+
+double ContactTwoFramePositions::getMinNormalForce() const { return m_fMin; }
+double ContactTwoFramePositions::getMaxNormalForce() const { return m_fMax; }
+
+const TaskTwoFramesEquality& ContactTwoFramePositions::getMotionTask() const {
+ return m_motionTask;
+}
+
+const ConstraintBase& ContactTwoFramePositions::getMotionConstraint() const {
+ return m_motionTask.getConstraint();
+}
+
+const ConstraintInequality& ContactTwoFramePositions::getForceConstraint()
+ const {
+ return m_forceInequality;
+}
+
+const ConstraintEquality& ContactTwoFramePositions::getForceRegularizationTask()
+ const {
+ return m_forceRegTask;
+}
diff --git a/src/tasks/task-cop-equality.cpp b/src/tasks/task-cop-equality.cpp
index 27be4418..3c362642 100644
--- a/src/tasks/task-cop-equality.cpp
+++ b/src/tasks/task-cop-equality.cpp
@@ -65,7 +65,11 @@ const ConstraintBase& TaskCopEquality::compute(const double, ConstRefVector,
unsigned int i = cl->index;
// get contact points in local frame and transform them to world frame
const Matrix3x& P = cl->contact.getContactPoints();
- m_robot.framePosition(data, cl->contact.getMotionTask().frame_id(), oMi);
+ m_robot.framePosition(
+ data,
+ static_cast(cl->contact.getMotionTask())
+ .frame_id(),
+ oMi);
// cout<<"Contact "<contact.name()<.
+//
+
+#include "tsid/math/utils.hpp"
+#include "tsid/tasks/task-two-frames-equality.hpp"
+#include "tsid/robots/robot-wrapper.hpp"
+
+namespace tsid {
+namespace tasks {
+using namespace std;
+using namespace math;
+using namespace trajectories;
+using namespace pinocchio;
+
+TaskTwoFramesEquality::TaskTwoFramesEquality(const std::string& name,
+ RobotWrapper& robot,
+ const std::string& frameName1,
+ const std::string& frameName2)
+ : TaskMotion(name, robot),
+ m_frame_name1(frameName1),
+ m_frame_name2(frameName2),
+ m_constraint(name, 6, robot.nv()) {
+ assert(m_robot.model().existFrame(frameName1));
+ assert(m_robot.model().existFrame(frameName2));
+ m_frame_id1 = m_robot.model().getFrameId(frameName1);
+ m_frame_id2 = m_robot.model().getFrameId(frameName2);
+
+ m_v_ref.setZero();
+ m_a_ref.setZero();
+ m_wMl1.setIdentity();
+ m_wMl2.setIdentity();
+ m_p_error_vec.setZero(6);
+ m_v_error_vec.setZero(6);
+ m_p.resize(12);
+ m_v.resize(6);
+ m_p_ref.resize(12);
+ m_v_ref_vec.resize(6);
+ m_Kp.setZero(6);
+ m_Kd.setZero(6);
+ m_a_des.setZero(6);
+ m_J1.setZero(6, robot.nv());
+ m_J2.setZero(6, robot.nv());
+ m_J1_rotated.setZero(6, robot.nv());
+ m_J2_rotated.setZero(6, robot.nv());
+
+ m_mask.resize(6);
+ m_mask.fill(1.);
+ setMask(m_mask);
+}
+
+void TaskTwoFramesEquality::setMask(math::ConstRefVector mask) {
+ TaskMotion::setMask(mask);
+ int n = dim();
+ m_constraint.resize(n, (unsigned int)m_J1.cols());
+ m_p_error_masked_vec.resize(n);
+ m_v_error_masked_vec.resize(n);
+ m_drift_masked.resize(n);
+ m_a_des_masked.resize(n);
+}
+
+int TaskTwoFramesEquality::dim() const { return (int)m_mask.sum(); }
+
+const Vector& TaskTwoFramesEquality::Kp() const { return m_Kp; }
+
+const Vector& TaskTwoFramesEquality::Kd() const { return m_Kd; }
+
+void TaskTwoFramesEquality::Kp(ConstRefVector Kp) {
+ assert(Kp.size() == 6);
+ m_Kp = Kp;
+}
+
+void TaskTwoFramesEquality::Kd(ConstRefVector Kd) {
+ assert(Kd.size() == 6);
+ m_Kd = Kd;
+}
+
+const Vector& TaskTwoFramesEquality::position_error() const {
+ return m_p_error_masked_vec;
+}
+
+const Vector& TaskTwoFramesEquality::velocity_error() const {
+ return m_v_error_masked_vec;
+}
+
+const Vector& TaskTwoFramesEquality::getDesiredAcceleration() const {
+ return m_a_des_masked;
+}
+
+Vector TaskTwoFramesEquality::getAcceleration(ConstRefVector dv) const {
+ return m_constraint.matrix() * dv + m_drift_masked;
+}
+
+Index TaskTwoFramesEquality::frame_id1() const { return m_frame_id1; }
+
+Index TaskTwoFramesEquality::frame_id2() const { return m_frame_id2; }
+
+const ConstraintBase& TaskTwoFramesEquality::getConstraint() const {
+ return m_constraint;
+}
+
+const ConstraintBase& TaskTwoFramesEquality::compute(const double,
+ ConstRefVector,
+ ConstRefVector,
+ Data& data) {
+ // Calculating task with formulation: [J1 - J2 0 0] dv = [-J1dot*v +
+ // J2dot*v]
+
+ SE3 oMi1, oMi2;
+ Motion v_frame1, v_frame2;
+ Motion m_drift1, m_drift2;
+ m_robot.framePosition(data, m_frame_id1, oMi1);
+ m_robot.framePosition(data, m_frame_id2, oMi2);
+ m_robot.frameVelocity(data, m_frame_id1, v_frame1);
+ m_robot.frameVelocity(data, m_frame_id2, v_frame2);
+ m_robot.frameClassicAcceleration(data, m_frame_id1, m_drift1);
+ m_robot.frameClassicAcceleration(data, m_frame_id2, m_drift2);
+
+ // Transformations from local to local-world-aligned frame (thus only rotation
+ // is used)
+ m_wMl1.rotation(oMi1.rotation());
+ m_wMl2.rotation(oMi2.rotation());
+
+ m_robot.frameJacobianLocal(data, m_frame_id1, m_J1);
+ m_robot.frameJacobianLocal(data, m_frame_id2, m_J2);
+
+ // Doing all calculations in local-world-aligned frame
+ errorInSE3(oMi1, oMi2, m_p_error); // pos err in local oMi1 frame
+ m_p_error_vec = m_wMl1.toActionMatrix() *
+ m_p_error.toVector(); // pos err in local-world-aligned frame
+
+ m_v_error = m_wMl2.act(v_frame2) -
+ m_wMl1.act(v_frame1); // vel err in local-world-aligned frame
+
+ // desired acc in local-world-aligned frame
+ m_a_des = m_Kp.cwiseProduct(m_p_error_vec) +
+ m_Kd.cwiseProduct(m_v_error.toVector());
+
+ m_v_error_vec = m_v_error.toVector();
+
+ m_drift = (m_wMl1.act(m_drift1) - m_wMl2.act(m_drift2));
+
+ m_J1_rotated.noalias() =
+ m_wMl1.toActionMatrix() *
+ m_J1; // Use an explicit temporary m_J_rotated to avoid allocations
+ m_J1 = m_J1_rotated;
+
+ m_J2_rotated.noalias() = m_wMl2.toActionMatrix() * m_J2;
+ m_J2 = m_J2_rotated;
+
+ int idx = 0;
+ for (int i = 0; i < 6; i++) {
+ if (m_mask(i) != 1.) continue;
+
+ m_constraint.matrix().row(idx) = m_J1.row(i) - m_J2.row(i);
+ m_constraint.vector().row(idx) = (m_a_des - m_drift.toVector()).row(i);
+ m_a_des_masked(idx) = m_a_des(i);
+ m_drift_masked(idx) = m_drift.toVector()(i);
+ m_p_error_masked_vec(idx) = m_p_error_vec(i);
+ m_v_error_masked_vec(idx) = m_v_error_vec(i);
+
+ idx += 1;
+ }
+
+ return m_constraint;
+}
+} // namespace tasks
+} // namespace tsid
diff --git a/tests/python/test_Constraint.py b/tests/python/test_Constraint.py
index 0f4cbae5..7110b517 100644
--- a/tests/python/test_Constraint.py
+++ b/tests/python/test_Constraint.py
@@ -1,6 +1,5 @@
import numpy as np
import pinocchio as se3
-
import tsid
print("")
diff --git a/tests/python/test_Contact.py b/tests/python/test_Contact.py
index 33381911..4872e919 100644
--- a/tests/python/test_Contact.py
+++ b/tests/python/test_Contact.py
@@ -2,7 +2,6 @@
import numpy as np
import pinocchio as se3
-
import tsid
print("")
diff --git a/tests/python/test_ContactPoint.py b/tests/python/test_ContactPoint.py
index cdf9e505..00e5f24b 100644
--- a/tests/python/test_ContactPoint.py
+++ b/tests/python/test_ContactPoint.py
@@ -3,7 +3,6 @@
import numpy as np
import pinocchio as se3
-
import tsid
print("")
diff --git a/tests/python/test_Deprecations.py b/tests/python/test_Deprecations.py
index 8e0bf828..588ce382 100644
--- a/tests/python/test_Deprecations.py
+++ b/tests/python/test_Deprecations.py
@@ -3,7 +3,6 @@
import warnings
import numpy as np
-
import tsid
diff --git a/tests/python/test_Formulation.py b/tests/python/test_Formulation.py
index 6d993306..07d3af06 100644
--- a/tests/python/test_Formulation.py
+++ b/tests/python/test_Formulation.py
@@ -2,9 +2,8 @@
import numpy as np
import pinocchio as se3
-from numpy.linalg import norm
-
import tsid
+from numpy.linalg import norm
print("")
print("Test InvDyn")
diff --git a/tests/python/test_Gravity.py b/tests/python/test_Gravity.py
index 84072885..c85d4fb8 100644
--- a/tests/python/test_Gravity.py
+++ b/tests/python/test_Gravity.py
@@ -2,7 +2,6 @@
import numpy as np
import pinocchio as se3
-
import tsid
print("")
diff --git a/tests/python/test_RobotWrapper.py b/tests/python/test_RobotWrapper.py
index 7fa1df85..6e7bb073 100644
--- a/tests/python/test_RobotWrapper.py
+++ b/tests/python/test_RobotWrapper.py
@@ -2,7 +2,6 @@
import numpy as np
import pinocchio as se3
-
import tsid
print("")
diff --git a/tests/python/test_Solvers.py b/tests/python/test_Solvers.py
index 4f437d0e..eb8e2896 100644
--- a/tests/python/test_Solvers.py
+++ b/tests/python/test_Solvers.py
@@ -1,5 +1,4 @@
import numpy as np
-
import tsid
print("")
diff --git a/tests/python/test_Tasks.py b/tests/python/test_Tasks.py
index cb98d577..59711dc1 100644
--- a/tests/python/test_Tasks.py
+++ b/tests/python/test_Tasks.py
@@ -2,9 +2,8 @@
import numpy as np
import pinocchio as pin
-from numpy.linalg import norm
-
import tsid
+from numpy.linalg import norm
print("")
print("Test Task COM")
diff --git a/tests/python/test_Trajectories.py b/tests/python/test_Trajectories.py
index 0674e989..8c0acdd5 100644
--- a/tests/python/test_Trajectories.py
+++ b/tests/python/test_Trajectories.py
@@ -1,6 +1,5 @@
import numpy as np
import pinocchio as se3
-
import tsid
print("")