Code to let Gr20's BioRobotics2017 robot come to live.

Dependencies:   FastPWM MODSERIAL QEI mbed

robot.cpp

Committer:
megrootens
Date:
2017-11-13
Revision:
7:b9a209f889f5

File content as of revision 7:b9a209f889f5:

#include "robot.h"
#include "ui.h"
#include "ref.h"
#include "tools.h"


/**
 * Robot implementation
 */
namespace robot
{
Motor m1(M1_PWM, M1_DIR, M1_ENC_A, M1_ENC_B, GEAR_RATIO*COUNTS_PER_REV);
Motor m2(M2_PWM, M2_DIR, M2_ENC_A, M2_ENC_B, GEAR_RATIO*COUNTS_PER_REV, true);

Controller c1(.500,.200,0.070,kSampleTime);
Controller c2(.400,.200,0.050,kSampleTime);

State state = OFF;
bool is_calibrated = false;

/**
 * Switching ROBOT state to a new state
 */
void SwitchState(State new_state)
{
    ui::serial.printf("* Switching ROBOT State to: %s\r\n",StateNames[new_state]);
    state = new_state;
}

/**
 * State flow // MANUAL state not implemented
 */
void GoToNextState()
{
    switch (state) {
        case OFF:
            SwitchState(CALIBRATION);
            ui::SwitchState(ui::IGNORE);
            Start();
            break;
        case CALIBRATION:
            SwitchState(HOMING);
            Start();
            break;
        case HOMING:
            SwitchState(DEMO);
            //ui::SwitchState(ui::STATE_SWITCHING);
            break;
        case READY:
            SwitchState(DEMO);
            break;
        default:
            SwitchState(OFF);
            is_calibrated = false;
            Stop();
    }
}

/**
 * Check whether any of the motors is running
 */
bool has_power()
{
    return m1.has_power() or m2.has_power();
}

/**
 * Get motor angle in [deg] for motor i=1,2
 */
double get_angle(int i)
{
    switch(i) {
        case 1:
            return m1.get_angle();
        case 2:
            return m2.get_angle();
        default:
            return NULL;
    }
}

/**
 * Compute end-effector x-coordinate [m] for given motor angles [deg].
 */
double ForwardKinematicsX(double theta_1, double theta_2)
{
    return kL1*cos(deg2rad(theta_1)) + kL2*cos(deg2rad(theta_2));
}

/**
 * Compute end-effector y-coordinate [m] for given motor angles [deg].
 */
double ForwardKinematicsY(double theta_1, double theta_2)
{
    return kL1*sin(deg2rad(theta_1)) + kL2*sin(deg2rad(theta_2));
}

/**
 * Compute end-effector x-coordinate [m] for current motor angles.
 */
double get_x()
{
    return ForwardKinematicsX(get_angle(1),get_angle(2));
}

/**
 * Compute end-effector y-coordinate [m] for current motor angles.
 */
double get_y()
{
    return ForwardKinematicsY(get_angle(1),get_angle(2));
}

/**
 * Compute motor angle [deg] for motor i=1,2 for given end-effector x and y
 * coordinate [m]
 */
double InverseKinematicsTheta(double x, double y, int i)
{
    // vector to end point
    double r = sqrt(pow(x,2) + pow(y,2));
    double dir_angle = rad2deg( atan2(y,x) );

    // law of cosines for internal angles
    double int_angle_1 =
        rad2deg( acos((pow(kL1,2) + pow(r,2) - pow(kL2,2))/(2*kL1*r)) );
    double int_angle_2 =
        rad2deg( acos((pow(kL2,2) + pow(r,2) - pow(kL1,2))/(2*kL2*r)) );

    // absolute motor angles w.r.t x,y frame
    double theta_1 = dir_angle + int_angle_1;
    double theta_2 = dir_angle - int_angle_2;

    switch (i) {
        case 1: return theta_1;
        case 2: return theta_2;
        default: return NULL;
    }
}

/**
 * Start robot:
 * - set reference position to current position s.t. no 'explosion'
 * - start motors
 * - reset controller
 */
void Start()
{
    ui::serial.printf("! Starting robot.\r\n");
    ui::serial.printf("  - Setting current position as reference.\r\n");
    ref::SetPositionAsReference();

    ui::serial.printf("  - Resetting controllers.\r\n");
    c1.Reset();
    c2.Reset();

    ui::serial.printf("  - Starting motors.\r\n");
    m1.Start();
    m2.Start();
}

void Stop()
{
    ui::serial.printf("! Stopping robot.\r\n");
    ui::serial.printf("  - Stopping motors.\r\n");
    m1.Stop();
    m2.Stop();
}

/**
 * Control loop; negative feedback control on error with reference postion
 */
void ControlLoop()
{
    m1.set_pwm(c1.Update( ref::theta_1 - get_angle(1) ));
    m2.set_pwm(c2.Update( ref::theta_2 - get_angle(2) ));
}

/**
 * Set the motor angles to the values corresponding to the end-stops.
 * Only call this method when the robot is at its end-stops!
 */
void SetCalibrationAngles()
{
    m1.set_angle(kCalibAngleMotor1);
    m2.set_angle(kCalibAngleMotor2);
    is_calibrated = true;
}

} // end namespace robot