Delta Robot example

Dependencies:   BufferedSerial Eigen

Fork of TCPSocket_Example by mbed_example

Revision:
4:778bc352c47f
diff -r 10fa3102c2d7 -r 778bc352c47f DeltaKinematics.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DeltaKinematics.cpp	Sun Oct 07 19:40:12 2018 +0000
@@ -0,0 +1,376 @@
+// DeltaKinematics - kinematics computation for delta parallel robot arm
+// Copyright(C) 2018  Szymon Szantula
+//
+// This program is free software : you can redistribute it and / or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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 Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.If not, see <http://www.gnu.org/licenses/.> 
+
+#include "DeltaKinematics.h"
+
+template <typename RealDataType>
+const RealDataType DeltaKinematics<RealDataType>::_SQRT3 = std::sqrt(3.0);
+
+template <typename RealDataType>
+const RealDataType DeltaKinematics<RealDataType>::_HSQRT3 = std::sqrt(3.0)/ 2.0;
+
+template <typename RealDataType>
+const RealDataType DeltaKinematics<RealDataType>::_DEG2RAD_FACTOR = M_PI / 180.0;
+
+template <typename RealDataType>
+const RealDataType DeltaKinematics<RealDataType>::_RAD2DEG_FACTOR = 180.0 / M_PI;
+
+template <typename RealDataType>
+const RealDataType DeltaKinematics<RealDataType>::_MROTZ120[3][3] = {{-0.5, 0.866025403784439, 0.0},
+                                                                     {-0.866025403784439, -0.5, 0.0},
+                                                                     {0.0, 0.0, 1.0}};
+
+template <typename RealDataType>
+const RealDataType DeltaKinematics<RealDataType>::_ROTZ120[3][3] = {{-0.5, -0.866025403784439, 0.0},
+                                                                    {0.866025403784439, -0.5, 0.0},
+                                                                    {0.0, 0.0, 1.0}};
+
+template <typename RealDataType>
+DeltaKinematics<RealDataType>::DeltaKinematics(DeltaGeometricDim dim)
+{
+    _sb = dim.sb;
+    _sp = dim.sp;
+    _Ll = dim.L;
+    _l = dim.l;
+    _h = dim.h;
+    _max_neg_angle = dim.max_neg_angle;
+    _min_parallelogram_angle = dim.min_parallelogram_angle;
+    Initialise();
+}
+
+template <typename RealDataType>
+void DeltaKinematics<RealDataType>::Initialise()
+{
+    _wb = _SQRT3 / 6 * _sb;
+    _ub = _SQRT3 / 3 * _sb;
+    _wp = _SQRT3 / 6 * _sp;
+    _up = _SQRT3 / 3 * _sp;
+    _B1[0] = 0;
+    _B1[1] = -_wb;
+    _B1[2] = 0;
+    _B2[0] = _HSQRT3 * _wb;
+    _B2[1] = _wb / 2;
+    _B2[2] = 0;
+    _B3[0] = -_HSQRT3 * _wb;
+    _B3[1] = _wb / 2;
+    _B3[2] = 0;
+    _Pp1[0] = 0;
+    _Pp1[1] = -_up;
+    _Pp1[2] = 0;
+    _Pp2[0] = _sp / 2;
+    _Pp2[1] = -_wp;
+    _Pp2[2] = 0;
+    _Pp3[0] = -_sp / 2;
+    _Pp3[1] = -_wp;
+    _Pp3[2] = 0;
+    _b1[0] = _sb / 2;
+    _b1[1] = -_wb;
+    _b1[2] = 0;
+    _b2[0] = 0;
+    _b2[1] = -_ub;
+    _b2[2] = 0;
+    _b3[0] = -_sb / 2;
+    _b3[1] = -_wb;
+    _b3[2] = 0;
+}
+
+template <typename RealDataType>
+void DeltaKinematics<RealDataType>::RotateByMatrix(RealDataType *point, const RealDataType (*matrix)[3])
+{
+    RealDataType temp[3];
+    for (int i = 0; i < 3; ++i)
+    {
+        temp[i] = matrix[i][0] * point[0] + matrix[i][1] * point[1] + matrix[i][2] * point[2];
+    }
+    point[0] = temp[0];
+    point[1] = temp[1];
+    point[2] = temp[2];
+}
+
+template <typename RealDataType>
+int DeltaKinematics<RealDataType>::CalculateIpk(DeltaVector *v, int num)
+{
+    RealDataType temp_p[3];
+    RealDataType temp_phi;
+    int flag;
+
+    for (int i = 0; i < num; ++i)
+    {
+        /* compute p1*/
+        temp_p[0] = _Pp1[0] + v[i].x;
+        temp_p[1] = _Pp1[1] + v[i].y;
+        temp_p[2] = _Pp1[2] + v[i].z;
+        /* calculate angle */
+        flag = CalculateAngle(_b1, temp_p, &temp_phi);
+        if (flag)
+        {
+            return 1;
+        }
+        else
+        {
+            v[i].phi1 = temp_phi;
+        }
+
+        /* compute p2 and change reference system */
+        temp_p[0] = v[i].x;
+        temp_p[1] = v[i].y;
+        temp_p[2] = v[i].z;
+        RotateByMatrix(temp_p, _MROTZ120);
+        temp_p[0] += _Pp1[0];
+        temp_p[1] += _Pp1[1];
+        temp_p[2] += _Pp1[2];
+        /* check all conditions */
+        flag = CalculateAngle(_b1, temp_p, &temp_phi);
+        if (flag)
+        {
+            return 1;
+        }
+        else
+        {
+            v[i].phi2 = temp_phi;
+        }
+
+        /* compute p3 change reference system */
+        temp_p[0] = v[i].x;
+        temp_p[1] = v[i].y;
+        temp_p[2] = v[i].z;
+        RotateByMatrix(temp_p, _ROTZ120);
+        temp_p[0] += _Pp1[0];
+        temp_p[1] += _Pp1[1];
+        temp_p[2] += _Pp1[2];
+        /* check all conditions */
+        flag = CalculateAngle(_b1, temp_p, &temp_phi);
+        if (flag)
+        {
+            return 1;
+        }
+        else
+        {
+            v[i].phi3 = temp_phi;
+        }
+    }
+
+    return 0;
+}
+
+template <typename RealDataType>
+int DeltaKinematics<RealDataType>::CalculateFpk(DeltaVector *v, int num)
+{
+    _A1[0] = 0.0;
+    RealDataType hsp = _sp / 2.0;
+    int flag;
+    for (int i = 0; i < num; ++i)
+    {
+        _A1[1] = -_wb - _Ll * std::cos(_DEG2RAD_FACTOR * v[i].phi1) + _up;
+        _A1[2] = -_Ll * std::sin(_DEG2RAD_FACTOR * v[i].phi1);
+        _A2[0] = _HSQRT3 * (_wb + _Ll * std::cos(_DEG2RAD_FACTOR * v[i].phi2)) - hsp;
+        _A2[1] = 0.5 * (_wb + _Ll * std::cos(_DEG2RAD_FACTOR * v[i].phi2)) - _wp;
+        _A2[2] = -_Ll * std::sin(_DEG2RAD_FACTOR * v[i].phi2);
+        _A3[0] = -_HSQRT3 * (_wb + _Ll * std::cos(_DEG2RAD_FACTOR * v[i].phi3)) + hsp;
+        _A3[1] = 0.5 * (_wb + _Ll * std::cos(_DEG2RAD_FACTOR * v[i].phi3)) - _wp;
+        _A3[2] = -_Ll * std::sin(_DEG2RAD_FACTOR * v[i].phi3);
+        if (_A1[2] == _A2[2] && _A2[2] == _A3[2])
+        {
+            flag = ThreeSpheresIntersectionB(&v[i]);
+        }
+        else
+        {
+            flag = ThreeSpheresIntersectionA(&v[i]);
+        }
+        if (flag)
+        {
+            return flag;
+        }
+    }
+    return 0;
+}
+
+template <typename RealDataType>
+int DeltaKinematics<RealDataType>::ThreeSpheresIntersectionA(DeltaVector *v)
+{
+    RealDataType a11, a12, a13, a21, a22, a23, b1, b2, a1, a2, a3, a4, a5, a6, a7, a, b, c, delta;
+    a11 = 2 * (_A3[0] - _A1[0]);
+    a12 = 2 * (_A3[1] - _A1[1]);
+    a13 = 2 * (_A3[2] - _A1[2]);
+    if (a13 == 0.0)
+        return 1;
+    a21 = 2 * (_A3[0] - _A2[0]);
+    a22 = 2 * (_A3[1] - _A2[1]);
+    a23 = 2 * (_A3[2] - _A2[2]);
+    if (a23 == 0.0)
+        return 1;
+    RealDataType A3_pow2 = _A3[0] * _A3[0] + _A3[1] * _A3[1] + _A3[2] * _A3[2];
+    b1 = -_A1[0] * _A1[0] - _A1[1] * _A1[1] - _A1[2] * _A1[2] + A3_pow2;
+    b2 = -_A2[0] * _A2[0] - _A2[1] * _A2[1] - _A2[2] * _A2[2] + A3_pow2;
+    a1 = a11 / a13 - a21 / a23;
+    a2 = a12 / a13 - a22 / a23;
+    a3 = b2 / a23 - b1 / a13;
+    if (a1 == 0.0)
+        return 1;
+    a4 = -a2 / a1;
+    a5 = -a3 / a1;
+    a6 = (-a21 * a4 - a22) / a23;
+    a7 = (b2 - a21 * a5) / a23;
+    a = a4 * a4 + 1 + a6 * a6;
+    if (a == 0.0)
+        return 1;
+    b = 2 * a4 * (a5 - _A1[0]) - 2 * _A1[1] + 2 * a6 * (a7 - _A1[2]);
+    c = a5 * (a5 - 2 * _A1[0]) + a7 * (a7 - 2 * _A1[2]) + _A1[0] * _A1[0] + _A1[1] * _A1[1] + _A1[2] * _A1[2] - _l * _l;
+    if ((delta = b * b - 4 * a * c) < 0.0)
+        return 1;
+    DeltaVector pp1, pp2;
+    pp1.y = (-b + std::sqrt(delta)) / (2 * a);
+    pp1.x = a4 * pp1.y + a5;
+    pp1.z = a6 * pp1.y + a7;
+    pp2.y = (-b - std::sqrt(delta)) / (2 * a);
+    pp2.x = a4 * pp2.y + a5;
+    pp2.z = a6 * pp2.y + a7;
+    if (pp1.z < 0.0 && CalculateIpk(&pp1, 1) == 0)
+    {
+        v->x = pp1.x;
+        v->y = pp1.y;
+        v->z = pp1.z;
+        return 0;
+    }
+    else if (pp2.z < 0.0 && CalculateIpk(&pp2, 1) == 0)
+    {
+        v->x = pp2.x;
+        v->y = pp2.y;
+        v->z = pp2.z;
+        return 0;
+    }
+    else
+    {
+        return 1;
+    }
+}
+
+template <typename RealDataType>
+int DeltaKinematics<RealDataType>::ThreeSpheresIntersectionB(DeltaVector *v)
+{
+    RealDataType a, b, c, d, e, f, zn, B, C, delta;
+    zn = _A1[2];
+    a = 2 * (_A3[0] - _A1[0]);
+    b = 2 * (_A3[1] - _A1[1]);
+    d = 2 * (_A3[0] - _A2[0]);
+    e = 2 * (_A3[1] - _A2[1]);
+    RealDataType A3_pow2 = _A3[0] * _A3[0] + _A3[1] * _A3[1];
+    c = -_A1[0] * _A1[0] - _A1[1] * _A1[1] + A3_pow2;
+    f = -_A2[0] * _A2[0] - _A2[1] * _A2[1] + A3_pow2;
+    DeltaVector pp;
+    RealDataType denom = a * e - b * d;
+    if (denom == 0.0)
+        return 1;
+    pp.x = (c * e - b * f) / denom;
+    pp.y = (a * f - c * d) / denom;
+    B = -2*zn;
+    C = zn * zn - _l * _l + (pp.x - _A1[0]) * (pp.x - _A1[0]) + (pp.y - _A1[1]) * (pp.y - _A1[1]);
+    delta = B * B - 4 * C;
+    if (delta < 0.0)
+        return 1;
+    RealDataType z1, z2;
+    z1 = (-B + std::sqrt(delta)) / 2;
+    z2 = (-B - std::sqrt(delta)) / 2;
+    pp.z = z1;
+    if (pp.z < 0.0 && CalculateIpk(&pp, 1) == 0)
+    {
+        v->x = pp.x;
+        v->y = pp.y;
+        v->z = pp.z;
+        return 0;
+    }
+    pp.z = z2;
+    if (pp.z < 0.0 && CalculateIpk(&pp, 1) == 0)
+    {
+        v->x = pp.x;
+        v->y = pp.y;
+        v->z = pp.z;
+        return 0;
+    }
+    return 1;
+}
+
+template <typename RealDataType>
+int DeltaKinematics<RealDataType>::CalculateAngle(const RealDataType *B, const RealDataType *P, RealDataType *phi)
+{
+    /* length of projection of vector AP on yz plane */
+    RealDataType lyz = _l * _l - P[0] * P[0];
+    if (lyz <= 0.0)
+        return 1;
+    lyz = std::sqrt(lyz);
+
+    /* check if gamma angle is correct */
+    if (P[0] != 0.0)
+    {
+        if (_RAD2DEG_FACTOR * std::atan(lyz / std::abs(P[0])) < _min_parallelogram_angle)
+            return 1;
+    }
+
+    /* compute vector BP -> both points B and P should be reduced to 2D points (yz) */
+    RealDataType vector_bp[2];
+    vector_bp[0] = P[1] - B[1];
+    vector_bp[1] = P[2] - B[2];
+
+    /* check if vector points in right direction */
+    if (vector_bp[1] >= 0)
+        return 1;
+
+    /* check if the vector have right size */
+    RealDataType d = std::sqrt(vector_bp[1] * vector_bp[1] + vector_bp[0] * vector_bp[0]);
+
+    if (d >= lyz + _Ll || d <= std::abs(lyz - _Ll))
+        return 1;
+    /* calculate alpha angle */
+    RealDataType alpha = 180.0 + std::atan2(vector_bp[1], vector_bp[0]) * _RAD2DEG_FACTOR;
+
+    /* calculate beta angle - cosine theorem */
+
+    RealDataType beta = _RAD2DEG_FACTOR * std::acos((_Ll * _Ll + d * d - lyz * lyz) / (2 * _Ll * d));
+
+    /* calculate phi angle and check max_neg_angle condition */
+    *phi = alpha - beta;
+
+    if (*phi < _max_neg_angle)
+    {
+        return 1;
+    }
+
+    /* if everything is OK */
+    return 0;
+}
+
+template <typename RealDataType>
+void DeltaKinematics<RealDataType>::DeltaVector::Print()
+{
+    #ifdef LIB_TEST_MODE
+        std::cout << "x = " << x << " "
+        << "y = " << y << " "
+        << "z = " << z << "\n"
+        << "phi1 = " << phi1 << " "
+        << "phi2 = " << phi2 << " "
+        << "phi3 = " << phi3 << "\n";
+    #endif
+}
+template <typename RealDataType>
+void DeltaKinematics<RealDataType>::DeltaVector::Clear()
+{
+    x = y = z = phi1 = phi2 = phi3 = 0.0;
+}   
+
+/* Explicit instantations */
+
+template class DeltaKinematics<float>;
+template class DeltaKinematics<double>;
\ No newline at end of file