control for robotic arm that can play chess using a granular gripper

Dependencies:   Encoder mbed HIDScope Servo MODSERIAL

Fork of chessRobot by a steenbeek

actuators.cpp

Committer:
bjornnijhuis
Date:
2015-10-23
Revision:
104:750d7e13137d
Parent:
103:4a37d19e8fcc
Child:
105:663b73bb2f81

File content as of revision 104:750d7e13137d:

#include "actuators.h"
#include "PID.h"
#include "mbed.h"
#include "config.h"
#include "encoder.h"
#include "HIDScope.h"
#include "buttons.h"

// functions for controlling the motors
bool motorsEnable = false;
bool safetyOn = true; // start with safety off for calibration


double encoder1Counts = 0;
double encoder2Counts = 0;

bool direction1 = false; // CCW is false(positive rotation), CW is true (neg rotation)
bool direction2 = false;

double motor1Pos = 0;
double motor2Pos = 0;

double motor1Speed = 0;
double motor2Speed = 0;

double motor1SetSpeed = 0;
double motor2SetSpeed = 0;

double servoPulsewidth;
double servoPos = 0;

double motor1PWM = 0;
double motor2PWM = 0;

// Set PID values
double Kp1 = 0.008;
double Ki1 = 0.08;
double Kd1 = 0;

double Kp2 = 0.008;
double Ki2 = 0.08;
double Kd2 = 0;

double motor1PrevCounts = 0;
double motor2PrevCounts = 0;
double prevTime = 0;
double now = 0;
double timechange;
bool pidOut = 0;

// Set servo values
const double servoPeriod = 0.020;
const double servo_range = 20;  // Servo range (-range/ range) [deg]
const double servo_vel = 15;    // Servo velocity [deg/s]
const double servo_inc = servo_vel * servoCall;     // Servo postion increment per cycle
double servo_pos = 0;
double servoSpeed = -1;
double scaleXSpeed = 10;
double scaleYSpeed = 20;
double scaleZSpeed = 1;



// Set calibration values
double motorCalSpeed = 10; // deg/sec
double returnSpeed = -10;
bool springHit = false;
float lastCall = 0;
bool calibrating1 = true;
bool calibrating2 = false;

// Create object instances
// Safety Pin
DigitalIn safetyIn(safetyPin);

// Initialze motors
PwmOut motor1(motor1PWMPin);
PwmOut motor2(motor2PWMPin);

// initialize Servo
PwmOut servo(servoPin);


// Initialize encoders
Encoder encoder1(enc1A, enc1B);
Encoder encoder2(enc2A, enc2B);

// Set direction pins
DigitalOut motor1Dir(motor1DirPin);
DigitalOut motor2Dir(motor2DirPin);

// create PID instances
PID motor1PID(&motor1Speed, &motor1PWM, &motor1SetSpeed, Kp1, Ki1, Kd1);
PID motor2PID(&motor2Speed, &motor2PWM, &motor2SetSpeed, Kp2, Ki2, Kd2);

Timer t;

void motorInit()
{

    motor1Dir.write(direction1);
    motor2Dir.write(direction2);

    // Set motor PWM period
    motor1.period(1/pwm_frequency);
    motor2.period(1/pwm_frequency);

    motor1PID.SetSampleTime(motorCall);
    motor2PID.SetSampleTime(motorCall);

    motor1PID.SetOutputLimits(0,1);
    motor2PID.SetOutputLimits(0,1);

    // Turn PID on
    motor1PID.SetMode(AUTOMATIC);
    motor2PID.SetMode(AUTOMATIC);

    // set servo period
    servo.period(servoPeriod);


    // start the timer
    t.start();
}


