|
| 1 | +/** |
| 2 | + * \file ne.c |
| 3 | + * \author Peter Corke |
| 4 | + * \brief Compute the recursive Newton-Euler formulation |
| 5 | + */ |
| 6 | + |
| 7 | +/* |
| 8 | + * Copyright (C) 1999-2008, by Peter I. Corke |
| 9 | + * |
| 10 | + * This file is part of The Robotics Toolbox for Matlab (RTB). |
| 11 | + * |
| 12 | + * RTB is free software: you can redistribute it and/or modify |
| 13 | + * it under the terms of the GNU Lesser General Public License as published by |
| 14 | + * the Free Software Foundation, either version 3 of the License, or |
| 15 | + * (at your option) any later version. |
| 16 | + * |
| 17 | + * RTB is distributed in the hope that it will be useful, |
| 18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | + * GNU Lesser General Public License for more details. |
| 21 | + * |
| 22 | + * You should have received a copy of the GNU Leser General Public License |
| 23 | + * along with RTB. If not, see <http://www.gnu.org/licenses/>. |
| 24 | + * |
| 25 | + */ |
| 26 | + |
| 27 | +/* |
| 28 | + * Compute the inverse dynamics via the recursive Newton-Euler formulation |
| 29 | + * |
| 30 | + * Requires: qd current joint velocities |
| 31 | + * qdd current joint accelerations |
| 32 | + * f applied tip force or load |
| 33 | + * grav the gravitational constant |
| 34 | + * |
| 35 | + * Returns: tau vector of bias torques |
| 36 | + */ |
| 37 | +#include "frne2.h" |
| 38 | +#include <iostream> |
| 39 | +#include <Eigen/Dense> |
| 40 | + |
| 41 | +using namespace Eigen; |
| 42 | + |
| 43 | +/* |
| 44 | +#define DEBUG |
| 45 | +*/ |
| 46 | + |
| 47 | +/* |
| 48 | + * Bunch of macros to make the main code easier to read. Dereference vectors |
| 49 | + * from the Link structures for the manipulator. |
| 50 | + * |
| 51 | + * Note that they return pointers (except for M(j) which is a scalar) |
| 52 | + */ |
| 53 | +#undef N |
| 54 | + |
| 55 | +#define w(j) (&links[j].omega) /* angular velocity */ |
| 56 | +#define wd(j) (&links[j].omega_d) /* angular acceleration */ |
| 57 | +#define a(j) (&links[j].acc) /* linear acceleration */ |
| 58 | +#define acc_cog(j) (&links[j].abar) /* linear acceln of COG */ |
| 59 | + |
| 60 | +#define f(j) (&links[j].f) /* force on link j due to link j-1 */ |
| 61 | +#define n(j) (&links[j].n) /* torque on link j due to link j-1 */ |
| 62 | + |
| 63 | +#define R(j) (&links[j].R) /* link rotation matrix */ |
| 64 | +#define M(j) (links[j].m) /* link mass */ |
| 65 | +#define PSTAR(j) (&links[j].r) /* offset link i from link (j-1) */ |
| 66 | +#define r_cog(j) (links[j].rbar) /* COG link j wrt link j */ |
| 67 | +#define I(j) (links[j].I) /* inertia of link about COG */ |
| 68 | + |
| 69 | +/** |
| 70 | + * Recursive Newton-Euler algorithm. |
| 71 | + * |
| 72 | + * @Note the parameter \p stride which is used to allow for input and output |
| 73 | + * arrays which are 2-dimensional but in column-major (Matlab) order. We |
| 74 | + * need to access rows from the arrays. |
| 75 | + * |
| 76 | + */ |
| 77 | +void |
| 78 | +newton_euler ( |
| 79 | + Robot *robot, /*!< robot object */ |
| 80 | + double *tau, /*!< returned joint torques */ |
| 81 | + double *qd, /*!< joint velocities */ |
| 82 | + double *qdd, /*!< joint accelerations */ |
| 83 | + double *fext, /*!< external force on manipulator tip */ |
| 84 | + int stride /*!< indexing stride for qd, qdd */ |
| 85 | +) { |
| 86 | + Map<Vector3d> gravity(robot->gravity); |
| 87 | + Vector3d qdv = Vector3d::Zero(); |
| 88 | + Vector3d qddv = Vector3d::Zero(); |
| 89 | + Vector3d F, N; |
| 90 | + Vector3d z0 = Vector3d::UnitZ(); |
| 91 | + Vector3d zero = Vector3d::Zero(); |
| 92 | + register int j; |
| 93 | + double t; |
| 94 | + Link *links = robot->links; |
| 95 | + |
| 96 | + /* |
| 97 | + * angular rate and acceleration vectors only have finite |
| 98 | + * z-axis component |
| 99 | + */ |
| 100 | + qdv = qddv = zero; |
| 101 | + |
| 102 | + /* setup external force/moment vectors */ |
| 103 | + if (fext) { |
| 104 | + Vector3d f_tip(&fext[0]); |
| 105 | + Vector3d n_tip(&fext[3]); |
| 106 | + } else |
| 107 | + { |
| 108 | + Vector3d f_tip = Vector3d::Zero(); |
| 109 | + Vector3d n_tip = Vector3d::Zero(); |
| 110 | + } |
| 111 | + |
| 112 | + |
| 113 | +/****************************************************************************** |
| 114 | + * forward recursion --the kinematics |
| 115 | + ******************************************************************************/ |
| 116 | + |
| 117 | + if (robot->dhtype == MODIFIED) { |
| 118 | + /* |
| 119 | + * MODIFIED D&H CONVENTIONS |
| 120 | + */ |
| 121 | + for (j = 0; j < robot->njoints; j++) { |
| 122 | + |
| 123 | + /* create angular vector from scalar input */ |
| 124 | + qdv.z() = qd[j*stride]; |
| 125 | + qddv.z() = qdd[j*stride]; |
| 126 | + |
| 127 | + switch (links[j].sigma) { |
| 128 | + case REVOLUTE: |
| 129 | + /* |
| 130 | + * calculate angular velocity of link j |
| 131 | + */ |
| 132 | + if (j == 0) |
| 133 | + w(j) = qdv; |
| 134 | + else { |
| 135 | + w(j) = R(j) * w(j-1) + qdv; |
| 136 | + } |
| 137 | + |
| 138 | + /* |
| 139 | + * calculate angular acceleration of link j |
| 140 | + */ |
| 141 | + if (j == 0) |
| 142 | + wd(j) = qddv; |
| 143 | + else { |
| 144 | + wd(j) = qdv.cross(R(j) * w(j-1)) + R(j) * wd(j-1)) + qddv; |
| 145 | + } |
| 146 | + |
| 147 | + /* |
| 148 | + * compute acc[j] |
| 149 | + */ |
| 150 | + if (j == 0) { |
| 151 | + a(j) = R(j) * gravity; |
| 152 | + } else { |
| 153 | + a(j) = a(j-1) + wd(j-1).cross(PSTAR(j)) + w(j-1).cross(w(j-1).cross(PSTAR(j))); |
| 154 | + } |
| 155 | + |
| 156 | + break; |
| 157 | + |
| 158 | + case PRISMATIC: |
| 159 | + /* |
| 160 | + * calculate omega[j] |
| 161 | + */ |
| 162 | + if (j == 0) |
| 163 | + w[j] = qdv; |
| 164 | + else |
| 165 | + w[j] = R[j] * w[j-1]; |
| 166 | + |
| 167 | + /* |
| 168 | + * calculate alpha[j] |
| 169 | + */ |
| 170 | + if (j == 0) |
| 171 | + *(wd(j)) = qddv; |
| 172 | + wd = qddv; |
| 173 | + else |
| 174 | + wd = R[j] * wd[j-1]l |
| 175 | + |
| 176 | + /* |
| 177 | + * compute acc[j] |
| 178 | + */ |
| 179 | + if (j == 0) |
| 180 | + a[j] = gravity; |
| 181 | + else |
| 182 | + a[j] = R[j] * (w[j-1].cross(w[j-1], PSTAR[j]) + wd[j-1].cross(PSTAR[j]) + a[j-1]) + |
| 183 | + |
| 184 | + 2*(R[j]*w[j-1]).cross(qdv) + qddv; |
| 185 | + } |
| 186 | + break; |
| 187 | + } |
| 188 | + |
| 189 | + /* |
| 190 | + * compute abar[j] |
| 191 | + */ |
| 192 | + acc_cog[j] = wd[j].cross(r_cog[j]) + w[j].cross(w[j].cross(r_cog[j])); |
| 193 | + acc_cog[j] += a[j]; |
| 194 | + |
| 195 | +#ifdef DEBUG |
| 196 | + vect_print("w", w(j)); |
| 197 | + vect_print("wd", wd(j)); |
| 198 | + vect_print("acc", a(j)); |
| 199 | + vect_print("abar", acc_cog(j)); |
| 200 | +#endif |
| 201 | + } |
| 202 | + } else { |
| 203 | + /* |
| 204 | + * STANDARD D&H CONVENTIONS |
| 205 | + */ |
| 206 | + for (j = 0; j < robot->njoints; j++) { |
| 207 | + |
| 208 | + /* create angular vector from scalar input */ |
| 209 | + qdv.z() = qd[j*stride]; |
| 210 | + qddv.z() = qdd[j*stride]; |
| 211 | + |
| 212 | + switch (links[j].sigma) { |
| 213 | + case REVOLUTE: |
| 214 | + /* |
| 215 | + * calculate omega[j] |
| 216 | + */ |
| 217 | + if (j == 0) |
| 218 | + w[j] = R[j] * qdv; |
| 219 | + else |
| 220 | + w[j] = R[j] * (w[j-1] + qdv); |
| 221 | + |
| 222 | + /* |
| 223 | + * calculate alpha[j] |
| 224 | + */ |
| 225 | + if (j == 0) |
| 226 | + wd[j] = R[j] * qddv; |
| 227 | + else { |
| 228 | + wd[j] = wd[j-1] + qddv + w[j-1].cross(qdv); |
| 229 | + } |
| 230 | + |
| 231 | + /* |
| 232 | + * compute acc[j] |
| 233 | + */ |
| 234 | + a[j] = wd[j].cross(PSTAR[j]) + w[j].cross(w[j].cross(PSTAR[j])); |
| 235 | + if (j == 0) { |
| 236 | + a[j] += R[j] * gravity; |
| 237 | + } else |
| 238 | + a[j] += R[j] * a[j-1]; |
| 239 | + break; |
| 240 | + |
| 241 | + case PRISMATIC: |
| 242 | + /* |
| 243 | + * calculate omega[j] |
| 244 | + */ |
| 245 | + if (j == 0) |
| 246 | + w[j] = zero; |
| 247 | + else |
| 248 | + w[j] = R[j] * w[j-1]; |
| 249 | + |
| 250 | + /* |
| 251 | + * calculate alpha[j] |
| 252 | + */ |
| 253 | + if (j == 0) |
| 254 | + wd[j] = zero; |
| 255 | + else |
| 256 | + wd[j] = R[j] * wd[j-1]; |
| 257 | + |
| 258 | + /* |
| 259 | + * compute acc[j] |
| 260 | + */ |
| 261 | + if (j == 0) |
| 262 | + a[j] = R[j] * (qddv + robot.gravity); |
| 263 | + else |
| 264 | + a[j] = R[j] * (qddv + a[j-1]); |
| 265 | + |
| 266 | + a[j] += wd[j].cross(PSTAR[j]) + |
| 267 | + 2*w[j].cross(R[j]*qdv) + |
| 268 | + w[j].cross( w[j].cross(PSTAR[j]) ); |
| 269 | + break; |
| 270 | + } |
| 271 | + /* |
| 272 | + * compute abar[j] |
| 273 | + */ |
| 274 | + acc_cog[j] = wd[j].cross(r_cog[j]) + w[j].cross(w[j].cross(r_cog[j])) + a[j]; |
| 275 | + |
| 276 | +#ifdef DEBUG |
| 277 | + vect_print("w", w(j)); |
| 278 | + vect_print("wd", wd(j)); |
| 279 | + vect_print("acc", a(j)); |
| 280 | + vect_print("abar", acc_cog(j)); |
| 281 | +#endif |
| 282 | + } |
| 283 | + } |
| 284 | + |
| 285 | +/****************************************************************************** |
| 286 | + * backward recursion part --the kinetics |
| 287 | + ******************************************************************************/ |
| 288 | + |
| 289 | + if (robot->dhtype == MODIFIED) { |
| 290 | + /* |
| 291 | + * MODIFIED D&H CONVENTIONS |
| 292 | + */ |
| 293 | + for (j = robot->njoints - 1; j >= 0; j--) { |
| 294 | + |
| 295 | + /* |
| 296 | + * compute F[j] |
| 297 | + */ |
| 298 | + F = acc_cog[j] * M[j]; |
| 299 | + |
| 300 | + /* |
| 301 | + * compute f[j] |
| 302 | + */ |
| 303 | + if (j == (robot->njoints-1)) |
| 304 | + f[j] = f_tip + F; |
| 305 | + else |
| 306 | + f[j] = R[j+1] * f[j+1] + F; |
| 307 | + |
| 308 | + /* |
| 309 | + * compute N[j] |
| 310 | + */ |
| 311 | + N = I[j] * wd[j] + w[j].cross(I[j] * w[j]); |
| 312 | + |
| 313 | + /* |
| 314 | + * compute n[j] |
| 315 | + */ |
| 316 | + if (j == (robot->njoints-1)) |
| 317 | + n[j] = n_tip; |
| 318 | + else |
| 319 | + n[j] = R[j+1] * n[j+1] + PSTAR[j+1].cross(R[j+1] * f[j+1]) |
| 320 | + |
| 321 | + n[j] += r_cog[j].cross(F) + N; |
| 322 | + |
| 323 | +#ifdef DEBUG |
| 324 | + vect_print("f", f(j)); |
| 325 | + vect_print("n", n(j)); |
| 326 | +#endif |
| 327 | + } |
| 328 | + |
| 329 | + } else { |
| 330 | + /* |
| 331 | + * STANDARD D&H CONVENTIONS |
| 332 | + */ |
| 333 | + for (j = robot->njoints - 1; j >= 0; j--) { |
| 334 | + |
| 335 | + /* |
| 336 | + * compute f[j] |
| 337 | + */ |
| 338 | + F = acc_cog[j] * M[j]; |
| 339 | + if (j != (robot->njoints-1)) |
| 340 | + f[j] = R[j+1] * f[j+1] + F; |
| 341 | + else |
| 342 | + f[j] = f_tip + F; |
| 343 | + |
| 344 | + /* |
| 345 | + * compute n[j] |
| 346 | + */ |
| 347 | + |
| 348 | + N = I[j] * wd[j] + w[j].cross(I[j] * w[j]); |
| 349 | + |
| 350 | + n[j] = (PSTAR[j] + r_cog[j]).cross(F); |
| 351 | + |
| 352 | + if (j != (robot->njoints-1)) |
| 353 | + n[j] += R[j+1] * (n[j+1] + R[j+1] * (n[j+1] + PSTAR[j]).cross(f[j+1]); |
| 354 | + else |
| 355 | + n[j] += n_tip + PSTAR[j].cross(f_tip); |
| 356 | + |
| 357 | + n[j] += r_cog[j].cross(F) + N; |
| 358 | +#ifdef DEBUG |
| 359 | + vect_print("f", f(j)); |
| 360 | + vect_print("n", n(j)); |
| 361 | +#endif |
| 362 | + } |
| 363 | + } |
| 364 | + |
| 365 | + /* |
| 366 | + * Compute the torque total for each axis |
| 367 | + * |
| 368 | + */ |
| 369 | + for (j=0; j < robot->njoints; j++) { |
| 370 | + double t; |
| 371 | + Vector3d tauv; |
| 372 | + Link *l = &links[j]; |
| 373 | + |
| 374 | + if (robot->dhtype == MODIFIED) |
| 375 | + tauv = z0; |
| 376 | + else |
| 377 | + tauv = R[j] * z0; |
| 378 | + |
| 379 | + switch (l->sigma) { |
| 380 | + case REVOLUTE: |
| 381 | + t = n[j].dot(tauv); |
| 382 | + break; |
| 383 | + case PRISMATIC: |
| 384 | + t = f[j].dot(tauv); |
| 385 | + break; |
| 386 | + } |
| 387 | + |
| 388 | + /* |
| 389 | + * add actuator dynamics and friction |
| 390 | + */ |
| 391 | + t += l->G * l->G * l->Jm * qdd[j*stride]; // inertia |
| 392 | + t += l->G * l->G * l->B * qd[j*stride]; // viscous friction |
| 393 | + t += fabs(l->G) * ( |
| 394 | + (qd[j*stride] > 0 ? l->Tc[0] : 0.0) + // Coulomb friction |
| 395 | + (qd[j*stride] < 0 ? l->Tc[1] : 0.0) |
| 396 | + ); |
| 397 | + tau[j*stride] = t; |
| 398 | + } |
| 399 | +} |
0 commit comments