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

Dependencies:   Encoder mbed HIDScope Servo MODSERIAL

Fork of chessRobot by a steenbeek

Committer:
annesteenbeek
Date:
Mon Oct 26 13:04:22 2015 +0100
Revision:
107:de47331612d9
Parent:
106:1773bf7b95c5
Child:
109:026abd708dce
added servo control without PWM

Who changed what in which revision?

UserRevisionLine numberNew contents of line
annesteenbeek 13:4837b36b9a68 1 #include "actuators.h"
annesteenbeek 13:4837b36b9a68 2 #include "PID.h"
annesteenbeek 13:4837b36b9a68 3 #include "mbed.h"
annesteenbeek 13:4837b36b9a68 4 #include "config.h"
annesteenbeek 13:4837b36b9a68 5 #include "encoder.h"
annesteenbeek 25:874675516927 6 #include "HIDScope.h"
annesteenbeek 107:de47331612d9 7 #include "buttons.h"
annesteenbeek 107:de47331612d9 8 #include "Servo.h"
annesteenbeek 98:25528494287d 9
annesteenbeek 106:1773bf7b95c5 10 // Motor control constants
annesteenbeek 106:1773bf7b95c5 11 #define pwm_frequency 50000 // still High, could be lowered
annesteenbeek 106:1773bf7b95c5 12 #define PI 3.14159265
annesteenbeek 106:1773bf7b95c5 13
annesteenbeek 32:2006977785f5 14 // functions for controlling the motors
annesteenbeek 34:f315b2b38555 15 bool motorsEnable = false;
annesteenbeek 106:1773bf7b95c5 16 bool safetyOn = true;
annesteenbeek 76:0aa90e728e4a 17
annesteenbeek 6:b957d8809e7c 18
annesteenbeek 68:21cb054f1399 19 double encoder1Counts = 0;
annesteenbeek 68:21cb054f1399 20 double encoder2Counts = 0;
annesteenbeek 68:21cb054f1399 21
annesteenbeek 32:2006977785f5 22 bool direction1 = false; // CCW is false(positive rotation), CW is true (neg rotation)
annesteenbeek 32:2006977785f5 23 bool direction2 = false;
annesteenbeek 6:b957d8809e7c 24
annesteenbeek 62:6c566e6f9664 25 double motor1Pos = 0;
annesteenbeek 62:6c566e6f9664 26 double motor2Pos = 0;
annesteenbeek 6:b957d8809e7c 27
annesteenbeek 62:6c566e6f9664 28 double motor1Speed = 0;
annesteenbeek 62:6c566e6f9664 29 double motor2Speed = 0;
annesteenbeek 6:b957d8809e7c 30
annesteenbeek 62:6c566e6f9664 31 double motor1SetSpeed = 0;
annesteenbeek 62:6c566e6f9664 32 double motor2SetSpeed = 0;
annesteenbeek 6:b957d8809e7c 33
annesteenbeek 62:6c566e6f9664 34 double motor1PWM = 0;
annesteenbeek 62:6c566e6f9664 35 double motor2PWM = 0;
annesteenbeek 6:b957d8809e7c 36
annesteenbeek 32:2006977785f5 37 // Set PID values
annesteenbeek 62:6c566e6f9664 38 double Kp1 = 1;
annesteenbeek 62:6c566e6f9664 39 double Ki1 = 0;
annesteenbeek 62:6c566e6f9664 40 double Kd1 = 0;
annesteenbeek 0:525558a26464 41
annesteenbeek 69:37f75a7d36d8 42 double Kp2 = 0.008;
annesteenbeek 69:37f75a7d36d8 43 double Ki2 = 0.08;
annesteenbeek 62:6c566e6f9664 44 double Kd2 = 0;
annesteenbeek 20:3cba803cd771 45
annesteenbeek 68:21cb054f1399 46 double motor1PrevCounts = 0;
annesteenbeek 68:21cb054f1399 47 double motor2PrevCounts = 0;
annesteenbeek 62:6c566e6f9664 48 double prevTime = 0;
annesteenbeek 62:6c566e6f9664 49 double now = 0;
annesteenbeek 62:6c566e6f9664 50 double timechange;
annesteenbeek 26:0a9e4147a31a 51
annesteenbeek 98:25528494287d 52 // Set servo values
annesteenbeek 107:de47331612d9 53 const int servoStartPos = 1300; // Servo ranges from 600ms(-90) to 2000ms(90), 1300 is 0 deg
annesteenbeek 99:7030e9790b1d 54
annesteenbeek 99:7030e9790b1d 55 // Set calibration values
annesteenbeek 99:7030e9790b1d 56 double motorCalSpeed = 10; // deg/sec
annesteenbeek 99:7030e9790b1d 57 double returnSpeed = -10;
annesteenbeek 99:7030e9790b1d 58 bool springHit = false;
annesteenbeek 99:7030e9790b1d 59 float lastCall = 0;
annesteenbeek 99:7030e9790b1d 60 bool calibrating1 = true;
annesteenbeek 99:7030e9790b1d 61 bool calibrating2 = false;
annesteenbeek 98:25528494287d 62
annesteenbeek 32:2006977785f5 63 // Create object instances
annesteenbeek 74:75be98779124 64 // Safety Pin
annesteenbeek 79:cf500b63f349 65 DigitalIn safetyIn(safetyPin);
annesteenbeek 74:75be98779124 66
annesteenbeek 32:2006977785f5 67 // Initialze motors
annesteenbeek 32:2006977785f5 68 PwmOut motor1(motor1PWMPin);
annesteenbeek 32:2006977785f5 69 PwmOut motor2(motor2PWMPin);
annesteenbeek 32:2006977785f5 70
annesteenbeek 98:25528494287d 71 // initialize Servo
annesteenbeek 107:de47331612d9 72 Servo servo(servoPin);
annesteenbeek 98:25528494287d 73
annesteenbeek 98:25528494287d 74
annesteenbeek 32:2006977785f5 75 // Initialize encoders
annesteenbeek 32:2006977785f5 76 Encoder encoder1(enc1A, enc1B);
annesteenbeek 32:2006977785f5 77 Encoder encoder2(enc2A, enc2B);
annesteenbeek 25:874675516927 78
annesteenbeek 32:2006977785f5 79 // Set direction pins
annesteenbeek 32:2006977785f5 80 DigitalOut motor1Dir(motor1DirPin);
annesteenbeek 32:2006977785f5 81 DigitalOut motor2Dir(motor2DirPin);
annesteenbeek 26:0a9e4147a31a 82
annesteenbeek 32:2006977785f5 83 // create PID instances
annesteenbeek 52:2ac9dee099ce 84 PID motor1PID(&motor1Speed, &motor1PWM, &motor1SetSpeed, Kp1, Ki1, Kd1);
annesteenbeek 52:2ac9dee099ce 85 PID motor2PID(&motor2Speed, &motor2PWM, &motor2SetSpeed, Kp2, Ki2, Kd2);
annesteenbeek 31:8fbee6c92753 86
annesteenbeek 32:2006977785f5 87 Timer t;
annesteenbeek 25:874675516927 88
annesteenbeek 25:874675516927 89 void motorInit(){
annesteenbeek 25:874675516927 90
annesteenbeek 3:47c76be6d402 91 motor1Dir.write(direction1);
annesteenbeek 3:47c76be6d402 92 motor2Dir.write(direction2);
annesteenbeek 3:47c76be6d402 93
annesteenbeek 3:47c76be6d402 94 // Set motor PWM period
annesteenbeek 3:47c76be6d402 95 motor1.period(1/pwm_frequency);
annesteenbeek 3:47c76be6d402 96 motor2.period(1/pwm_frequency);
annesteenbeek 55:ee5257fb73df 97
annesteenbeek 55:ee5257fb73df 98 motor1PID.SetSampleTime(motorCall);
annesteenbeek 55:ee5257fb73df 99 motor2PID.SetSampleTime(motorCall);
annesteenbeek 55:ee5257fb73df 100
annesteenbeek 69:37f75a7d36d8 101 motor1PID.SetOutputLimits(0,1);
annesteenbeek 69:37f75a7d36d8 102 motor2PID.SetOutputLimits(0,1);
annesteenbeek 69:37f75a7d36d8 103
annesteenbeek 30:a20f16bf8dda 104 // Turn PID on
annesteenbeek 55:ee5257fb73df 105 motor1PID.SetMode(AUTOMATIC);
annesteenbeek 55:ee5257fb73df 106 motor2PID.SetMode(AUTOMATIC);
annesteenbeek 98:25528494287d 107
annesteenbeek 98:25528494287d 108 // set servo period
annesteenbeek 107:de47331612d9 109 servo.Enable(servoStartPos, 20000);
annesteenbeek 98:25528494287d 110
annesteenbeek 30:a20f16bf8dda 111 // start the timer
annesteenbeek 29:e4f3455aaa0b 112 t.start();
annesteenbeek 4:80e2280058ed 113 }
annesteenbeek 0:525558a26464 114
annesteenbeek 26:0a9e4147a31a 115
annesteenbeek 0:525558a26464 116 void motorControl(){
annesteenbeek 107:de47331612d9 117 #ifndef SETPOS // if not tuning with potmeters, switch to EMG
annesteenbeek 107:de47331612d9 118 // EMG signals to motor speeds
annesteenbeek 107:de47331612d9 119 const double scaleVel = 20;
annesteenbeek 107:de47331612d9 120 motor1SetSpeed = x_velocity*scaleVel;
annesteenbeek 107:de47331612d9 121 motor2SetSpeed = y_velocity*scaleVel;
annesteenbeek 107:de47331612d9 122 servoSpeed = z_velocity*scaleVel;
annesteenbeek 107:de47331612d9 123 #endif
annesteenbeek 30:a20f16bf8dda 124 // get encoder positions in degrees
annesteenbeek 30:a20f16bf8dda 125 // 131.25:1 gear ratio
annesteenbeek 30:a20f16bf8dda 126 // getPosition uses X2 configuration, so 32 counts per revolution
annesteenbeek 30:a20f16bf8dda 127 // encoder reads CCW negative, and CW positive, so multiply by -1 to make CCW positive
annesteenbeek 68:21cb054f1399 128
annesteenbeek 68:21cb054f1399 129 encoder1Counts = encoder1.getPosition();
annesteenbeek 68:21cb054f1399 130 encoder2Counts = encoder2.getPosition();
annesteenbeek 68:21cb054f1399 131
annesteenbeek 68:21cb054f1399 132
annesteenbeek 68:21cb054f1399 133 motor1Pos = -((encoder1Counts/32)/131.25)*360;
annesteenbeek 68:21cb054f1399 134 motor2Pos = -((encoder2Counts/32)/131.25)*360;
annesteenbeek 3:47c76be6d402 135
annesteenbeek 0:525558a26464 136 // check if motor's are within rotational boundarys
annesteenbeek 30:a20f16bf8dda 137 // get encoder speeds in deg/sec
annesteenbeek 66:d1ab5904f8e5 138 now = t.read();
annesteenbeek 50:b0cf07ca53cf 139 timechange = (now - prevTime);
annesteenbeek 68:21cb054f1399 140 motor1Speed = -((((encoder1Counts - motor1PrevCounts)/32)/131.25)*360)/timechange;
annesteenbeek 68:21cb054f1399 141 motor2Speed = -((((encoder2Counts - motor2PrevCounts)/32)/131.25)*360)/timechange;
annesteenbeek 50:b0cf07ca53cf 142 prevTime = now;
annesteenbeek 68:21cb054f1399 143 motor1PrevCounts = encoder1Counts;
annesteenbeek 68:21cb054f1399 144 motor2PrevCounts = encoder2Counts;
annesteenbeek 29:e4f3455aaa0b 145
annesteenbeek 31:8fbee6c92753 146 // calculate motor setpoint speed in deg/sec from setpoint x/y speed
annesteenbeek 30:a20f16bf8dda 147
annesteenbeek 48:3cf1eaf34926 148
annesteenbeek 48:3cf1eaf34926 149 if(motorsEnable){ // only run motors if switch is enabled
annesteenbeek 32:2006977785f5 150 // compute new PID parameters using setpoint angle speeds and encoder speed
annesteenbeek 31:8fbee6c92753 151 writeMotors();
annesteenbeek 98:25528494287d 152 servoControl();
annesteenbeek 0:525558a26464 153 }else{
annesteenbeek 0:525558a26464 154 // write 0 to motors
annesteenbeek 2:95ba9f6f0128 155 motor1.write(0);
annesteenbeek 2:95ba9f6f0128 156 motor2.write(0);
annesteenbeek 0:525558a26464 157 }
annesteenbeek 0:525558a26464 158 }
annesteenbeek 0:525558a26464 159
annesteenbeek 31:8fbee6c92753 160 void writeMotors(){
annesteenbeek 54:c14c3bc48b8a 161 motor1PID.Compute(); // calculate PID outputs, output changes automatically
annesteenbeek 76:0aa90e728e4a 162 motor2PID.Compute();
annesteenbeek 31:8fbee6c92753 163 // write new values to motor's
annesteenbeek 82:4cc8f9ad3fec 164 if (motor1SetSpeed > 0 ){ // CCW rotation
annesteenbeek 31:8fbee6c92753 165 direction1 = false;
annesteenbeek 84:df770ec4df61 166 motor1PID.SetOutputLimits(0,1); // change pid output direction
annesteenbeek 31:8fbee6c92753 167 }else{
annesteenbeek 31:8fbee6c92753 168 direction1 = true; // CW rotation
annesteenbeek 83:8fa05f53fc73 169 motor1PID.SetOutputLimits(-1,0);
annesteenbeek 31:8fbee6c92753 170 }
annesteenbeek 82:4cc8f9ad3fec 171 if (motor2SetSpeed > 0 ){ // CCW rotation
annesteenbeek 68:21cb054f1399 172 direction2 = false;
annesteenbeek 83:8fa05f53fc73 173 motor2PID.SetOutputLimits(0,1);
annesteenbeek 68:21cb054f1399 174 }else{
annesteenbeek 68:21cb054f1399 175 direction2 = true; // CW rotation
annesteenbeek 83:8fa05f53fc73 176 motor2PID.SetOutputLimits(-1,0);
annesteenbeek 68:21cb054f1399 177 }
annesteenbeek 31:8fbee6c92753 178 motor1Dir.write(direction1);
annesteenbeek 31:8fbee6c92753 179 motor2Dir.write(direction2);
annesteenbeek 69:37f75a7d36d8 180
annesteenbeek 52:2ac9dee099ce 181 motor1.write(abs(motor1PWM));
annesteenbeek 76:0aa90e728e4a 182 motor2.write(abs(motor2PWM));
annesteenbeek 31:8fbee6c92753 183 }
annesteenbeek 31:8fbee6c92753 184
annesteenbeek 0:525558a26464 185 void servoControl(){
annesteenbeek 107:de47331612d9 186 servo.SetPosition(1300 + 700*servoSpeed);
annesteenbeek 25:874675516927 187 }
annesteenbeek 25:874675516927 188
annesteenbeek 106:1773bf7b95c5 189 bool calibrateMotors(){
annesteenbeek 98:25528494287d 190 safetyOn = false; // safety springs off
annesteenbeek 98:25528494287d 191 motorsEnable = true; // motors on
annesteenbeek 98:25528494287d 192 redLed.write(0); greenLed.write(1); blueLed.write(1);
annesteenbeek 98:25528494287d 193 while (calibrating1 || calibrating2){
annesteenbeek 98:25528494287d 194 if (calibrating1){
annesteenbeek 98:25528494287d 195 redLed.write(1); greenLed.write(0); blueLed.write(1);
annesteenbeek 98:25528494287d 196 if(safetyIn.read() !=1){ // check if arm reached safety position
annesteenbeek 98:25528494287d 197 encoder1.setPosition(0); // set motor 1 cal angle
annesteenbeek 98:25528494287d 198 motor1SetSpeed = returnSpeed; // move away
annesteenbeek 98:25528494287d 199 springHit = true;
annesteenbeek 98:25528494287d 200 }else{
annesteenbeek 98:25528494287d 201 if(springHit){ // if hit and after is no longer touching spring
annesteenbeek 98:25528494287d 202 motor1SetSpeed = 0;
annesteenbeek 98:25528494287d 203 springHit = false;
annesteenbeek 98:25528494287d 204 calibrating1 = false;
annesteenbeek 98:25528494287d 205 calibrating2 = true; // start calibrating 2
annesteenbeek 98:25528494287d 206 }
annesteenbeek 98:25528494287d 207 }
annesteenbeek 98:25528494287d 208 }
annesteenbeek 98:25528494287d 209 if (calibrating2){
annesteenbeek 98:25528494287d 210 motor2SetSpeed = motorCalSpeed;
annesteenbeek 98:25528494287d 211 redLed.write(1); greenLed.write(1); blueLed.write(0);
annesteenbeek 98:25528494287d 212 if(safetyIn.read() !=1){ // check if arm reached safety position
annesteenbeek 98:25528494287d 213 encoder2.setPosition(0); // set motor 2 cal angle
annesteenbeek 98:25528494287d 214 motor2SetSpeed = returnSpeed; // move away
annesteenbeek 98:25528494287d 215 springHit = true;
annesteenbeek 98:25528494287d 216 }else{
annesteenbeek 98:25528494287d 217 if(springHit){ // if hit and after is no longer touching spring
annesteenbeek 98:25528494287d 218 motor2SetSpeed = 0;
annesteenbeek 98:25528494287d 219 springHit = false;
annesteenbeek 98:25528494287d 220 calibrating2 = false; // stop calibrating 2
annesteenbeek 98:25528494287d 221 }
annesteenbeek 98:25528494287d 222 }
annesteenbeek 98:25528494287d 223 }
annesteenbeek 98:25528494287d 224 now = t.read(); // call motor using timer instead of wait
annesteenbeek 98:25528494287d 225 if(now - lastCall > motorCall){
annesteenbeek 98:25528494287d 226 motorControl();
annesteenbeek 98:25528494287d 227 lastCall = now;
annesteenbeek 98:25528494287d 228 }
annesteenbeek 98:25528494287d 229
annesteenbeek 98:25528494287d 230 }
annesteenbeek 99:7030e9790b1d 231 motorsEnable = false; // turn motor's off again
annesteenbeek 76:0aa90e728e4a 232 safetyOn = true; // turn safety on after callibration
annesteenbeek 106:1773bf7b95c5 233 return true; // return true wehn finished
annesteenbeek 74:75be98779124 234 }
annesteenbeek 74:75be98779124 235
annesteenbeek 74:75be98779124 236
annesteenbeek 74:75be98779124 237 void safety(){
annesteenbeek 74:75be98779124 238 if (safetyOn){
annesteenbeek 81:71e7e98deb2c 239 if (safetyIn.read() != 1){
annesteenbeek 79:cf500b63f349 240 motorsEnable = false;
annesteenbeek 79:cf500b63f349 241 }
annesteenbeek 74:75be98779124 242 }
annesteenbeek 79:cf500b63f349 243 }
annesteenbeek 106:1773bf7b95c5 244
annesteenbeek 106:1773bf7b95c5 245
annesteenbeek 106:1773bf7b95c5 246 bool kinematics(){
annesteenbeek 107:de47331612d9 247 // // calculate current x and Y
annesteenbeek 107:de47331612d9 248 // X = L2*cos((motor1Pos + motor2Pos)*PI/180) + L1*cos(motor1Pos*PI/180);
annesteenbeek 107:de47331612d9 249 // Y = L2*sin((motor1Pos + motor2Pos)*PI/180) + L1*sin(motor1Pos*PI/180);
annesteenbeek 107:de47331612d9 250 // // check if x and y are within limits
annesteenbeek 107:de47331612d9 251 // // else Store the constraint line
annesteenbeek 107:de47331612d9 252 // // check if movement is in direction of constraint
annesteenbeek 107:de47331612d9 253 // // else return false no movement (anglespeed = 0)
annesteenbeek 107:de47331612d9 254 // // calculate required angle speeds
annesteenbeek 107:de47331612d9 255 // if( (X>Xmax && setXSpeed > 0 )|| \
annesteenbeek 107:de47331612d9 256 // (X<Xmin && setXSpeed < 0 )|| \
annesteenbeek 107:de47331612d9 257 // (Y>Ymax && setYSpeed > 0 )|| \
annesteenbeek 107:de47331612d9 258 // (Y<Ymin && setYSpeed < 0 ) \
annesteenbeek 107:de47331612d9 259 // ){
annesteenbeek 107:de47331612d9 260 // motor1SetSpeed = 0;
annesteenbeek 107:de47331612d9 261 // motor2SetSpeed = 0;
annesteenbeek 107:de47331612d9 262 // return false;
annesteenbeek 107:de47331612d9 263 // break;
annesteenbeek 107:de47331612d9 264 // }
annesteenbeek 107:de47331612d9 265 // motor1SetSpeed = (setXSpeed*cos((motor1Pos + motor2Pos)*PI/180) + \
annesteenbeek 107:de47331612d9 266 // setYSpeed*sin((motor1Pos + motor2Pos)*PI/180))/(L1*sin(motor2Pos*PI/180));
annesteenbeek 107:de47331612d9 267 // motor2SetSpeed = -(setXSpeed*L2*cos((motor1Pos + motor2Pos)*PI/180) + \
annesteenbeek 107:de47331612d9 268 // setYSpeed*L2*sin((motor1Pos + motor2Pos)*PI/180) + \
annesteenbeek 107:de47331612d9 269 // setXSpeed*L1*cos(motor1Pos*PI/180) + \
annesteenbeek 107:de47331612d9 270 // setYSpeed*L1*sin(motor1Pos*PI/180))/(L1*L2*sin(motor2Pos*PI/180));
annesteenbeek 106:1773bf7b95c5 271
annesteenbeek 106:1773bf7b95c5 272 }