test

Dependencies:   mbed ros_lib_kinetic nhk19mr2_can_info splitData SerialHalfDuplex_HM

Walk/Walk.cpp

Committer:
shimizuta
Date:
2019-02-27
Revision:
27:79b4b932a6dd
Parent:
26:24ae5a4f5b1f
Child:
29:7d8b8011a88d

File content as of revision 27:79b4b932a6dd:

#define _USE_MATH_DEFINES
#include "math.h"
#include <stdio.h>
#include "stdlib.h"
#include "Walk.h"
 #include "pi.h"
//Orbitは足毎の軌道をあらわす。
const float kGravity = 9.8;
void EllipseOrbit::SetParam(float stridetime_s, float risetime_s,
                            float stride_m, float height_m, float ground_m,
                            float ellipsecenter_x_m, float ellipsecenter_y_m)
{
    stridetime_s_ = stridetime_s;
    risetime_s_ = risetime_s;
    stride_m_ = stride_m;
    height_m_ = height_m;
    ground_m_ = ground_m;
    ellipsecenter_x_m_ = ellipsecenter_x_m;
    ellipsecenter_y_m_ = ellipsecenter_y_m;
}

//着地中の動き.直線軌道.等速
int EllipseOrbit::StrideLine_(OneLeg &leg, float phasetime_s)
{
    float x_m = -stride_m_ * phasetime_s / stridetime_s_ + stride_m_ * 0.5 + ellipsecenter_x_m_;
    float y_m = ellipsecenter_y_m_;
    return leg.SetXY_m(x_m, y_m);
}
int EllipseOrbit::StrideLineAccel_(OneLeg &leg, float phasetime_s)
{
    ///////////x,yを計算
    float s0 = stride_m_ * 0.5 + ellipsecenter_x_m_;
    float s1 = -stride_m_ * 0.5 + ellipsecenter_x_m_;
    float g_h = sqrtf(kGravity / ground_m_);
    float t = phasetime_s / stridetime_s_;
    float denominator = expf(g_h) - expf(-g_h); //分母

    float x_m = -(s0 * expf(-g_h) - s1) * expf(g_h * t) / denominator + (s0 * expf(g_h) - s1) * expf(-g_h * t) / denominator;
    float y_m = ground_m_;
    //x,yを代入
    return leg.SetXY_m(x_m, y_m);
}
//空中の動き.半分にきれいに切れる楕円軌道
int EllipseOrbit::RiseEllipse_(OneLeg &leg, float phasetime_s)
{
    float rad = M_PI * (phasetime_s - stridetime_s_) / risetime_s_ + M_PI;
    float x_m = stride_m_ * 0.5 * cosf(rad) + ellipsecenter_x_m_;
    float y_m = height_m_ * sinf(rad) + ellipsecenter_y_m_;
    return leg.SetXY_m(x_m, y_m);
}
//空中の動き.完全に半分には切れない楕円軌道
int EllipseOrbit::RiseEllipse2_(OneLeg &leg, float phasetime_s)
{
    ///////////x,yを計算
    float ellipselong_m = stride_m_ * 0.5 / cosf(asinf(ground_m_ - ellipsecenter_y_m_));
    float ellipseshort_m = 2 * (height_m_ - ground_m_ + ellipsecenter_y_m_);
    float theta1 = acosf(stride_m_ / ellipselong_m * 0.5);      //stride の始まりの位置の角度(数学基準)
    float theta2 = acosf(-stride_m_ / ellipselong_m * 0.5);     //stride の終わりの位置の角度(数学基準)
    float omega = (2 * M_PI - theta2 + theta1) / risetime_s_;   //楕円軌道における角速度、一定の値とする(適当)
    float rad = (phasetime_s - stridetime_s_) * omega + theta2; //角度の基準はtheta1とする(適当)
    float x_m = ellipselong_m * cos(rad) + ellipsecenter_x_m_;
    float y_m = ellipseshort_m * sin(rad) + ellipsecenter_y_m_;
    //x,yを代入
    return leg.SetXY_m(x_m, y_m);
}
//楕円軌道
int EllipseOrbit::GetOrbit(OneLeg &leg, float phasetime_s)
{
    if (phasetime_s < stridetime_s_)
        return StrideLine_(leg, phasetime_s);
    else
        return RiseEllipse_(leg, phasetime_s);
}
float EllipseOrbit::GetOneWalkTime()
{
    return stridetime_s_ + risetime_s_;
}
void EllipseOrbit::ChangeOneParam(EllipseParams param, float val)
{
    switch (param)
    {
    case STRIDE_M:
        stride_m_ = val;
        break;
    case HEIGHT_M:
        height_m_ = val;
        break;
    case GROUND_M:
        ground_m_ = val;
        break;
    case ELLIPSE_CENTER_X_M:
        ellipsecenter_x_m_ = val;
        break;
    case ELLIPSE_CENTER_Y_M:
        ellipsecenter_y_m_ = val;
        break;
    }
}
void FreeLineOrbit::SetFreeLinesParam(LineParam lineparams[], int point_num)
{
    point_num_ = point_num;
    if (point_num_ == 1)
    {
        printf("error:point_num = 1. You should put >=2 to make line.");
        while (1)
            ;
    }
    for (int i = 0; i < point_num_; i++)
        lineparams_[i] = lineparams[i];
}
int FreeLineOrbit::GetOrbit(OneLeg &leg, float phasetime_s)
{
    ;
    //現在の最終到達pointを決定
    int arrived_point;
    float sum_time = 0;
    for (arrived_point = 0; arrived_point < point_num_ - 2; arrived_point++) //arrived_point = point_num-1(これが配列の最大index)の状態で終わらないように-2している
    {
        sum_time += lineparams_[arrived_point].time_s;
        if (phasetime_s < sum_time)
            break;
    }
    //x,yを計算
    float x_m, y_m;
    x_m = lineparams_[arrived_point].x_m +
          (lineparams_[arrived_point + 1].x_m - lineparams_[arrived_point].x_m) * phasetime_s / lineparams_[arrived_point].time_s;
    y_m = lineparams_[arrived_point].y_m +
          (lineparams_[arrived_point + 1].y_m - lineparams_[arrived_point].y_m) * phasetime_s / lineparams_[arrived_point].time_s;
    return leg.SetXY_m(x_m, y_m);
}
float FreeLineOrbit::GetOneWalkTime() //足一周の時間
{
    float sum_time = 0;
    for (int i = 0; i < point_num_; i++)
        sum_time += lineparams_[i].time_s;
    return sum_time;
}
void FreeLineOrbit::SetStandParam(float x_m, float y_m, float time_s)
{
    point_num_ = 1;
    lineparams_[0].x_m = x_m;
    lineparams_[0].y_m = y_m;
    lineparams_[0].time_s = time_s;
    lineparams_[1].x_m = x_m;
    lineparams_[1].y_m = y_m;
    lineparams_[1].time_s = 0;
}

