Skip to content

Commit 07ebc56

Browse files
committed
Added damped least sqaures to the operational space controller and use fullPivHouseholderQr for more numerical stability.
Also added a new example for the Eurofusion robot using the operational space controller while the tilting plate joint is fixed. Here, we also see some of the joints wander a bit off while the end-effector is at the desired position -- that is how it is, when we are using this particular controller.
1 parent d25d586 commit 07ebc56

4 files changed

Lines changed: 160 additions & 4 deletions

File tree

examples/simulation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ add_example(impedance_controller ur/cpp)
88
add_example(eurofusion_joint_motion_controller eurofusion/cpp)
99
add_example(eurofusion_robot_rnea eurofusion/cpp)
1010
add_example(eurofusion_force_control_velocity eurofusion/cpp)
11+
add_example(eurofusion_cartesian_motion_controller eurofusion/cpp)
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#include <Eigen/Dense>
2+
#include <fstream>
3+
#include <iostream>
4+
#include <sdu_controllers/controllers/operational_space_controller.hpp>
5+
#include <sdu_controllers/math/forward_dynamics.hpp>
6+
#include <sdu_controllers/math/inverse_dynamics_joint_space.hpp>
7+
#include <sdu_controllers/kinematics/forward_kinematics.hpp>
8+
#include <sdu_controllers/models/parameter_robot_model.hpp>
9+
#include <sdu_controllers/safety/safety_verifier.hpp>
10+
#include <sdu_controllers/utils/utility.hpp>
11+
12+
using namespace csv;
13+
using namespace Eigen;
14+
using namespace sdu_controllers;
15+
using namespace sdu_controllers::utils;
16+
17+
int main()
18+
{
19+
// Setup writing of output trajectory to csv.
20+
std::ofstream output_filestream;
21+
output_filestream.open("output_cartesian.csv");
22+
auto csv_writer = make_csv_writer(output_filestream);
23+
24+
// Initialize robot model and parameters
25+
auto robot_model = std::make_shared<models::ParameterRobotModel>(utils::ConfigFolder::find_config_file("breeding_blanket_handling_robot_fixed.yaml"));
26+
27+
double freq = 1000.0;
28+
double dt = 1.0 / freq;
29+
30+
double Kp_pos_value = 10.0;
31+
double Kp_orient_value = 1;
32+
double Kd_pos_value = 20.0;
33+
double Kd_orient_value = 2;
34+
double N_value = 0;
35+
uint16_t ROBOT_DOF = robot_model->get_dof();
36+
37+
VectorXd Kp_pos_vec = VectorXd::Ones(3) * Kp_pos_value;
38+
VectorXd Kp_orient_vec = VectorXd::Ones(3) * Kp_orient_value;
39+
VectorXd Kd_pos_vec = VectorXd::Ones(3) * Kd_pos_value;
40+
VectorXd Kd_orient_vec = VectorXd::Ones(3) * Kd_orient_value;
41+
VectorXd N_vec = VectorXd::Ones(6) * N_value;
42+
43+
MatrixXd Kp = MatrixXd::Zero(6, 6);
44+
Kp.setIdentity();
45+
Kp.block<3, 3>(0,0) = Kp_pos_vec.asDiagonal();
46+
Kp.block<3, 3>(3,3) = Kp_orient_vec.asDiagonal();
47+
MatrixXd Kd = MatrixXd::Zero(6, 6);
48+
Kd.setIdentity();
49+
Kd.block<3, 3>(0,0) = Kd_pos_vec.asDiagonal();
50+
Kd.block<3, 3>(3,3) = Kd_orient_vec.asDiagonal();
51+
52+
controllers::OperationalSpaceController osc_controller(Kp, Kd, robot_model);
53+
osc_controller.set_kappa(1e-2);
54+
//math::InverseDynamicsJointSpace inv_dyn_jnt_space(robot_model);
55+
//math::ForwardDynamics fwd_dyn(robot_model);
56+
57+
VectorXd x_d(6);
58+
VectorXd dx_d(6);
59+
VectorXd ddx_d(6);
60+
61+
VectorXd q(ROBOT_DOF), q0(ROBOT_DOF);
62+
VectorXd dq(ROBOT_DOF);
63+
Vector<double, 6> he = VectorXd::Zero(6);
64+
q << 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
65+
q0 << 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
66+
dq << 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
67+
68+
// output to csv
69+
output_filestream << "q0,q1,q2,q3,q4,q5,x,y,z,rx,ry,rz" << std::endl;;
70+
71+
// Stay put at the initial position
72+
// Control loop for 10s
73+
for (size_t j=0; j < freq * 20.; j++) // (const std::vector<double>& trajectory_point : input_trajectory)
74+
{
75+
if (j % int(freq) == 0)
76+
std::cout << "Time: " << j * dt << std::endl;
77+
78+
// Desired
79+
Eigen::Matrix4d T0 = robot_model->get_fk_solver().forward_kinematics(q0);
80+
VectorXd pos0 = T0.block<3, 1>(0, 3);
81+
Matrix3d rot_mat0 = T0.block<3,3>(0, 0);
82+
Vector3d rpy_zyz0 = rot_mat0.eulerAngles(2, 1, 2); // ZYZ representation
83+
84+
Vector3d pos_desired = pos0;
85+
pos_desired[0] += 0.1;
86+
pos_desired[1] += -0.1;
87+
pos_desired[2] += 2;
88+
89+
Vector3d rpy_zyz_desired = rpy_zyz0;
90+
rpy_zyz_desired[0] += M_PI / 8;
91+
rpy_zyz_desired[1] += 0;
92+
rpy_zyz_desired[2] += M_PI / 2;
93+
94+
x_d << pos_desired, rpy_zyz_desired;
95+
dx_d.setZero();
96+
ddx_d.setZero();
97+
98+
// std::cout << "x_d: " << x_d << std::endl;
99+
100+
// Add noise to q and dq
101+
VectorXd q_meas = q;
102+
VectorXd dq_meas = dq;
103+
//add_noise_to_vector(q_meas, 0.0, 0.001);
104+
//add_noise_to_vector(dq_meas, 0.0, 0.001);
105+
106+
// std::cout << "before all fk" << std::endl;
107+
// std::vector<Eigen::Matrix4d> TTT = robot_model->get_fk_solver().forward_kinematics_all(q0);
108+
// std::cout << "after all fk" << std::endl;
109+
// std::cout << TTT.at(4) << std::endl;
110+
111+
// Controller
112+
osc_controller.step(x_d, dx_d, ddx_d, q_meas, dq_meas);
113+
VectorXd y = osc_controller.get_output();
114+
// std::cout << "y: " << y << std::endl;
115+
VectorXd tau = robot_model->inverse_dynamics(q_meas, dq_meas, y, he);
116+
// std::cout << "tau: " << tau << std::endl;
117+
118+
// Simulation
119+
VectorXd ddq = robot_model->forward_dynamics(q, dq, tau);
120+
// integrate to get velocity
121+
dq += ddq * dt;
122+
// integrate to get position
123+
q += dq * dt;
124+
125+
// std::cout << "q:" << q << std::endl;
126+
MatrixXd T = robot_model->get_fk_solver().forward_kinematics(q);
127+
VectorXd pos = T.block<3, 1>(0, 3);
128+
// std::cout << "pos:" << pos << std::endl;
129+
Matrix3d rot_mat = T.block<3,3>(0, 0);
130+
Vector3d rpy_zyz = rot_mat.eulerAngles(2, 1, 2); // ZYZ representation
131+
// std::cout << "rpy_zyz:" << rpy_zyz << std::endl;
132+
VectorXd temp(q.size()+pos.size()+rpy_zyz.size());
133+
temp << q, pos, rpy_zyz;
134+
csv_writer << eigen_to_std_vector(temp);
135+
}
136+
output_filestream.close();
137+
}