void motorControl()
{
    // EMG signals to motor speeds
//        motor1SetSpeed = x_velocity*scaleXSpeed;
//        motor2SetSpeed = y_velocity*scaleYSpeed;
//        servoSpeed = z_velocity*scaleZSpeed;


    // get encoder positions in degrees
    // 131.25:1 gear ratio
    // getPosition uses X2 configuration, so 32 counts per revolution
    // encoder reads CCW negative, and CW positive, so multiply by -1 to make CCW positive

    encoder1Counts = encoder1.getPosition();
    encoder2Counts = encoder2.getPosition();


    motor1Pos = -((encoder1Counts/32)/131.25)*360;
    motor2Pos = -((encoder2Counts/32)/131.25)*360;

    // check if motor's are within rotational boundarys
    // get  encoder speeds in deg/sec
    now = t.read();
    timechange = (now - prevTime);
    motor1Speed = -((((encoder1Counts - motor1PrevCounts)/32)/131.25)*360)/timechange;
    motor2Speed = -((((encoder2Counts - motor2PrevCounts)/32)/131.25)*360)/timechange;
    prevTime = now;
    motor1PrevCounts = encoder1Counts;
    motor2PrevCounts = encoder2Counts;

    // calculate motor setpoint speed in deg/sec from setpoint x/y speed


    if(motorsEnable) { // only run motors if switch is enabled
        // compute new PID parameters using setpoint angle speeds and encoder speed
        writeMotors();

    } else {
        // write 0 to motors
        motor1.write(0);
        motor2.write(0);
    }
}

void writeMotors()
{
    motor1PID.Compute(); // calculate PID outputs, output changes automatically
    motor2PID.Compute();
// write new values to motor's
    if (motor1SetSpeed > 0 ) { // CCW rotation
        direction1 = false;
        motor1PID.SetOutputLimits(0,1); // change pid output direction
    } else {
        direction1 = true; // CW rotation
        motor1PID.SetOutputLimits(-1,0);
    }
    if (motor2SetSpeed > 0 ) { // CCW rotation
        direction2 = false;
        motor2PID.SetOutputLimits(0,1);
    } else {
        direction2 = true; // CW rotation
        motor2PID.SetOutputLimits(-1,0);
    }
    motor1Dir.write(direction1);
    motor2Dir.write(direction2);

   // motor1.write(abs(motor1PWM));
 //   motor2.write(abs(motor2PWM));
}

void servoControl()
{
    if (servoSpeed > 0) {
        if((servo_pos + servo_inc) <= servo_range) {       // If increment step does not exceed maximum range
            servo_pos += servo_inc;
        }
    } else if (servoSpeed < 0) {
        if((servo_pos - servo_inc) >= -servo_range) {       // If increment step does not exceed maximum range
            servo_pos -= servo_inc;
        }
    }
    servoPulsewidth = 0.0015 + (servo_pos/90)*0.001;
    if(motorsEnable) {
        servo.pulsewidth(servoPulsewidth);
    } else if (!motorsEnable) {
        servo.pulsewidth(0.0017);
    }
}

void calibrateMotors()
{
    safetyOn = false; // safety springs off
    motorsEnable = true; // motors on
    redLed.write(0);
    greenLed.write(1);
    blueLed.write(1);
    while (calibrating1 || calibrating2) {
        if (calibrating1) {
            redLed.write(1);
            greenLed.write(0);
            blueLed.write(1);
            if(safetyIn.read() !=1) { // check if arm reached safety position
                encoder1.setPosition(0); // set motor 1 cal angle
                motor1SetSpeed = returnSpeed; // move away
                springHit = true;
            } else {
                if(springHit) { // if hit and after is no longer touching spring
                    motor1SetSpeed = 0;
                    springHit = false;
                    calibrating1 = false;
                    calibrating2 = true; // start calibrating 2
                }
            }
        }
        if (calibrating2) {
            motor2SetSpeed = motorCalSpeed;
            redLed.write(1);
            greenLed.write(1);
            blueLed.write(0);
            if(safetyIn.read() !=1) { // check if arm reached safety position
                encoder2.setPosition(0); // set motor 2 cal angle
                motor2SetSpeed = returnSpeed; // move away
                springHit = true;
            } else {
                if(springHit) { // if hit and after is no longer touching spring
                    motor2SetSpeed = 0;
                    springHit = false;
                    calibrating2 = false; // stop calibrating 2
                }
            }
        }
        now = t.read(); // call motor using timer instead of wait
        if(now - lastCall > motorCall) {
            motorControl();
            lastCall = now;
        }

    }
    motorsEnable = false; // turn motor's off again
    safetyOn = true; // turn safety on after callibration
}


void safety()
{
    if (safetyOn) {
        if (safetyIn.read() != 1) {
            motorsEnable = false;
            redLed.write(!redLed.read());
        }
    }
}