Orbit::Orbit(OrbitPattern pattern)
{
    pattern_ = pattern;
}
float Orbit::GetOneWalkTime()
{
    float time_s;
    switch (pattern_)
    {
    case FREELINES:
        time_s = FreeLineOrbit::GetOneWalkTime();
        break;

    default:
        time_s = EllipseOrbit::GetOneWalkTime();
        break;
    }
    return time_s;
}
int Orbit::GetOrbit(OneLeg &leg, float phasetime_s)
{
    int ret;
    switch (pattern_)
    {
    case FREELINES:
        ret = FreeLineOrbit::GetOrbit(leg, phasetime_s);
        break;
    default:
        ret = EllipseOrbit::GetOrbit(leg, phasetime_s);
        break;
    }
    return ret;
}

Walk::Walk()
{
    for (int i = 0; i < 4; i++)
        offset_multi_[i] = 0;
}
float Walk::calctime_s_;
void Walk::Cal4LegsPosi(OneLeg leg[4])
{
    for (int i = 0; i < 4; i++)
    {
        float one_walk_time = orbit_[i].GetOneWalkTime();
        phasetime_s_[i] += calctime_s_;
        while (phasetime_s_[i] > one_walk_time)
            phasetime_s_[i] -= one_walk_time;
        orbit_[i].GetOrbit(leg[i], phasetime_s_[i]);
    }
}
float Walk::GetOneWalkTime()
{
    return orbit_[0].GetOneWalkTime(); //4足全て同じ時間のはずなので一例としてorbit_[0]のものを返している.
};
void Walk::SetOffset(float offset_multi0, float offset_multi1, float offset_multi2, float offset_multi3)
{
    offset_multi_[0] = offset_multi0;
    offset_multi_[1] = offset_multi1;
    offset_multi_[2] = offset_multi2;
    offset_multi_[3] = offset_multi3;
}
//軌道がリンク定義外になっていないかチェック。reutn 0:ok 1:out
int Walk::CheckOrbit(OneLeg templateleg)
{
    for (int i = 0; i < 4; i++)
    {
        //軌道が値域の外に出ないか計算で確かめる
        float one_walk_time = GetOneWalkTime();
        int step = one_walk_time / calctime_s_ * 2;
        for (float j = 0; j < one_walk_time; j += step)
        {
            if (orbit_[i].GetOrbit(templateleg, j) == 1)
                return 1; //解が出ないときは1を返す
        }
        phasetime_s_[i] = one_walk_time * offset_multi_[i];
    }
    return 0;
}
void Walk::SetOneOrbit(int legnum, Orbit orbit)
{
    orbit_[legnum] = orbit;
}
void Walk::SetAllOrbit(Orbit orbit)
{
    for (int i = 0; i < 4; i++)
        SetOneOrbit(i, orbit);
}

void Walk::ChangeOneParam(int legnum, EllipseParams param, float val)
{
    orbit_[legnum].ChangeOneParam(param, val);
}
void Walk::SetAllLegEllipseParam(float stridetime_s, float risetime_s,
                                 float stride_m, float height_m, float ground_m,
                                 float ellipsecenter_x_m, float ellipsecenter_y_m)
{
    for (int i = 0; i < 4; i++)
        orbit_[i].SetParam(stridetime_s, risetime_s, stride_m, height_m, ground_m, ellipsecenter_x_m, ellipsecenter_y_m);
}
void Walk::SetAllLegStandParam(float x_m, float y_m, float time_s)
{
    Orbit stand(FREELINES);
    stand.SetStandParam(x_m, y_m, time_s); //defaultとなる軌道設定
    SetAllOrbit(stand);                    //4足にコピー
}