include/sdu_controllers/controllers/operational_space_controller.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,15 @@ namespace sdu_controllers::controllers
4646
*/
4747
void reset() override;
4848

49+
/**
50+
* Set kappa used in the damped least squares.
51+
*/
52+
void set_kappa(double kappa);
53+
4954
private:
5055
Eigen::VectorXd y_;
5156
Eigen::MatrixXd Kp_, Kd_;
57+
double kappa_;
5258
std::shared_ptr<models::RobotModel> robot_model_;
5359
};
5460

src/controllers/operational_space_controller.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <sdu_controllers/kinematics/forward_kinematics.hpp>
33
#include <sdu_controllers/math/math.hpp>
44
#include <utility>
5+
#include <Eigen/src/QR/FullPivHouseholderQR.h>
56

67
using namespace Eigen;
78

@@ -15,6 +16,7 @@ namespace sdu_controllers::controllers
1516
Kd_(std::move(Kd)),
1617
robot_model_(std::move(robot_model))
1718
{
19+
kappa_ = 0;
1820
}
1921

2022
void OperationalSpaceController::step(
@@ -44,23 +46,33 @@ namespace sdu_controllers::controllers
4446

4547
VectorXd dx_tilde = dx_d - dx_e;
4648

47-
4849
// Eq. (8.114) from page 348, Robotics: Modelling, Planning and Control:
49-
// TODO: This will only work for a robot with six joints, since you cannot take the inverse
50-
// of a 6x7 sized Jacobian.
51-
y_ = J_A.lu().solve(ddx_d + Kd_ * dx_tilde + Kp_ * x_tilde - Jdot_A * dq);
50+
Eigen::MatrixXd kappaI;
51+
kappaI.setIdentity(6, 6);
52+
kappaI *= kappa_*kappa_; // todo: should be user configurable
53+
54+
// The following implements damped least-squares, see eq. (3.59)
55+
y_ = J_A.transpose() * (J_A * J_A.transpose() + kappaI).fullPivHouseholderQr().solve(
56+
ddx_d + Kd_ * dx_tilde + Kp_ * x_tilde - Jdot_A * dq
57+
);
5258
}
5359

5460
void OperationalSpaceController::reset()
5561
{
5662
Kp_.setZero();
5763
Kd_.setZero();
5864
y_.setZero();
65+
kappa_ = 0;
5966
}
6067

6168
VectorXd OperationalSpaceController::get_output()
6269
{
6370
return y_;
6471
}
6572

73+
void OperationalSpaceController::set_kappa(double kappa)
74+
{
75+
kappa_ = kappa;
76+
}
77+
6678
} // namespace sdu_controllers::controllers

0 commit comments

Comments
 (0)