Customer_controller/USER/RobotAlgorithmModule.c

2384 lines
55 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @brief Description: Algorithm module of robotics, according to the
* book[modern robotics : mechanics, planning, and control].
* @file: RobotAlgorithmModule.c
* @author: Brian
* @date: 2019/03/01 12:23
* Copyright(c) 2019 Brian. All rights reserved.
*
* Contact https://blog.csdn.net/Galaxy_Robot
* @note:
*@warning:
*/
#include "RobotAlgorithmModule.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/**
*@brief Description:use GrublersFormula calculate The number of degrees of
* freedom of a mechanism with links and joints.
*@param[in] N the number of links( including the ground ).
*@param[in] m the number of degrees of freedom of a rigid body.
* (m = 3 for planar mechanisms and m = 6 for spatial mechanisms).
*@param[in] J the number of joints.
*@param[in] f the number of freedoms provided by each joint..
*@return The number of degrees of freedom of a mechanism
*@note: This formula holds only if all joint constraints are independent.
* If they are not independent then the formula provides a lower
* bound on the number of degrees of freedom.
*@warning:
*/
int GrublersFormula(int m, int N, int J, int *f)
{
int i;
int dof;
int c = 0;
for (i=1;i<=J;i++)
{
c = c + f[i-1];
}
dof = m*(N - 1 - J) + c;
return dof;
}
/**
*@brief Description: Make matrix b equal to matrix a.
*@param[in] a a 3 x 3 matrix.
*@param[out] b result,b=a.
*@return No return value.
*@note:
*@warning:
*/
void Matrix3Equal(double a[][3], double b[][3])
{
int i;
int j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
b[i][j] = a[i][j];
}
}
return;
}
/**
*@brief Description: Make matrix b equal to matrix a.
*@param[in] a a 4 x 4 matrix.
*@param[out] b result,b=a.
*@return No return value.
*@note:
*@warning:
*/
void Matrix4Equal(double a[][4], double b[][4])
{
int i;
int j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
b[i][j] = a[i][j];
}
}
return;
}
/**
*@brief Description:Calculate a 3 x 3 matrix add a 3 x 3 matrix.
*@param[in] a a 3 x 3 matrix.
*@param[in] b a 3 x 3 matrix.
*@param[out] c result of a+b.
*@return No return value.
*@note:
*@warning:
*/
void Matrix3Add(double a[][3], double b[][3], double c[][3])
{
int i;
int j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
c[i][j] = a[i][j] + b[i][j];
}
}
return;
}
/**
*@brief Description:Calculate a 4 x 4 matrix add a 4 x 4 matrix.
*@param[in] a a 4 x 4 matrix.
*@param[in] b a 4 x 4 matrix.
*@param[out] c result of a+b.
*@return No return value.
*@note:
*@warning:
*/
void Matrix4Add(double a[][4], double b[][4], double c[][4])
{
int i;
int j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
c[i][j] = a[i][j] + b[i][j];
}
}
return;
}
/**
*@brief Description:Calculate a 3 x 3 matrix Subtract a 3 x 3 matrix.
*@param[in] a a 3 x 3 matrix.
*@param[in] b a 3 x 3 matrix.
*@param[out] c result of a-b.
*@return No return value.
*@note:
*@warning:
*/
void Matrix3Sub(double a[][3], double b[][3], double c[][3])
{
int i;
int j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
c[i][j] = a[i][j] - b[i][j];
}
}
return;
}
/**
*@brief Description:Calculate a 4 x 4 matrix Subtract a 4 x 4 matrix.
*@param[in] a a 4 x 4 matrix.
*@param[in] b a 4 x 4 matrix.
*@param[out] c result of a-b.
*@return No return value.
*@note:
*@warning:
*/
void Matrix4Sub(double a[][4], double b[][4], double c[][4])
{
int i;
int j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
c[i][j] = a[i][j] - b[i][j];
}
}
return;
}
/**
*@brief Description: Calculate two 3 x 3 matrix multiplication.
*@param[in] a a 3 x 3 matrix.
*@param[in] b a 3 x 3 matrix.
*@param[out] c result of a*b.
*@return No return value.
*@note:
*@warning:
*/
void Matrix3Mult(double a[][3],double b[][3],double c[][3])
{
int i;
int j;
int k;
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
c[i][j] = 0.0;
for (k=0;k<3;k++)
{
c[i][j] = c[i][j] + a[i][k] * b[k][j];
}
}
}
return;
}
/**
*@brief Description: Calculate two 4 x 4 matrix multiplication.
*@param[in] a a 4 x 4 matrix.
*@param[in] b a 4 x 4 matrix.
*@param[out] c result of a*b.
*@return No return value.
*@note:
*@warning:
*/
void Matrix4Mult(double a[][4], double b[][4], double c[][4])
{
int i;
int j;
int k;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
c[i][j] = 0.0;
for (k = 0; k < 4; k++)
{
c[i][j] = c[i][j] + a[i][k] * b[k][j];
}
}
}
return;
}
/**
*@brief Description: Calculate 3 x 3 matrix multiply a value.
*@param[in] a a 3 x 3 matrix.
*@param[in] Value a scalar value.
*@param[out] c result of a*Value.
*@return No return value.
*@note:
*@warning:
*/
void Matrix3MultValue(double a[][3], double Value, double c[][3])
{
int i;
int j;
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
c[i][j] = a[i][j] * Value;
}
}
return;
}
/**
*@brief Description: Calculate 4 x 4 matrix multiply a value.
*@param[in] a a 4 x 4 matrix.
*@param[in] Value a scalar value.
*@param[out] c result of a*Value.
*@return No return value.
*@note:
*@warning:
*/
void Matrix4MultValue(double a[][4], double Value, double c[][4])
{
int i;
int j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
c[i][j] = a[i][j] * Value;
}
}
return;
}
/**
*@brief Description:Computes the result of a 3 x 3 Matrix multiply a 3-vector.
*@param[in] R a 3 x 3 Matrix.
*@param[in] vec1 an input of 3-vector.
*@param[out] vec2 the output result of 3-vector.
*@return No return value.
*@note:
*@warning:
*/
void Matrix3MultVec(double R[3][3], double vec1[3], double vec2[3])
{
int i;
int j;
for (i=0;i<3;i++)
{
vec2[i] = 0;
for (j=0;j<3;j++)
{
vec2[i] = vec2[i] + R[i][j] * vec1[j];
}
}
return;
}
/**
*@brief Description:Computes a 3-vector add a 3-vector.
*@param[in] vec1 a 3-vector.
*@param[in] vec2 a 3-vector.
*@param[out] vec3 result of vec1 + vec2;
*@return No return value.
*@note:
*@warning:
*/
void Vec3Add(double vec1[3], double vec2[3], double vec3[3])
{
vec3[0] = vec1[0] + vec2[0];
vec3[1] = vec1[1] + vec2[1];
vec3[2] = vec1[2] + vec2[2];
return;
}
/**
*@brief Description:Computes result of two 3-vector cross product.
*@param[in] vec1 a first 3-vector.
*@param[in] vec2 a first 3-vector.
*@param[out] vec3 result of vec1 cross product vec2.
*@return No return value.
*@note:
*@warning:
*/
void Vec3Cross(double vec1[3],double vec2[3],double vec3[3])
{
vec3[0] = vec1[1] * vec2[2] - vec2[1] * vec1[2];
vec3[1] = -(vec1[0] * vec2[2] - vec2[0] * vec1[2]);
vec3[2] = vec1[0] * vec2[1] - vec2[0] * vec1[1];
return;
}
/**
*@brief Description:Computes a 3-vector multiply a scalar value.
*@param[in] vec1 a 3-vector.
*@param[in] value a scalar value.
*@param[out] vec2 result of vec1 * value.
*@return No return value.
*@note:
*@warning:
*/
void Vec3MultValue(double vec1[3], double value, double vec2[3])
{
vec2[0] = vec1[0] * value;
vec2[1] = vec1[1] * value;
vec2[2] = vec1[2] * value;
return;
}
/**
*@brief Description: Computes the norm of a 3-vector.
*@param[in] vec an input 3-vector.
*@return the norm of a an input 3-vector.
*@note:
*@warning:
*/
double Vec3Norm2(double vec[3])
{
return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
}
/**
*@brief Description: Computes the 2-norm of a n-vector.
*@param[in] n dimension of vector.
*@param[in] vec an input n-vector.
*@return the norm of a an input 3-vector.
*@note:
*@warning:
*/
double VecNorm2(int n,double *vec)
{
int i;
double tmp=0.0;
for (i=0;i<n;i++)
{
tmp = tmp + vec[i] * vec[i];
}
if (tmp<0.0)
{
tmp = 0;
}
return sqrt(tmp);
}
/**
*@brief Copy matrix from a to b .
*@param[in] a First matrix.
*@param[in] m rows of matrix a.
*@param[in] n columns of matrix a.
*@param[in] b Second matrix.
*@return No return value.
*@note:
*@warning:
*/
void MatrixCopy(const double *a, int m, int n, double *b)
{
memcpy(b, a, m*n * sizeof(double));
return;
}
/**
*@brief Computes Matrix transpose.
*@param[in] a a matrix.
*@param[in] m rows of matrix a.
*@param[in] n columns of matrix a.
*@param[out] b transpose of matrix a.
*@return No return value.
*@note:
*@waring:
*/
void MatrixT(double *a, int m, int n, double *b)
{
int i, j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
b[j*m + i] = a[i*n + j];
}
}
return;
}
/**
*@brief Computes matrix multiply.
*@param[in] a First matrix.
*@param[in] m rows of matrix a.
*@param[in] n columns of matrix b.
*@param[in] b Second matrix.
*@param[in] l columns of matrix b.
*@param[out] c result of a*b.
*@return No return value.
*@note:
*@waring:
*/
void MatrixMult(const double *a, int m, int n, const double *b, int l, double *c)
{
int i, j, k;
for (i = 0; i < m; i++)
{
for (j = 0; j < l; j++)
{
c[i*l + j] = 0.0;
for (k = 0; k < n; k++)
{
c[i*l + j] = c[i*l + j] + a[i*n + k] * b[k*l + j];
}
}
}
return;
}
/**
* @brief Description: Algorithm for Computing the roll-pitch-yaw angles(rotate around fix reference X,Y,Z axis).
* @param[in] R Rotation matrix.
* @param[out] roll Angles for rotate around fix reference X axis.
* @param[out] pitch Angles for rotate around fix reference Y axis.
* @param[out] yaw Angles for rotate around fix reference Z axis.
* @return No return value.
* @note:
*@warning:
*/
void RotToRPY(double R[3][3],double *roll,double *pitch,double *yaw)
{
if (fabs(1.0 + R[2][0]) < ZERO_ELEMENT)
{
*yaw = 0;
*pitch = PI / 2.0;
*roll = atan2(R[0][1], R[1][1]);
}
else if (fabs(1.0 - R[2][0]) < ZERO_ELEMENT)
{
*yaw = 0;
*pitch = -PI / 2.0;
*roll = atan2(R[0][1], R[1][1]);
}
else
{
*yaw = atan2(R[1][0], R[0][0]);
*pitch = atan2(-R[2][0], sqrt(R[0][0] * R[0][0] + R[1][0] * R[1][0]));
*roll = atan2(R[2][1], R[2][2]);
}
return;
}
/**
* @brief Description: Algorithm for Computing the rotation matrix of the roll-pitch-yaw angles.
* @param[in] roll Angles for rotate around fix reference X axis.
* @param[in] pitch Angles for rotate around fix reference Y axis.
* @param[in] yaw Angles for rotate around fix reference Z axis.
* @param[out] R Rotation matrix.
* @return No return value.
* @note:
*@warning:
*/
void RPYToRot(double roll, double pitch, double yaw, double R[3][3])
{
double alpha = yaw;
double beta = pitch;
double gamma = roll;
R[0][0] = cos(alpha)*cos(beta);
R[0][1] = cos(alpha)*sin(beta)*sin(gamma) - sin(alpha)*cos(gamma);
R[0][2] = cos(alpha)*sin(beta)*cos(gamma) + sin(alpha)*sin(gamma);
R[1][0] = sin(alpha)*cos(beta);
R[1][1] = sin(alpha)*sin(beta)*sin(gamma) + cos(alpha)*cos(gamma);
R[1][2] = sin(alpha)*sin(beta)*cos(gamma) - cos(alpha)*sin(gamma);
R[2][0] = -sin(beta);
R[2][1] = cos(beta)*sin(gamma);
R[2][2] = cos(beta)*cos(gamma);
return;
}
/**
*@brief Computes the inverse of the rotation matrix R.
*@param[in] R rotation matrix .
*@param[out] InvR inverse matrix of R.
*@return No return value.
*@note Input R must be a 3 x 3 rotation matrix.
*/
void RotInv(double R[3][3], double InvR[3][3])
{
int i;
int j;
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
InvR[i][j] = R[j][i];
}
}
return;
}
/**
*@brief Description:Returns the 3 x 3 skew-symmetric matrix corresponding to omg.
*@param[in] omg a 3-vector.
*@param[out] so3Mat the 3 x 3 skew-symmetric matrix corresponding to omg.
*@return No return value.
*@note:
*@warning:
*/
void VecToso3(double omg[3],double so3Mat[3][3])
{
so3Mat[0][0] = 0.0; so3Mat[0][1] = -omg[2]; so3Mat[0][2] = omg[1];
so3Mat[1][0] = omg[2]; so3Mat[1][1] = 0; so3Mat[1][2] = -omg[0];
so3Mat[2][0] = -omg[1]; so3Mat[2][1] = omg[0]; so3Mat[2][2] = 0.0;
return;
}
/**
*@brief Description:Returns the 3-vector corresponding to the 3 x 3 skew-symmetric matrix so3mat.
*@param[in] so3Mat a 3 x 3 skew-symmetric matrix so3mat.
*@param[out] omg the 3-vector.
*@return No return value.
*@note:
*@warning:
*/
void so3ToVec(double so3Mat[3][3], double omg[3])
{
omg[0] = so3Mat[2][1]; omg[1] = so3Mat[0][2]; omg[2] = so3Mat[1][0];
return;
}
/**
*@brief Description:Extracts the unit rotation axis omghat and the corresponding
* rotation angle theta from exponential coordinates omghat*theta for rotation, expc3.
*@param[in] expc3
*@param[out] omghat the unit vector of rotation axis .
*@param[out] theta rotation angle.
*@return No return value.
*@note:
*@warning:
*/
void AxisAng3(double expc3[3],double omghat[3],double *theta)
{
int i;
int ret = 0;
*theta = sqrt(expc3[0] * expc3[0] + expc3[1] * expc3[1] + expc3[2] * expc3[2]);
if (*theta<ZERO_ANGLE)
{
omghat[0] = 0.0;
omghat[1] = 0.0;
omghat[2] = 0.0;
*theta = 0.0;
return;
}
for (i=0;i<3;i++)
{
omghat[i]=expc3[i]/(*theta);
}
return ;
}
/**
*@brief Description:Computes the rotation matrix R in SO(3) corresponding to
* the matrix exponential of so3mat in so(3).
*@param[in] so3Mat [omghat]*theta,matrix exponential of so3mat in so(3).
*@param[out] R rotation matrix R in SO(3).
*@return No return value.
*@note:
*@warning:
*/
void MatrixExp3(double so3Mat[3][3],double R[3][3])
{
double omgtheta[3];
double omghat[3] = { 0 };
double theta = 0;
int ret = 0;
int i;
int j;
double MatI3[3][3] =
{
1,0,0,
0,1,0,
0,0,1
};
so3ToVec(so3Mat, omgtheta);
AxisAng3(omgtheta, omghat, &theta);
if (theta<ZERO_ANGLE)
{
Matrix3Equal(MatI3, R);
return ;
}
else
{
//calculate formula(3.51) in book [modern robotics : mechanics,planning,and control]
double omgmat[3][3];
double temp[3][3];
Matrix3MultValue(so3Mat, 1.0 / theta, omgmat);
Matrix3Mult(omgmat, omgmat, temp);
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
R[i][j] = MatI3[i][j] + sin(theta)*so3Mat[i][j] / theta + (1 - cos(theta))*temp[i][j];
}
}
}
return;
}
/**
*@brief Description:Computes the matrix logarithm so3mat in so(3) of the rotation matrix R in SO(3).
*@param[in] R the rotation matrix.
*@param[out] so3Mat matrix logarithm.
*@return No return value.
*@note:
*@warning:
*/
void MatrixLog3(double R[3][3],double so3Mat[3][3])
{
double omg[3] = { 0 };
double acosinput = (R[0][0] + R[1][1] + R[2][2] - 1.0) / 2.0;
if (fabs(acosinput - 1.0)<ZERO_VALUE)
{
memset(so3Mat, 0, 9 * sizeof(double));
}
else if (acosinput<=-1.0)
{
if ((1.0+R[2][2])>= ZERO_VALUE)
{
omg[0] = 1.0 / sqrt(2 * (1.0 + R[2][2]))*R[0][2];
omg[1] = 1.0 / sqrt(2 * (1.0 + R[2][2]))*R[1][2];
omg[2] = 1.0 / sqrt(2 * (1.0 + R[2][2]))*(1.0 + R[2][2]);
}
else if ((1.0+R[1][1]>= ZERO_VALUE))
{
omg[0] = 1.0 / sqrt(2 * (1.0 + R[1][1]))*R[0][1];
omg[1] = 1.0 / sqrt(2 * (1.0 + R[1][1]))*(1.0 + R[1][1]);
omg[2] = 1.0 / sqrt(2 * (1.0 + R[1][1]))*R[2][1];
}
else
{
omg[0] = 1.0 / sqrt(2 * (1.0 + R[0][0]))*(1.0 + R[0][0]);
omg[1] = 1.0 / sqrt(2 * (1.0 + R[0][0]))*R[1][0];
omg[2] = 1.0 / sqrt(2 * (1.0 + R[0][0]))*R[2][0];
}
omg[0] = PI*omg[0];
omg[1] = PI*omg[1];
omg[2] = PI*omg[2];
VecToso3(omg, so3Mat);
}
else
{
int i;
int j;
double theta = acos(acosinput);
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
so3Mat[i][j] = 1.0 / (2.0*sin(theta))*(R[i][j] - R[j][i])*theta;
}
}
}
return;
}
/**
*@brief Description:Builds the homogeneous transformation matrix T corresponding to a rotation
* matrix R in SO(3) and a position vector p in R3.
*@param[in] R a rotation matrix R in SO(3).
*@param[in] p a position vector p in R3.
*@param[out] T the homogeneous transformation matrix T.
*@return No return value.
*@note:
*@warning:
*/
void RpToTrans(double R[3][3], double p[3], double T[4][4])
{
int i;
int j;
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
T[i][j] = R[i][j];
}
}
T[0][3] = p[0];
T[1][3] = p[1];
T[2][3] = p[2];
T[3][0] = 0.0;
T[3][1] = 0.0;
T[3][2] = 0.0;
T[3][3] = 1.0;
return;
}
/**
*@brief Description: Extracts the rotation matrix R and position vector p
from a homogeneous transformation matrix T.
*@param[in] T a homogeneous transformation matrix.
*@param[out] R the rotation matrix.
*@param[out] p position vector.
*@return No return value.
*@note:
*@waring:
*/
void TransToRp(double T[4][4], double R[3][3], double p[3])
{
int i;
int j;
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
R[i][j] = T[i][j];
}
}
p[0] = T[0][3];
p[1] = T[1][3];
p[2] = T[2][3];
return;
}
/**
*@brief Description:Computes the inverse of a homogeneous transformation matrix T.
*@param[in] T a homogeneous transformation matrix.
*@param[out] InvT the inverse of T.
*@return No return value.
*@note:
*@warning:
*/
void TransInv(double T[4][4],double InvT[4][4])
{
double R[3][3];
double InvR[3][3];
double p[3];
double p2[3];
TransToRp(T, R, p);
RotInv(R, InvR);
Matrix3MultValue(InvR, -1.0, R);
Matrix3MultVec(R, p, p2);
RpToTrans(InvR, p2, InvT);
return;
}
/**
*@brief Description:Computes the se(3) matrix corresponding to a 6-vector twist V.
*@param[in] V a 6-vector twist V.
*@param[out] se3Mat the se(3) matrix.
*@return No return value.
*@note:
*@warning:
*/
void VecTose3(double V[6], double se3Mat[4][4])
{
double so3Mat[3][3];
double omg[3];
int i;
int j;
omg[0] = V[0];
omg[1] = V[1];
omg[2] = V[2];
VecToso3(omg, so3Mat);
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
se3Mat[i][j] = so3Mat[i][j];
}
}
se3Mat[0][3] = V[3];
se3Mat[1][3] = V[4];
se3Mat[2][3] = V[5];
se3Mat[3][0] = 0.0;
se3Mat[3][1] = 0.0;
se3Mat[3][2] = 0.0;
se3Mat[3][3] = 0.0;
return;
}
/**
*@brief Description:Computes the 6-vector twist corresponding to an se(3) matrix se3mat.
*@param[in] se3Mat an se(3) matrix.
*@param[out] V he 6-vector twist.
*@return No return value.
*@note:
*@warning:
*/
void se3ToVec(double se3Mat[4][4],double V[6])
{
V[0] = se3Mat[2][1];
V[1] = se3Mat[0][2];
V[2] = se3Mat[1][0];
V[3] = se3Mat[0][3];
V[4] = se3Mat[1][3];
V[5] = se3Mat[2][3];
return;
}
/**
*@brief Description:Computes the 6 x 6 adjoint representation [AdT ]
of the homogeneous transformation matrix T.
*@param[in] T a homogeneous transformation matrix.
*@param[out] AdT the 6 x 6 adjoint representation [AdT ].
*@return No return value.
*@note:
*@warning:
*/
void Adjoint(double T[4][4], double AdT[6][6])
{
double R[3][3];
double p[3];
double so3Mat[3][3];
int i;
int j;
TransToRp(T, R, p);
VecToso3(p, so3Mat);
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
AdT[i][j] = R[i][j];
}
}
for (i = 0; i < 3; i++)
{
for (j = 3; j < 6; j++)
{
AdT[i][j] = 0.0;
}
}
for (i=3;i<6;i++)
{
for (j = 3; j < 6; j++)
{
AdT[i][j] = R[i-3][j-3];
}
}
double mat[3][3];
Matrix3Mult(so3Mat, R, mat);
for (i = 3; i < 6; i++)
{
for (j = 0; j < 3; j++)
{
AdT[i][j] = mat[i-3][j];
}
}
return;
}
/**
*@brief Description: Computes a normalized screw axis representation S of a screw described by
* a unit vector s in the direction of the screw axis, located at the point q, with pitch h.
*@param[in] q a point lying on the screw axis.
*@param[in] s a unit vector in the direction of the screw axis.
*@param[in] h the pitch of the screw axis.
*@param[in] S a normalized screw axis representation.
*@return No return value.
*@note:
*@warning:
*/
void ScrewToAxis(double q[3], double s[3], double h,double S[6])
{
double v[3];
double temp[3];
Vec3Cross(s, q, temp);
Vec3MultValue(temp, -1.0, temp);
Vec3MultValue(s, h, v);
Vec3Add(v, temp, v);
S[0] = s[0];
S[1] = s[1];
S[2] = s[2];
S[3] = v[0];
S[4] = v[1];
S[5] = v[2];
return;
}
/**
*@brief Description: Extracts the normalized screw axis S and the distance traveled along the screw
theta from the 6-vector of exponential coordinates S*theta.
*@param[in] expc6 the 6-vector of exponential coordinates.
*@param[out] S the normalized screw axis.
*@param[out] theta the distance traveled along the screw.
*@return No return value.
*@note:
*@warning:
*/
void AxisAng6(double expc6[6],double S[6],double *theta)
{
*theta = Vec3Norm2(expc6);
if (*theta<ZERO_ANGLE)
{
*theta = Vec3Norm2(&expc6[3]);
if (*theta<ZERO_DISTANCE)
{
*theta=0.0;
//S is undefine,no motion at all.
S[0] = 0.0; S[1] = 0.0; S[2] = 0.0; S[3] = 0.0; S[4] = 0.0; S[5] = 0.0;
return;
}
}
Vec3MultValue(expc6, 1.0 / (*theta), S);
Vec3MultValue(&expc6[3], 1.0 / (*theta), &S[3]);
return ;
}
/**
*@brief Description: Computes the homogeneous transformation matrix T in SE(3) corresponding to
* the matrix exponential of se3mat in se(3).
*@param[in] se3mat the matrix exponential of se3mat in se(3).
*@param[out] T the homogeneous transformation matrix T in SE(3).
*@return No return value.
*@note:
*@warning:
*/
void MatrixExp6(double se3Mat[4][4], double T[4][4])
{
int i;
int j;
double so3mat[3][3];
double omgmat[3][3];
double temp[3][3];
double Gtheta[3][3];
double p[3];
double v[3];
double omgtheta[3];
double omghat[3];
double theta;
double MatI3[3][3] =
{
1.0,0.0,0.0,
0.0,1.0,0.0,
0.0,0.0,1.0
};
TransToRp(se3Mat, so3mat, p);//extracts so3mat from se3mat
so3ToVec(so3mat, omgtheta);
if (Vec3Norm2(omgtheta)<ZERO_ANGLE)
{
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
T[i][j] = MatI3[i][j];
}
}
T[0][3] = se3Mat[0][3];
T[1][3] = se3Mat[1][3];
T[2][3] = se3Mat[2][3];
T[3][0] = 0.0;
T[3][1] = 0.0;
T[3][2] = 0.0;
T[3][3] = 1.0;
}
else
{
AxisAng3(omgtheta, omghat, &theta);
MatrixExp3(so3mat, temp);
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
T[i][j] = temp[i][j];
}
}
Matrix3MultValue(so3mat, 1.0/theta,omgmat);
Matrix3Mult(omgmat, omgmat, temp);
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
Gtheta[i][j] = MatI3[i][j] * theta + (1.0 - cos(theta))*omgmat[i][j] + (theta - sin(theta))*temp[i][j];
}
}
v[0] = p[0] / theta;
v[1] = p[1] / theta;
v[2] = p[2] / theta;
Matrix3MultVec(Gtheta, v, p);
T[0][3] = p[0]; T[1][3] = p[1]; T[2][3] = p[2];
T[3][0] = 0.0;
T[3][1] = 0.0;
T[3][2] = 0.0;
T[3][3] = 1.0;
}
return;
}
/**
*@brief Description: Computes the matrix logarithm se3mat in se(3) of
the homogeneous transformation matrix T in SE(3)
*@param[in] T the homogeneous transformation matrix.
*@param[out] se3Mat the matrix logarithm of T.
*@return No return value.
*@note:
*@warning:
*/
void MatrixLog6(double T[4][4], double se3Mat[4][4])
{
int i;
int j;
double R[3][3];
double so3mat[3][3];
double p[3];
TransToRp(T, R, p);
MatrixLog3(R, so3mat);
int flag = 0;
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
if (fabs(so3mat[i][j])<ZERO_ELEMENT)
{
continue;
}
else
{
flag = 1;
break;
}
}
}
if (!flag)
{
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
se3Mat[i][j] = 0.0;
}
}
se3Mat[0][3] = T[0][3];
se3Mat[1][3] = T[1][3];
se3Mat[2][3] = T[2][3];
se3Mat[3][0] = 0.0;
se3Mat[3][1] = 0.0;
se3Mat[3][2] = 0.0;
se3Mat[3][3] = 0.0;
}
else
{
double MatI3[3][3] =
{
1.0,0.0,0.0,
0.0,1.0,0.0,
0.0,0.0,1.0
};
double v[3];
double temp[3][3];
double InvGtheta[3][3];
double theta = acos((R[0][0] + R[1][1] + R[2][2] - 1.0) / 2.0);
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
{
se3Mat[i][j] = so3mat[i][j];
}
}
Matrix3Mult(so3mat, so3mat, temp);
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
InvGtheta[i][j] = MatI3[i][j] - 0.5*so3mat[i][j] + (1.0 / theta - 0.5*1.0 / tan(0.5*theta))*temp[i][j] / theta;
}
}
Matrix3MultVec(InvGtheta, p, v);
se3Mat[0][3] = v[0];
se3Mat[1][3] = v[1];
se3Mat[2][3] = v[2];
se3Mat[3][0] = 0.0;
se3Mat[3][1] = 0.0;
se3Mat[3][2] = 0.0;
se3Mat[3][3] = 0.0;
}
return ;
}
/**
*@brief Description: Computes the end-effector frame given the zero position of the end-effector M,
* the list of joint screws Slist expressed in the fixed-space frame, and the list of joint values thetalist.
*@param[in] M the zero position of the end-effector expressed in the fixed-space frame.
*@param[in] Joint Num the number of joints.
*@param[in] Slist the list of joint screws Slist expressed in the fixed-space frame.
* in the format of a matrix with the screw axes as the column.
*@param[in] thetalist the list of joint values.
*@param[out] T the end-effector frame expressed in the fixed-space frame.
*@return No return value.
*@note: when Slist is a matrix ,make sure that columns number of Slist is equal to JointNum,
* rows number of Slist 6 .The function call should be written as
* FKinBody(...,(double *)Slist,...).
*@warning:
*/
void FKinSpace(double M[4][4],int JointNum,double *Slist, double *thetalist,double T[4][4])
{
int i, j, k, l;
double se3mat[4][4];
double T2[4][4];
double exp6[4][4];
double V[6];
Matrix4Equal(M, T);
for (i= JointNum-1;i>=0;i--)
{
for (l=0;l<6;l++)
{
V[l] = Slist[l*JointNum+i];//get each column of Slist.
}
VecTose3(V, se3mat);
for (j=0;j<4;j++)
{
for (k=0;k<4;k++)
{
se3mat[j][k] = se3mat[j][k] * thetalist[i];
}
}
MatrixExp6(se3mat, exp6);
Matrix4Mult(exp6, T, T2);
Matrix4Equal(T2, T);
}
return ;
}
/**
*@brief Description:Computes the end-effector frame given the zero position of the end-effector M,
* the list of joint screws Blist expressed in the end-effector frame, and the list of joint values thetalist.
*@param[in] M the zero position of the end-effector expressed in the end-effector frame.
*@param[in] JointNum the number of joints.
*@param[in] Blist the list of joint screws Slist expressed in the end-effector frame.
* in the format of a matrix with the screw axes as the column.
*@param[in] thetalist the list of joint values.
*@param[out] T the end-effector frame expressed in the end-effector frame.
*@return No return value.
*@note: when Blist is a matrix ,make sure that columns number of Slist is equal to JointNum,
* rows number of Slist 6 .The function call should be written as
* FKinBody(...,(double *)Blist,...).
*@warning:
*/
void FKinBody(double M[4][4], int JointNum, double *Blist, double thetalist[], double T[4][4])
{
int i, j, k, l;
double se3mat[4][4];
double T2[4][4];
double exp6[4][4];
double V[6];
Matrix4Equal(M, T);
for (i = 0; i < JointNum ; i++)
{
for (l = 0; l < 6; l++)
{
V[l] = Blist[l*JointNum + i];//get each column of Slist.
}
VecTose3(V, se3mat);
for (j = 0; j < 4; j++)
{
for (k = 0; k < 4; k++)
{
se3mat[j][k] = se3mat[j][k] * thetalist[i];
}
}
MatrixExp6(se3mat, exp6);
Matrix4Mult(T, exp6, T2);
Matrix4Equal(T2, T);
}
return ;
}
/**
*@brief Description: Computes the body Jacobian Jb(theta) in 6×n given a list of joint screws Bi
expressed in the body frame and a list of joint angles.
*@param[in] Blist The joint screw axes in the end - effector frame when the manipulator is
* at the home position, in the format of a matrix with the screw axes as the row.
*@param[in] thetalist A list of joint coordinates.
*@param[out] Jb Body Jacobian matrix.
*@return No return value.
*@note: when Blist and Jb are matrixes ,make sure that columns number of Slist or Jb is equal to JointNum,
* rows number of Slist or Jb is 6 .The function call should be written as
* JacobianSpace(JointNum,(double *)Slist,thetalist,(double *)Jb).
*@warning:
*/
void JacobianBody(int JointNum,double *Blist, double *thetalist,double *Jb)
{
int i;
int j;
int k;
double T1[4][4];
double T2[4][4];
double se3mat[4][4];
double V[6];
double AdT[6][6];
double T[4][4] = {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1
};
//Fist column of Jbn.
for (i=0;i<6;i++)
{
Jb[i*JointNum+JointNum -1] = Blist[i*JointNum + JointNum-1];
}
//Jbi for i=n-1,n-2,...,1.
for (i= JointNum -2;i>=0;i--)
{
for (j=0;j<6;j++)
{
V[j] = -1.0*Blist[j*JointNum+i+1];
}
VecTose3(V, se3mat);
Matrix4MultValue(se3mat, thetalist[i + 1], se3mat);
MatrixExp6(se3mat, T1);
Matrix4Mult(T, T1,T2);
Matrix4Equal(T2, T);
Adjoint(T, AdT);
for (j=0;j<6; j++)
{
Jb[j*JointNum + i] = 0;
for (k=0;k<6;k++)
{
Jb[j*JointNum + i] = Jb[j*JointNum + i] + AdT[j][k] * Blist[k*JointNum + i];
}
}
}
return ;
}
/**
*@brief Description:Computes the space Jacobian Js(theta) in R6 x n given a list of joint screws Si
* expressed in the fixed space frame and a list of joint angles.
*@param[in] JointNum joints number.
*@param[in] Slist The joint screw axes expressed in the fixed space frame when the manipulator is
* at the home position, in the format of a matrix with the screw axes as the column.
*@param[in] thetalist A list of joint coordinates.
*@param[out] Js Space Jacobian matrix.
*@return No return value.
*@note: when Slist and Js are matrices ,make sure that columns number of Slist or Js is equal to JointNum,
* rows number of Slist or Js is 6 .The function call should be written as
* JacobianSpace(JointNum,(double *)Slist,thetalist,(double *)Js).
*@warning:
*/
void JacobianSpace(int JointNum, double *Slist, double *thetalist, double *Js)
{
int i;
int j;
int k;
double T1[4][4];
double T2[4][4];
double se3mat[4][4];
double V[6];
double AdT[6][6];
double T[4][4] = {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1
};
//Fist column of Js.
for (i = 0; i < 6; i++)
{
Js[i*JointNum + 0] = Slist[i*JointNum + 0];
}
//Jsi for i=2,3,...,n.
for (i = 1; i <JointNum; i++)
{
for (j = 0; j < 6; j++)
{
V[j] = Slist[j*JointNum + i - 1];
}
VecTose3(V, se3mat);
Matrix4MultValue(se3mat, thetalist[i - 1], se3mat);
MatrixExp6(se3mat, T1);
Matrix4Mult(T, T1, T2);
Matrix4Equal(T2, T);
Adjoint(T, AdT);
for (j = 0; j < 6; j++)
{
Js[j*JointNum + i] = 0;
for (k = 0; k < 6; k++)
{
Js[j*JointNum + i] = Js[j*JointNum + i] + AdT[j][k] * Slist[k*JointNum + i];
}
}
}
return;
}
#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
#define MAX(a,b) (a>b?a:b)
#define MIN(a,b) (a<b?a:b)
/**
*@brief Computes (a^2+b^2)^(1/2),
*@param[in] a
*@param[in] b
*@note:
*@warning:
*/
double pythag(const double a, const double b)
{
double absa, absb;
absa = fabs(a);
absb = fabs(b);
if (absa > absb) return absa*sqrt(1.0 + (absb / absa)*(absb / absa));
else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0 + (absa / absb)*(absa / absb)));
}
void reorder(double *u,int m,int n,double *w,double *v)
{
/*Given the output of decompose, this routine sorts the singular values, and corresponding columns
of u and v, by decreasing magnitude.Also, signs of corresponding columns are flipped so as to
maximize the number of positive elements.*/
int i, j, k, s, inc = 1;
double sw;
double *su = (double *)malloc(m * sizeof(double));
if (su==NULL)
{
return;
}
double *sv = (double *)malloc(n * sizeof(double));
if (sv==NULL)
{
free(su);
return;
}
do { inc *= 3; inc++; } while (inc <= n);// Sort.The method is Shells sort.(The work is negligible as compared to that already done in decompose.)
do {
inc /= 3;
for (i = inc; i < n; i++) {
sw = w[i];
for (k = 0; k < m; k++) su[k] = u[k*n + i];
for (k = 0; k < n; k++) sv[k] = v[k*n + i];
j = i;
while (w[j - inc] < sw) {
w[j] = w[j - inc];
for (k = 0; k < m; k++) u[k*n + j] = u[k*n + j - inc];
for (k = 0; k < n; k++) v[k*n + j] = v[k*n + j - inc];
j -= inc;
if (j < inc) break;
}
w[j] = sw;
for (k = 0; k < m; k++) u[k*n + j] = su[k];
for (k = 0; k < n; k++) v[k*n + j] = sv[k];
}
} while (inc > 1);
for (k = 0; k < n; k++) {
//Flip signs.
s = 0;
for (i = 0; i < m; i++) if (u[i*n + k] < 0.0) s++;
for (j = 0; j < n; j++) if (v[j*n + k] < 0.0) s++;
if (s > (m + n) / 2) {
for (i = 0; i < m; i++) u[i*n + k] = -u[i*n + k];
for (j = 0; j < n; j++) v[j*n + k] = -v[j*n + k];
}
}
free(su);
free(sv);
return;
}
/**
*@brief Given the matrix a,this routine computes its singular value decomposition.
*@param[in/out] a input matrix a or output matrix u.
*@param[in] m number of rows of matrix a.
*@param[in] n number of columns of matrix a.
*@param[in] tol any singular values less than a tolerance are treated as zero.
*@param[out] w output vector w.
*@param[out] v output matrix v.
*@return No return value.
*@note: input a must be a m rows and n columns matrix,w is n-vector,v is a n rows and n columns matrix.
*@warning:
*/
int svdcmp(double *a, int m, int n, double tol, double *w, double *v)
{
int flag, i, its, j, jj, k, l, nm;
double anorm, c, f, g, h, s, scale, x, y, z;
double *rv1 = (double *)malloc(n * sizeof(double));
if (rv1==NULL)
{
return 1;
}
g = scale = anorm = 0.0;
for (i=0;i<n;i++)//Householder reduction to bidiagonal form.
{
l = i + 2;
rv1[i] = scale*g;
g = s = scale = 0.0;
if (i<m)
{
for (k = i; k < m; k++)scale += fabs(a[k*n + i]);
if (scale!=0.0)
{
for (k = i; k < m;k++)
{
a[k*n + i] /= scale;
s += a[k*n + i] * a[k*n + i];
}
f = a[i*n + i];
g = -SIGN(sqrt(s), f);
h = f*g - s;
a[i*n + i] = f - g;
for (j=l-1;j<n;j++)
{
for (s = 0.0, k = i; k < m;k++)
{
s += a[k*n + i] * a[k*n + j];
}
f = s / h;
for (k = i; k < m;k++)
{
a[k*n + j] += f*a[k*n + i];
}
}
for (k = i; k < m;k++)
{
a[k*n + i] *= scale;
}
}
}
w[i] = scale*g;
g = s = scale = 0.0;
if (i+1 <= m && (i+1)!=n)
{
for (k=l-1;k<n;k++)
{
scale += fabs(a[i*n + k]);
}
if (scale!=0.0)
{
for (k=l-1;k<n;k++)
{
a[i*n + k] /= scale;
s += a[i*n + k] * a[i*n + k];
}
f = a[i*n + l - 1];
g = -SIGN(sqrt(s), f);
h = f*g - s;
a[i*n + l - 1] = f - g;
for (k=l-1;k<n;k++)
{
rv1[k] = a[i*n + k] / h;
}
for (j = l - 1; j < m; j++)
{
for (s = 0.0, k = l - 1; k < n; k++)
{
s += a[j*n + k] * a[i*n + k];
}
for (k = l - 1; k < n; k++)
{
a[j*n + k] += s*rv1[k];
}
}
for (k=l-1;k<n;k++)
{
a[i*n + k] *= scale;
}
}
}
anorm = MAX(anorm, (fabs(w[i]) + fabs(rv1[i])));
}
for (i=n-1;i>=0;i--)//Accumulation of right-hand transformations.
{
if (i<n-1)
{
if (g!=0.0)
{
for (j = l;j<n;j++)//Double division to avoid possible underflow.
{
v[j*n + i] = (a[i*n + j] / a[i*n + l]) / g;
}
for (j = l;j<n;j++)
{
for (s = 0.0, k = l;k<n;k++)
{
s += a[i*n + k] * v[k*n + j];
}
for (k = l;k<n;k++)
{
v[k*n + j] += s*v[k*n + i];
}
}
}
for (j = l;j<n;j++)
{
v[i*n + j] = v[j*n + i] = 0.0;
}
}
v[i*n + i] = 1.0;
g = rv1[i];
l = i;
}
for (i=MIN(m,n)-1;i>=0;i--)//Accumulation of left-hand transformations.
{
l = i + 1;
g = w[i];
for (j = l;j<n;j++)
{
a[i*n + j] = 0.0;
}
if (g!=0.0)
{
g = 1.0 / g;
for (j = l;j<n;j++)
{
for (s = 0.0, k = l; k < m;k++)
{
s += a[k*n + i] * a[k*n + j];
}
f = (s / a[i*n + i])*g;
for (k = i; k < m;k++)
{
a[k*n + j] += f*a[k*n + i];
}
}
for (j = i; j < m;j++)
{
a[j*n + i] *= g;
}
}
else
{
for (j = i; j < m;j++)
{
a[j*n + i] = 0.0;
}
}
++a[i*n + i];
}
for (k=n-1;k>=0;k--)
{
/* Diagonalization of the bidiagonal form: Loop over
singular values, and over allowed iterations. */
for (its=0;its<30;its++)
{
flag = 1;
for (l = k;l>=0;l--)//Test for splitting.
{
nm = l - 1;
if (l==0 || fabs(rv1[l])<= tol*anorm)
{
flag = 0;
break;
}
if (fabs(w[nm]) <=tol*anorm)break;
}
if (flag)//Cancellation of rv1[l], if l > 0.
{
c = 0.0;
s = 1.0;
for (i=l;i<k+1;i++)
{
f = s*rv1[i];
rv1[i] = c*rv1[i];
if (fabs(f) <= tol*anorm)break;
g = w[i];
h = pythag(f, g);
w[i] = h;
h = 1.0 / h;
c = g*h;
s = -f*h;
for (j = 0; j < m;j++)
{
y = a[j*n + nm];
z = a[j*n + i];
a[j*n + nm] = y*c + z*s;
a[j*n + i] = z*c - y*s;
}
}
}
z = w[k];
if (l==k)//Convergence
{
if (z<0.0)//Singular value is made nonnegative..
{
w[k] = -z;
for (j=0;j<n;j++)
{
v[j*n + k] = -v[j*n + k];
}
}
break;
}
//if (its==29)
//{
// printf("no convergence in 30 svdcmp iterations\n");
//}
x = w[l]; //Shift from bottom 2-by-2 minor.
nm = k - 1;
y = w[nm];
g = rv1[nm];
h = rv1[k];
f = ((y - z)*(y + z) + (g - h)*(g + h)) / (2.0*h*y);
g = pythag(f, 1.0);
f = ((x - z)*(x + z) + h*((y / (f + SIGN(g, f))) - h)) / x;
c = s = 1.0;
for (j = l;j<=nm;j++)//Next QR transformation:
{
i = j + 1;
g = rv1[i];
y = w[i];
h = s*g;
g = c*g;
z = pythag(f, h);
rv1[j] = z;
c = f / z;
s = h / z;
f = x*c + g*s;
g = g*c - x*s;
h = y*s;
y *= c;
for (jj=0;jj<n;jj++)
{
x = v[jj*n + j];
z = v[jj*n + i];
v[jj*n + j] = x*c + z*s;
v[jj*n + i] = z*c - x*s;
}
z = pythag(f, h);
w[j] = z;
if (z)//Rotation can be arbitrary if z = 0.
{
z = 1.0 / z;
c = f*z;
s = h*z;
}
f = c*g + s*y;
x = c*y - s*g;
for (jj = 0; jj < m;jj++)
{
y = a[jj*n + j];
z = a[jj*n + i];
a[jj*n + j] = y*c + z*s;
a[jj*n + i] = z*c - y*s;
}
}
rv1[l] = 0.0;
rv1[k] = f;
w[k] = x;
}
}
free(rv1);
reorder(a, m, n, w, v);//对特征值按降序排列,且调整对应矩阵
return 0;
}
double u[PINV_MAX * PINV_MAX] = { 0 };
double w[PINV_MAX] = { 0 };
double vw[PINV_MAX * PINV_MAX] = { 0 };
double v[PINV_MAX * PINV_MAX] = { 0 };
double uT[PINV_MAX * PINV_MAX] = { 0 };
/**
*@brief Computes Moore-Penrose pseudoinverse by Singular Value Decomposition (SVD) algorithm.
*@param[in] a an arbitrary order matrix.
*@param[in] m rows.
*@param[in] n columns.
*@param[in] tol any singular values less than a tolerance are treated as zero.
*@param[out] b Moore-Penrose pseudoinverse of matrix a.
*@return 0:success,Nonzero:failure.
*@retval 0 success.
*@retval 1 failure when use malloc to allocate memory.
*@note:
*@warning:
*/
int MatrixPinv(const double *a, int m, int n, double tol, double *b)
{
int i, j;
int ret;
memcpy(u, a, m*n * sizeof(double));
ret=svdcmp(u, m, n, tol,w, v);
for (i = 0; i < n; i++)
{
if (w[i] <= tol)
{
w[i] = 0;
}
else
{
w[i] = 1.0 / w[i];
}
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
vw[i*n + j] = v[i*n + j] * w[j];
}
}
MatrixT(u, m, n, uT);
MatrixMult(vw, n, n, uT, m, b);
return 0;
}
/**
*@brief Description:use an iterative Newton-Raphson root-finding method.
*@param[in] JointNum Number of joints.
*@param[in] Blist The joint screw axes in the Body frame when the manipulator
* is at the home position, in the format of a matrix with the
* screw axes as the columns.
*@param[in] M The home configuration of the end-effector.
*@param[in] T The desired end-effector configuration Tsd.
*@param[in] thetalist0 An initial guess of joint angles that are close to satisfying Tsd.
*@param[in] eomg A small positive tolerance on the end-effector orientation error.
* The returned joint angles must give an end-effector orientation error less than eomg.
*@param[in] ev A small positive tolerance on the end-effector linear position error. The returned
* joint angles must give an end-effector position error less than ev.
*@param[in] maxiter The maximum number of iterations before the algorithm is terminated.
*@param[out] thetalist Joint angles that achieve T within the specified tolerances.
*@return 0:success,Nonzero:failure
*@retval 0 success.
*@retval 1 The maximum number of iterations reach before the algorithm is terminated.
*@retval 2 failure to allocate memory for Jacobian matrix.
*@note:
*@warning:
*/
int IKinBodyNR(int JointNum, double *Blist, double M[4][4], double T[4][4], double *thetalist0, double eomg, double ev, int maxiter, double *thetalist)
{
int i, j;
double Tsb[4][4];
double iTsb[4][4];
double Tbd[4][4];
double se3Mat[4][4];
double Vb[6];
int ErrFlag;
double *Jb = (double *)malloc(JointNum * 6 * sizeof(double));
if (Jb == NULL)
{
return 2;
}
double *pJb = (double *)malloc(JointNum * 6 * sizeof(double));
if (pJb == NULL)
{
free(Jb);
return 2;
}
double *dtheta = (double *)malloc(JointNum * sizeof(double));
if (dtheta == NULL)
{
free(Jb);
free(pJb);
return 2;
}
MatrixCopy(thetalist0, JointNum, 1, thetalist);
FKinBody(M, JointNum, Blist, thetalist, Tsb);
TransInv(Tsb, iTsb);
Matrix4Mult(iTsb,T,Tbd);
MatrixLog6(Tbd, se3Mat);
se3ToVec(se3Mat, Vb);
ErrFlag = VecNorm2(3, &Vb[0]) > eomg || VecNorm2(3, &Vb[3]) > ev;
i = 0;
#if(DEBUGMODE)
///////////////////Debug///////////
printf("iteration:%4d thetalist: ", i);
int k;
for (k = 0; k < JointNum; k++)
{
printf("%4.6lf\t", thetalist[k]);
}
printf("\n");
////////////////////////////////////
#endif
while (ErrFlag && i<maxiter)
{
JacobianBody(JointNum, Blist, thetalist, Jb);
MatrixPinv(Jb, 6, JointNum, 2.2E-15, pJb);
MatrixMult(pJb, JointNum,6 , Vb, 1, dtheta);
for (j=0;j<JointNum;j++)
{
thetalist[j] = thetalist[j] + dtheta[j];
}
i++;
FKinBody(M, JointNum, Blist, thetalist, Tsb);
TransInv(Tsb, iTsb);
Matrix4Mult(iTsb, T, Tbd);
MatrixLog6(Tbd, se3Mat);
se3ToVec(se3Mat, Vb);
ErrFlag = VecNorm2(3, &Vb[0]) > eomg || VecNorm2(3, &Vb[3]) > ev;
#if (DEBUGMODE)
///////////////////////DEBUG///////////
printf("iteration:%4d thetalist: ", i);
for (k = 0; k < JointNum; k++)
{
printf("%4.6lf\t", thetalist[k]);
}
printf("\n");
//////////////////////////////////////
#endif
}
free(Jb);
free(pJb);
free(dtheta);
return ErrFlag;
}
/**
*@brief Description:use an iterative Newton-Raphson root-finding method.
*@param[in] JointNum Number of joints.
*@param[in] Slist The joint screw axes in the space frame when the manipulator
* is at the home position, in the format of a matrix with the
* screw axes as the columns.
*@param[in] M The home configuration of the end-effector.
*@param[in] T The desired end-effector configuration Tsd.
*@param[in] thetalist0 An initial guess of joint angles that are close to satisfying Tsd.
*@param[in] eomg A small positive tolerance on the end-effector orientation error.
* The returned joint angles must give an end-effector orientation error less than eomg.
*@param[in] ev A small positive tolerance on the end-effector linear position error. The returned
* joint angles must give an end-effector position error less than ev.
*@param[in] maxiter The maximum number of iterations before the algorithm is terminated.
*@param[out] thetalist Joint angles that achieve T within the specified tolerances.
*@return 0:success,Nonzero:failure
*@retval 0
*@note :
*@warning:
*/
int IKinSpaceNR(int JointNum, double *Slist, double M[4][4], double T[4][4], double *thetalist0, double eomg, double ev, int maxiter,double *thetalist)
{
int i, j;
double Tsb[4][4];
double iTsb[4][4];
double Tbd[4][4];
double AdT[6][6];
double se3Mat[4][4];
double Vb[6];
double Vs[6];
int ErrFlag;
double *Js = (double *)malloc(JointNum * 6 * sizeof(double));
if (Js == NULL)
{
return 2;
}
double *pJs = (double *)malloc(JointNum * 6 * sizeof(double));
if (pJs == NULL)
{
free(Js);
return 2;
}
double *dtheta = (double *)malloc(JointNum * sizeof(double));
if (dtheta == NULL)
{
free(Js);
free(pJs);
return 2;
}
MatrixCopy(thetalist0, JointNum, 1, thetalist);
FKinSpace(M, JointNum, Slist, thetalist, Tsb);
TransInv(Tsb, iTsb);
Matrix4Mult(iTsb, T, Tbd);
MatrixLog6(Tbd, se3Mat);
se3ToVec(se3Mat, Vb);
Adjoint(Tsb, AdT);
MatrixMult((double *)AdT, 6, 6, Vb, 1, Vs);
ErrFlag = VecNorm2(3, &Vs[0]) > eomg || VecNorm2(3, &Vs[3]) > ev;
i = 0;
#if(DEBUGMODE)
///////////////////Debug///////////
printf("iteration:%4d thetalist: ", i);
int k;
for (k = 0; k < JointNum; k++)
{
printf("%4.4lf, ", thetalist[k]);
}
printf("\n");
////////////////////////////////////
#endif
while (ErrFlag && i < maxiter)
{
JacobianSpace(JointNum, Slist, thetalist, Js);
MatrixPinv(Js, 6, JointNum, 2.2E-15, pJs);
MatrixMult(pJs, JointNum, 6, Vs, 1, dtheta);
for (j = 0; j < JointNum; j++)
{
thetalist[j] = thetalist[j] + dtheta[j];
}
i++;
FKinSpace(M, JointNum, Slist, thetalist, Tsb);
TransInv(Tsb, iTsb);
Matrix4Mult(iTsb, T, Tbd);
MatrixLog6(Tbd, se3Mat);
se3ToVec(se3Mat, Vb);
Adjoint(Tsb, AdT);
MatrixMult((double *)AdT, 6, 6, Vb, 1, Vs);
ErrFlag = VecNorm2(3, &Vs[0]) > eomg || VecNorm2(3, &Vs[3]) > ev;
#if (DEBUGMODE)
///////////////////////DEBUG///////////
printf("iteration:%4d thetalist: ", i);
for (k = 0; k < JointNum; k++)
{
printf("%4.4lf, ", thetalist[k]);
}
printf("\n");
//////////////////////////////////////
#endif
}
free(Js);
free(pJs);
free(dtheta);
return ErrFlag;
}
/**
* @brief Description: Algorithm for Computing the ZYX Euler Angles according to rotation matrix.
* @param[in] R Rotation matrix.
* @param[out] alpha Angles for rotation around Z axis.
* @param[out] beta Angles for rotation around Y axis.
* @param[out] gamma Angles for rotation around X axis.
* @return No return value.
* @note:
*@warning:
*/
void RotToZYXEulerAngle(double R[3][3], double *alpha, double *beta, double *gamma)
{
if (fabs(1.0 + R[2][0])<ZERO_ELEMENT)
{
*alpha = 0;
*beta = PI / 2.0;
*gamma = atan2(R[0][1], R[1][1]);
}
else if (fabs(1.0 - R[2][0])<ZERO_ELEMENT)
{
*alpha = 0;
*beta = -PI / 2.0;
*gamma = atan2(R[0][1], R[1][1]);
}
else
{
*alpha = atan2(R[1][0], R[0][0]);
*beta = atan2(-R[2][0], sqrt(R[0][0] * R[0][0] + R[1][0] * R[1][0]));
*gamma = atan2(R[2][1], R[2][2]);
}
return;
}
/**
* @brief Description: Algorithm for Computing the rotation matrix of ZYX Euler Angles.
* @param[in] alpha Angles for rotation around Z axis.
* @param[in] beta Angles for rotation around Y axis.
* @param[in] gamma Angles for rotation around X axis.
* @param[out] R Rotation matrix.
* @return No return value.
* @note:
* @waring:
*/
void ZYXEulerAngleToRot(double alpha, double beta, double gamma, double R[3][3])
{
R[0][0] = cos(alpha)*cos(beta);
R[0][1] = cos(alpha)*sin(beta)*sin(gamma) - sin(alpha)*cos(gamma);
R[0][2] = cos(alpha)*sin(beta)*cos(gamma) + sin(alpha)*sin(gamma);
R[1][0] = sin(alpha)*cos(beta);
R[1][1] = sin(alpha)*sin(beta)*sin(gamma) + cos(alpha)*cos(gamma);
R[1][2] = sin(alpha)*sin(beta)*cos(gamma) - cos(alpha)*sin(gamma);
R[2][0] = -sin(beta);
R[2][1] = cos(beta)*sin(gamma);
R[2][2] = cos(beta)*cos(gamma);
return;
}
/**
* @brief Description: Computes the unit vector of Euler axis and rotation angle corresponding to rotation matrix.
* @param[in] R A rotation matrix.
* @param[out] omghat the unit vector of Euler axis .
* @param[out] theta the rotation angle.
* @return No return value.
* @retval 0
* @note: if theta is zero ,the unit axis is undefined and set it as a zero vector [0;0;0].
*@warning:
*/
void RotToAxisAng(double R[3][3],double omghat[3],double *theta)
{
double tmp;
double omg[3] = { 0 };
double acosinput = (R[0][0] + R[1][1] + R[2][2] - 1.0) / 2.0;
if (fabs(acosinput-1.0)<ZERO_VALUE)
{
memset(omghat, 0, 3 * sizeof(double));
*theta = 0.0;
}
else if (acosinput <= -1.0)
{
if ((1.0 + R[2][2]) >= ZERO_VALUE)
{
omg[0] = 1.0 / sqrt(2 * (1.0 + R[2][2]))*R[0][2];
omg[1] = 1.0 / sqrt(2 * (1.0 + R[2][2]))*R[1][2];
omg[2] = 1.0 / sqrt(2 * (1.0 + R[2][2]))*(1.0 + R[2][2]);
}
else if ((1.0 + R[1][1] >= ZERO_VALUE))
{
omg[0] = 1.0 / sqrt(2 * (1.0 + R[1][1]))*R[0][1];
omg[1] = 1.0 / sqrt(2 * (1.0 + R[1][1]))*(1.0 + R[1][1]);
omg[2] = 1.0 / sqrt(2 * (1.0 + R[1][1]))*R[2][1];
}
else
{
omg[0] = 1.0 / sqrt(2 * (1.0 + R[0][0]))*(1.0 + R[0][0]);
omg[1] = 1.0 / sqrt(2 * (1.0 + R[0][0]))*R[1][0];
omg[2] = 1.0 / sqrt(2 * (1.0 + R[0][0]))*R[2][0];
}
omghat[0] = omg[0];
omghat[1] = omg[1];
omghat[2] = omg[2];
*theta=PI;
}
else
{
*theta = acos(acosinput);
tmp = 2.0*sin(*theta);
omghat[0] = (R[2][1] - R[1][2]) / tmp;
omghat[1] = (R[0][2] - R[2][0]) / tmp;
omghat[2] = (R[1][0] - R[0][1]) / tmp;
}
return;
}
/**
* @brief Description: Computes the unit quaternion corresponding to the Euler axis and rotation angle.
* @param[in] omg Unit vector of Euler axis.
* @param[in] theta Rotation angle.
* @param[in] q The unit quaternion
* @return No return value.
* @note:
*@warning:
*/
void AxisAngToQuaternion(double omg[3],double theta, double q[4])
{
q[0] = cos(theta / 2.0);
q[1] = omg[0] * sin(theta / 2.0);
q[2] = omg[1] * sin(theta / 2.0);
q[3] = omg[2] * sin(theta / 2.0);
return;
}
/**
* @brief Description:Computes the unit quaternion corresponding to a rotation matrix.
* @param[in] q Unit quaternion.
* @param[out] R Rotation matrix.
* @return No return value.
* @note:
* @warning:
*/
void QuaternionToRot(double q[4], double R[3][3])
{
R[0][0] = q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3];
R[0][1] = 2.0*(q[1] * q[2] - q[0] * q[3]);
R[0][2] = 2.0*(q[0] * q[2] + q[1] * q[3]);
R[1][0] = 2.0*(q[0] * q[3] + q[1] * q[2]);
R[1][1] = q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3];
R[1][2] = 2.0*(q[2] * q[3] - q[0] * q[1]);
R[2][0] = 2.0*(q[1] * q[3] - q[0] * q[2]);
R[2][1] = 2.0*(q[0] * q[1] + q[2] * q[3]);
R[2][2] = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
return;
}
/**
* @brief Description: Computes the unit quaternion corresponding to the rotation matrix.
* @param[in] R The rotation matrix.
* @param[out] q The unit quaternion.
* @return No return value.
* @note:
* @warning:
*/
void RotToQuaternion(double R[3][3], double q[4])
{
double omghat[3];
double theta;
RotToAxisAng(R, omghat, &theta);
AxisAngToQuaternion(omghat, theta, q);
return;
}
/**
* @brief 单位四元数转换为旋转矩阵。
* @param[in] q 单位四元数[ox,oy,oz,ow].
* @param[out] R 旋转矩阵.
* @return 无返回值.
* @note:
* @warning: (1)此函数不对输入参数做检查,需保证输入为单位四元数。
(2)四元数顺序为[ox,oy,oz,w]。
*/
void q2rot(double q[4], double R[3][3])
{
double q1[4] = { 0 };
q1[0] = q[3];
q1[1] = q[0];
q1[2] = q[1];
q1[3] = q[2];
QuaternionToRot(q1, R);
return;
}
/**
* @brief 旋转矩阵转单位四元数。
* @param[in] R 旋转矩阵
* @param[out] q 单位四元数.[ox,oy,oz,ow].
* @return 无返回值.
* @note:
* @warning: (1)此函数不对输入参数做检查,需保证输入为旋转矩阵。
(2)四元数顺序为[ox,oy,oz,w]。
*/
void rot2q(double R[3][3], double q[4])
{
double q1[4] = { 0 };
RotToQuaternion(R, q1);
q[0] = q1[1];
q[1] = q1[2];
q[2] = q1[3];
q[3] = q1[0];
return;
}
/**
* @brief Description: Computes the parameters of orientation interpolation between two orientations.
* @param[in] Rs Start orientation.
* @param[in] Re End orientation.
* @param[in] Param structure of orientation interpolation parameters..
* @return No return value.
* @note:
* @warning:
*/
void InitialOrientInpParam(double Rs[3][3],double Re[3][3], OrientInpParam *Param)
{
double InvR[3][3];
MatrixCopy((double *)Rs, 3, 3, (double *)Param->Rs);
MatrixCopy((double *)Re, 3, 3, (double *)Param->Re);
RotInv(Rs, InvR);
MatrixMult((double *)InvR, 3, 3, (double *)Re, 3, (double *)Param->R);
RotToAxisAng(Param->R, Param->omg, &Param->theta);
MatrixCopy((double *)Param->R, 3, 3, (double *)Param->Ri);
Param->thetai = 0.0;
Param->InpFlag = 1;
return;
}
/**
* @brief Description: Computes orientations in each interpolation cycle.
* @param[in] Param Interpolation parameter structure.
* @param[out] dtheta angle need to rotate from previous orientation to next orientation in next time step.
* @return Ri1 orientations in next interpolation cycle.
* @retval 0
* @note:
* @warning:
*/
void QuaternionOrientInp(OrientInpParam *Param, double dtheta, double Ri1[3][3])
{
double q[4];
double R[3][3];
Param->InpFlag = 2;
Param->thetai = Param->thetai + dtheta;
if (Param->thetai >= Param->theta)
{
Param->thetai = Param->theta;
Param->InpFlag = 3;
}
AxisAngToQuaternion(Param->omg, Param->thetai, q);
QuaternionToRot(q, R);
MatrixMult((double *)Param->Rs, 3, 3, (double *)R, 3, (double *)Ri1);
MatrixCopy((double *)Ri1, 3, 3, (double *)Param->Ri);
return;
}
/**
* @brief Description:Computes the parameters of line path for interpolation.
* @param[in] p1 Coordinates of start point.
* @param[in] p2 Coordinates of end point.
* @param[out] p Line path parameters structure.
* @return No return value.
* @note:
* @warning:
*/
void InitialLinePathParam(double p1[3],double p2[3], LineInpParam *p)
{
int i;
for (i=0;i<3;i++)
{
p->p1[i] = p1[i];
p->p2[i] = p2[i];
p->pi[i] = p1[i];
}
p->L = sqrt((p2[0] - p1[0])*(p2[0] - p1[0]) + (p2[1] - p1[1])*(p2[1] - p1[1]) + (p2[2] - p1[2])*(p2[2] - p1[2]));
if (p->L<ZERO_DISTANCE)
{
p->t[0] = 0.0;
p->t[1] = 0.0;
p->t[2] = 0.0;
}
else
{
p->t[0] = (p2[0] - p1[0]) / p->L;
p->t[1] = (p2[1] - p1[1]) / p->L;
p->t[2] = (p2[2] - p1[2]) / p->L;
}
p->InpFlag = 1;
p->Li = 0;
return;
}
/**
* @brief Description:Computes the line path interpolation coordinates in each interpolation cycle.
* @param[in] p Line path parameters structure.
* @param[in] dL step length in next interpolation cycle.
* @param[in] pi1 coordinates in next interpolation cycle.
* @return No return value.
* @note:
* @warning:
*/
void LinePathInp(LineInpParam *p, double dL, double pi1[3])
{
p->InpFlag = 2;
if (p->Li + dL>=p->L)
{
pi1[0] = p->p2[0];
pi1[1] = p->p2[1];
pi1[2] = p->p2[2];
p->Li = p->L;
p->InpFlag = 3;
}
else if ( p->L- p->Li < 2.0*dL)
{
//avoid distance of final step is too small.
dL = 0.5*dL;
pi1[0] = p->pi[0] + p->t[0] * dL;
pi1[1] = p->pi[1] + p->t[1] * dL;
pi1[2] = p->pi[2] + p->t[2] * dL;
p->Li = p->Li+dL;
}
else
{
pi1[0] = p->pi[0] + p->t[0] * dL;
pi1[1] = p->pi[1] + p->t[1] * dL;
pi1[2] = p->pi[2] + p->t[2] * dL;
p->Li = p->Li + dL;
}
p->pi[0] = pi1[0];
p->pi[1] = pi1[1];
p->pi[2] = pi1[2];
return;
}
/**
* @brief Description: Computes the parameters of both line path and orientation for interpolation.
* @param[in] p1 Start coordinates,including x,y,z coordinates and orientation angles roll-pitch-yaw angles.
* @param[in] p2 End coordinates,including x,y,z coordinates and orientation angles roll-pitch-yaw angles.
* @param[out] LPO Parameters of both line path and orientation for interpolation.
* @return No return value.
* @note:
* @warning:
*/
void InitialLinePOInpParam( double p1[6], double p2[6], LinePOParam *LPO)
{
double Rs[3][3];
double Re[3][3];
RPYToRot(p1[3], p1[4], p1[5], Rs);
RPYToRot(p2[3], p2[4], p2[5], Re);
InitialLinePathParam( p1, p2, &(LPO->Line));
InitialOrientInpParam(Rs, Re, &(LPO->Orient));
RpToTrans(Rs, p1, LPO->Ts);
RpToTrans(Rs, p1, LPO->Ti);
RpToTrans(Re, p2, LPO->Te);
LPO->InpFlag = 1;
return;
}
/**
* @brief Description:Computes the line path interpolation coordinates and orientation in each interpolation cycle.
* @param[out] LPO Line path and orientation parameters structure.
* @param[in] dL Line path interpolation step length.
* @param[out] dtheta angle interpolation step length for Orientation interpolation.
* @return No return value.
* @note:
* @warning:
*/
void LinePOInp(LinePOParam *LPO,double dL,double dtheta,double Ti[4][4])
{
double pi[3];
double Ri[3][3];
LPO->InpFlag = 2;
LinePathInp(&LPO->Line, dL, pi);
QuaternionOrientInp(&LPO->Orient, dtheta, Ri);
if (LPO->Line.InpFlag==3 && LPO->Orient.InpFlag==3)
{
LPO->InpFlag = 3;
}
RpToTrans(Ri, pi, Ti);
MatrixCopy((double *)Ti, 4, 4, (double *)LPO->Ti);
return;
}