Bachelor Assignment for delayed teleoperating systems
Dependencies: EthernetInterface FastPWM mbed-rtos mbed MODSERIAL
main.cpp@9:16044ec419af, 2018-05-30 (annotated)
- Committer:
- darth_bachious
- Date:
- Wed May 30 14:52:34 2018 +0000
- Revision:
- 9:16044ec419af
- Parent:
- 8:5c891d5ebe45
- Child:
- 10:694de5b31fd6
Switched to MODSERIAL,; updated the numbers; Pos-force / force-pos functional; ; strange vibration observed in pos-pos;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
darth_bachious | 0:2f89dec3e2ab | 1 | #include "mbed.h" |
darth_bachious | 0:2f89dec3e2ab | 2 | #include "EthernetInterface.h" |
darth_bachious | 0:2f89dec3e2ab | 3 | #include "rtos.h" |
darth_bachious | 2:c27b0654cffd | 4 | #include <vector> |
darth_bachious | 5:4d5b077b3fe6 | 5 | #include "FastPWM.h" |
darth_bachious | 6:ccbbf4c77d35 | 6 | #include <cmath> |
darth_bachious | 9:16044ec419af | 7 | #include "MODSERIAL.h" |
darth_bachious | 0:2f89dec3e2ab | 8 | |
darth_bachious | 1:853939e38acd | 9 | //Master or Slave? 1=Master, 0=Slave |
darth_bachious | 7:984f363f5e87 | 10 | static const int identity = 0; |
darth_bachious | 0:2f89dec3e2ab | 11 | |
darth_bachious | 0:2f89dec3e2ab | 12 | //network config |
darth_bachious | 1:853939e38acd | 13 | static const char* master_ip = "192.168.1.101"; |
darth_bachious | 1:853939e38acd | 14 | static const char* slave_ip = "192.168.1.102"; |
darth_bachious | 1:853939e38acd | 15 | static const char* MASK = "255.255.255.0"; |
darth_bachious | 1:853939e38acd | 16 | static const char* GATEWAY = "192.168.1.1"; |
darth_bachious | 9:16044ec419af | 17 | static const char* laptop_IP = "192.168.1.103"; |
darth_bachious | 0:2f89dec3e2ab | 18 | static const int port = 865; |
darth_bachious | 0:2f89dec3e2ab | 19 | |
darth_bachious | 9:16044ec419af | 20 | |
darth_bachious | 0:2f89dec3e2ab | 21 | //declaration of interfaces |
darth_bachious | 0:2f89dec3e2ab | 22 | DigitalOut led(LED_GREEN); |
darth_bachious | 0:2f89dec3e2ab | 23 | DigitalOut led2(LED_RED); |
darth_bachious | 0:2f89dec3e2ab | 24 | EthernetInterface eth; //network |
darth_bachious | 0:2f89dec3e2ab | 25 | Serial pc(USBTX, USBRX);//create PC interface |
darth_bachious | 0:2f89dec3e2ab | 26 | UDPSocket socket; //socket to receive data on |
darth_bachious | 0:2f89dec3e2ab | 27 | Endpoint client; //The virtual other side, not to send actual information to |
darth_bachious | 0:2f89dec3e2ab | 28 | Endpoint counterpart; //The actual other side, this is where the information should go to |
darth_bachious | 9:16044ec419af | 29 | Endpoint laptop; |
darth_bachious | 6:ccbbf4c77d35 | 30 | InterruptIn Button1(SW2); |
darth_bachious | 6:ccbbf4c77d35 | 31 | InterruptIn Button2(SW3); |
darth_bachious | 5:4d5b077b3fe6 | 32 | Ticker controllerloop; |
darth_bachious | 0:2f89dec3e2ab | 33 | Ticker mainloop; |
darth_bachious | 6:ccbbf4c77d35 | 34 | DigitalOut debug(D11); |
darth_bachious | 0:2f89dec3e2ab | 35 | |
darth_bachious | 4:610b5051182a | 36 | //Motor interfaces and variables |
darth_bachious | 3:376fccdc7cd6 | 37 | InterruptIn EncoderA(D2); |
darth_bachious | 6:ccbbf4c77d35 | 38 | DigitalIn EncoderB(D3); |
darth_bachious | 3:376fccdc7cd6 | 39 | DigitalOut M1_DIR(D4); |
darth_bachious | 5:4d5b077b3fe6 | 40 | FastPWM M1_pwm(D5); |
darth_bachious | 4:610b5051182a | 41 | AnalogIn measuredForce(A5); |
darth_bachious | 4:610b5051182a | 42 | |
darth_bachious | 4:610b5051182a | 43 | //Low pass filter filter coeffs, 2nd order, 50 Hz |
darth_bachious | 4:610b5051182a | 44 | double b[3] = {0.020083365564211, 0.020083365564211*2, 0.020083365564211}; |
darth_bachious | 4:610b5051182a | 45 | double a[3] = {1.00000000000000, -1.561018075, 0.64135153805}; |
darth_bachious | 4:610b5051182a | 46 | |
darth_bachious | 4:610b5051182a | 47 | //variables related to networking |
darth_bachious | 7:984f363f5e87 | 48 | char data[25]= {""}; |
darth_bachious | 9:16044ec419af | 49 | char output[25] = {""}; |
darth_bachious | 9:16044ec419af | 50 | char status[17] = {""}; |
darth_bachious | 0:2f89dec3e2ab | 51 | int size; |
darth_bachious | 7:984f363f5e87 | 52 | unsigned int counter = 1; |
darth_bachious | 7:984f363f5e87 | 53 | unsigned int counter_received = 1; |
darth_bachious | 7:984f363f5e87 | 54 | unsigned int check = 1; |
darth_bachious | 9:16044ec419af | 55 | |
darth_bachious | 2:c27b0654cffd | 56 | float input = 0.0; |
darth_bachious | 4:610b5051182a | 57 | |
darth_bachious | 4:610b5051182a | 58 | //measured variables |
darth_bachious | 2:c27b0654cffd | 59 | float angle = 0.0; |
darth_bachious | 5:4d5b077b3fe6 | 60 | int encoderPos = 0; |
darth_bachious | 5:4d5b077b3fe6 | 61 | int prev_encoderPos = 0; |
darth_bachious | 4:610b5051182a | 62 | float encoder_vel = 0.0; |
darth_bachious | 4:610b5051182a | 63 | float motor_vel = 0.0; |
darth_bachious | 4:610b5051182a | 64 | float force = 0.0; |
darth_bachious | 5:4d5b077b3fe6 | 65 | float control_torque = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 66 | float force_offset = 0.5; |
darth_bachious | 3:376fccdc7cd6 | 67 | |
darth_bachious | 4:610b5051182a | 68 | //Reference, used in admittance |
darth_bachious | 4:610b5051182a | 69 | float ref_angle = 0.0; |
darth_bachious | 4:610b5051182a | 70 | float ref_vel = 0.0; |
darth_bachious | 4:610b5051182a | 71 | float ref_acc = 0.0; |
darth_bachious | 9:16044ec419af | 72 | const float virtualInertia = 0.03; |
darth_bachious | 9:16044ec419af | 73 | const float virtualDamping = 0.1; |
darth_bachious | 9:16044ec419af | 74 | const float arm = 0.08; |
darth_bachious | 9:16044ec419af | 75 | const float max_velocity = 0.8; |
darth_bachious | 4:610b5051182a | 76 | |
darth_bachious | 6:ccbbf4c77d35 | 77 | //Controller required variables |
darth_bachious | 5:4d5b077b3fe6 | 78 | bool controller_check = 0; |
darth_bachious | 7:984f363f5e87 | 79 | const float looptime = 1.0/50.0; //50Hz, for the controller |
darth_bachious | 9:16044ec419af | 80 | const float ADDMlooptime = 1.0/2000; //2KHz, for the admittance controller |
darth_bachious | 6:ccbbf4c77d35 | 81 | enum States {stateCalibration, stateHoming, stateOperation}; |
darth_bachious | 4:610b5051182a | 82 | int currentState = stateCalibration; |
darth_bachious | 6:ccbbf4c77d35 | 83 | int transparancy = 1; // 1=Pos-Pos, 2=Pos-Force, 3=Force-Pos |
darth_bachious | 6:ccbbf4c77d35 | 84 | int passivity =0; // 0=off, 1=on |
darth_bachious | 6:ccbbf4c77d35 | 85 | int received_transparancy = 1; |
darth_bachious | 6:ccbbf4c77d35 | 86 | int received_passivity = 0; |
darth_bachious | 4:610b5051182a | 87 | |
darth_bachious | 4:610b5051182a | 88 | //Controller parameters |
darth_bachious | 9:16044ec419af | 89 | const float Ktl = 4.5; //high level controller parameters |
darth_bachious | 3:376fccdc7cd6 | 90 | const float Dtl=0.1; |
darth_bachious | 9:16044ec419af | 91 | const float Kp = 100; //low level controller parameters |
darth_bachious | 9:16044ec419af | 92 | const float Dp = 0.3; |
darth_bachious | 6:ccbbf4c77d35 | 93 | float u = 0.0; //serves as input variable for the motor; |
darth_bachious | 4:610b5051182a | 94 | |
darth_bachious | 6:ccbbf4c77d35 | 95 | //passivity layer constant |
darth_bachious | 9:16044ec419af | 96 | const float beta = 0.2218; |
darth_bachious | 9:16044ec419af | 97 | const float Hd = 0.0309; |
darth_bachious | 9:16044ec419af | 98 | const float alpha = 5.6705; |
darth_bachious | 6:ccbbf4c77d35 | 99 | |
darth_bachious | 6:ccbbf4c77d35 | 100 | //passivity layer variables |
darth_bachious | 6:ccbbf4c77d35 | 101 | float tank = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 102 | float prev_ref_angle = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 103 | float package_out = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 104 | float received_package = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 105 | float prev_torque = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 106 | |
darth_bachious | 4:610b5051182a | 107 | |
darth_bachious | 4:610b5051182a | 108 | //Constants |
darth_bachious | 0:2f89dec3e2ab | 109 | const float PI = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; |
darth_bachious | 2:c27b0654cffd | 110 | const float RadsPerCount = (2 * PI)/(1024*10); |
darth_bachious | 4:610b5051182a | 111 | const float FORCESENSORGAIN = 15.134; |
darth_bachious | 4:610b5051182a | 112 | const int MAX_ENCODER_LEFT = 1333; |
darth_bachious | 4:610b5051182a | 113 | const int MAX_ENCODER_RIGHT = -1453; |
darth_bachious | 5:4d5b077b3fe6 | 114 | const float WORKSPACEBOUND = PI/6; |
darth_bachious | 2:c27b0654cffd | 115 | |
darth_bachious | 6:ccbbf4c77d35 | 116 | const int frequency_pwm = 20000; |
darth_bachious | 0:2f89dec3e2ab | 117 | |
darth_bachious | 4:610b5051182a | 118 | //Time delay related variables |
darth_bachious | 9:16044ec419af | 119 | float timedelay = 0.10; //SECONDS |
darth_bachious | 6:ccbbf4c77d35 | 120 | int delaysteps = timedelay/looptime; |
darth_bachious | 8:5c891d5ebe45 | 121 | std::vector<float> delayArrayINPUT(max(delaysteps,1),0.0); |
darth_bachious | 8:5c891d5ebe45 | 122 | std::vector<float> delayArrayMODE(max(delaysteps,1),0.0); |
darth_bachious | 8:5c891d5ebe45 | 123 | std::vector<float> delayArrayPASS(max(delaysteps,1),0.0); |
darth_bachious | 8:5c891d5ebe45 | 124 | std::vector<float> delayArrayENERGY(max(delaysteps,1),0.0); |
darth_bachious | 4:610b5051182a | 125 | Timer t; |
darth_bachious | 4:610b5051182a | 126 | |
darth_bachious | 3:376fccdc7cd6 | 127 | //FUNCTIONS START HERE |
darth_bachious | 3:376fccdc7cd6 | 128 | |
darth_bachious | 3:376fccdc7cd6 | 129 | void encoderFunctionA() |
darth_bachious | 3:376fccdc7cd6 | 130 | { |
darth_bachious | 3:376fccdc7cd6 | 131 | if ((bool)EncoderA == (bool)EncoderB) { //Increment or decrement encoder position during interrupt |
darth_bachious | 3:376fccdc7cd6 | 132 | encoderPos++; |
darth_bachious | 3:376fccdc7cd6 | 133 | } else { |
darth_bachious | 3:376fccdc7cd6 | 134 | encoderPos--; |
darth_bachious | 3:376fccdc7cd6 | 135 | } |
darth_bachious | 3:376fccdc7cd6 | 136 | } |
darth_bachious | 4:610b5051182a | 137 | double velocityFilter(float x) |
darth_bachious | 4:610b5051182a | 138 | { |
darth_bachious | 4:610b5051182a | 139 | double y = 0.0; //Output |
darth_bachious | 4:610b5051182a | 140 | static double y_1 = 0.0; //Output last loop |
darth_bachious | 4:610b5051182a | 141 | static double y_2 = 0.0; //Output 2 loops ago |
darth_bachious | 4:610b5051182a | 142 | static double x_1 = 0.0; //Input last loop |
darth_bachious | 4:610b5051182a | 143 | static double x_2 = 0.0; //Input two loops ago |
darth_bachious | 3:376fccdc7cd6 | 144 | |
darth_bachious | 4:610b5051182a | 145 | //Finite difference equation for 2nd order Butterworth low-pass |
darth_bachious | 4:610b5051182a | 146 | y = -a[1]*y_1 - a[2]*y_2 + x*b[0] + x_1*b[1] + x_2*b[2]; |
darth_bachious | 4:610b5051182a | 147 | y_2 = y_1; |
darth_bachious | 4:610b5051182a | 148 | y_1 = y; |
darth_bachious | 4:610b5051182a | 149 | x_2 = x_1; |
darth_bachious | 4:610b5051182a | 150 | x_1 = x; |
darth_bachious | 4:610b5051182a | 151 | return (float)y; |
darth_bachious | 4:610b5051182a | 152 | } |
darth_bachious | 0:2f89dec3e2ab | 153 | |
darth_bachious | 0:2f89dec3e2ab | 154 | void inet_eth(){ |
darth_bachious | 1:853939e38acd | 155 | if(identity==1) |
darth_bachious | 1:853939e38acd | 156 | { |
darth_bachious | 1:853939e38acd | 157 | eth.init(master_ip, MASK,GATEWAY); |
darth_bachious | 1:853939e38acd | 158 | eth.connect(); |
darth_bachious | 0:2f89dec3e2ab | 159 | |
darth_bachious | 1:853939e38acd | 160 | socket.bind(port); |
darth_bachious | 1:853939e38acd | 161 | counterpart.set_address(slave_ip,port); |
darth_bachious | 9:16044ec419af | 162 | laptop.set_address(laptop_IP,port); |
darth_bachious | 1:853939e38acd | 163 | } |
darth_bachious | 1:853939e38acd | 164 | else if(identity==0) |
darth_bachious | 1:853939e38acd | 165 | { |
darth_bachious | 1:853939e38acd | 166 | eth.init(slave_ip, MASK,GATEWAY); |
darth_bachious | 1:853939e38acd | 167 | eth.connect(); |
darth_bachious | 1:853939e38acd | 168 | |
darth_bachious | 1:853939e38acd | 169 | socket.bind(port); |
darth_bachious | 9:16044ec419af | 170 | counterpart.set_address(master_ip,port); |
darth_bachious | 9:16044ec419af | 171 | laptop.set_address(laptop_IP,port+1); |
darth_bachious | 1:853939e38acd | 172 | } |
darth_bachious | 1:853939e38acd | 173 | |
darth_bachious | 0:2f89dec3e2ab | 174 | } |
darth_bachious | 0:2f89dec3e2ab | 175 | |
darth_bachious | 0:2f89dec3e2ab | 176 | void inet_USB(){ |
darth_bachious | 2:c27b0654cffd | 177 | pc.baud(115200); |
darth_bachious | 0:2f89dec3e2ab | 178 | } |
darth_bachious | 0:2f89dec3e2ab | 179 | |
darth_bachious | 0:2f89dec3e2ab | 180 | |
darth_bachious | 0:2f89dec3e2ab | 181 | void end_eth(){ |
darth_bachious | 0:2f89dec3e2ab | 182 | socket.close(); |
darth_bachious | 0:2f89dec3e2ab | 183 | eth.disconnect(); |
darth_bachious | 0:2f89dec3e2ab | 184 | } |
darth_bachious | 0:2f89dec3e2ab | 185 | |
darth_bachious | 5:4d5b077b3fe6 | 186 | void controllertrigger() |
darth_bachious | 0:2f89dec3e2ab | 187 | { |
darth_bachious | 5:4d5b077b3fe6 | 188 | controller_check = 1; |
darth_bachious | 0:2f89dec3e2ab | 189 | } |
darth_bachious | 2:c27b0654cffd | 190 | |
darth_bachious | 4:610b5051182a | 191 | |
darth_bachious | 2:c27b0654cffd | 192 | float update_delay(std::vector<float>&array, float new_value) |
darth_bachious | 2:c27b0654cffd | 193 | { |
darth_bachious | 8:5c891d5ebe45 | 194 | float return_value = array[0]; |
darth_bachious | 3:376fccdc7cd6 | 195 | for (int i=0; i<array.size()-1; ++i) |
darth_bachious | 3:376fccdc7cd6 | 196 | { |
darth_bachious | 3:376fccdc7cd6 | 197 | array[i]=array[i+1]; |
darth_bachious | 3:376fccdc7cd6 | 198 | } |
darth_bachious | 3:376fccdc7cd6 | 199 | array.back() = new_value; |
darth_bachious | 3:376fccdc7cd6 | 200 | return return_value; |
darth_bachious | 3:376fccdc7cd6 | 201 | } |
darth_bachious | 3:376fccdc7cd6 | 202 | |
darth_bachious | 3:376fccdc7cd6 | 203 | void limit(float &x, float lower, float upper) |
darth_bachious | 3:376fccdc7cd6 | 204 | { |
darth_bachious | 3:376fccdc7cd6 | 205 | if (x > upper) |
darth_bachious | 3:376fccdc7cd6 | 206 | x = upper; |
darth_bachious | 3:376fccdc7cd6 | 207 | if (x < lower) |
darth_bachious | 3:376fccdc7cd6 | 208 | x = lower; |
darth_bachious | 3:376fccdc7cd6 | 209 | } |
darth_bachious | 3:376fccdc7cd6 | 210 | |
darth_bachious | 4:610b5051182a | 211 | void motor_update(float PWM) //angle required to safeguard it from crashing into its stops |
darth_bachious | 4:610b5051182a | 212 | { |
darth_bachious | 4:610b5051182a | 213 | limit(PWM,-1.0f,1.0f); |
darth_bachious | 4:610b5051182a | 214 | if(PWM >= 0.0f) |
darth_bachious | 4:610b5051182a | 215 | { |
darth_bachious | 4:610b5051182a | 216 | M1_DIR = false; |
darth_bachious | 4:610b5051182a | 217 | M1_pwm = PWM; |
darth_bachious | 4:610b5051182a | 218 | } else { |
darth_bachious | 4:610b5051182a | 219 | M1_DIR = true; |
darth_bachious | 4:610b5051182a | 220 | M1_pwm = -PWM; |
darth_bachious | 4:610b5051182a | 221 | } |
darth_bachious | 4:610b5051182a | 222 | } |
darth_bachious | 4:610b5051182a | 223 | |
darth_bachious | 4:610b5051182a | 224 | void sensorUpdate() |
darth_bachious | 4:610b5051182a | 225 | { |
darth_bachious | 4:610b5051182a | 226 | angle = encoderPos * RadsPerCount; |
darth_bachious | 5:4d5b077b3fe6 | 227 | encoder_vel = (encoderPos - prev_encoderPos)/ADDMlooptime; //careful, this function should be called every 1/5000 seconds |
darth_bachious | 4:610b5051182a | 228 | motor_vel = velocityFilter(encoder_vel * RadsPerCount); |
darth_bachious | 4:610b5051182a | 229 | prev_encoderPos = encoderPos; |
darth_bachious | 6:ccbbf4c77d35 | 230 | force = -FORCESENSORGAIN*2.0f*(measuredForce - force_offset); //Measured force |
darth_bachious | 4:610b5051182a | 231 | } |
darth_bachious | 4:610b5051182a | 232 | |
darth_bachious | 4:610b5051182a | 233 | void doCalibration() |
darth_bachious | 4:610b5051182a | 234 | { |
darth_bachious | 8:5c891d5ebe45 | 235 | u = -0.15; |
darth_bachious | 4:610b5051182a | 236 | motor_update(u); |
darth_bachious | 6:ccbbf4c77d35 | 237 | led2=0; |
darth_bachious | 6:ccbbf4c77d35 | 238 | led=1; |
darth_bachious | 4:610b5051182a | 239 | //switching states |
darth_bachious | 6:ccbbf4c77d35 | 240 | if((abs(motor_vel)<0.001f)&& t.read()>3.0f) |
darth_bachious | 3:376fccdc7cd6 | 241 | { |
darth_bachious | 8:5c891d5ebe45 | 242 | encoderPos = MAX_ENCODER_RIGHT; |
darth_bachious | 4:610b5051182a | 243 | ref_angle = encoderPos * RadsPerCount; |
darth_bachious | 4:610b5051182a | 244 | currentState = stateHoming; |
darth_bachious | 4:610b5051182a | 245 | t.stop(); |
darth_bachious | 4:610b5051182a | 246 | } |
darth_bachious | 4:610b5051182a | 247 | } |
darth_bachious | 4:610b5051182a | 248 | |
darth_bachious | 4:610b5051182a | 249 | void doHoming() |
darth_bachious | 4:610b5051182a | 250 | { |
darth_bachious | 4:610b5051182a | 251 | led2=0; |
darth_bachious | 4:610b5051182a | 252 | led=0; |
darth_bachious | 8:5c891d5ebe45 | 253 | ref_vel = 0.2; |
darth_bachious | 8:5c891d5ebe45 | 254 | if(ref_angle < 0.0f) |
darth_bachious | 4:610b5051182a | 255 | { |
darth_bachious | 5:4d5b077b3fe6 | 256 | ref_angle += ref_vel*ADDMlooptime; //careful, this function should be called every 1/50 seconds |
darth_bachious | 4:610b5051182a | 257 | } |
darth_bachious | 4:610b5051182a | 258 | else |
darth_bachious | 4:610b5051182a | 259 | { |
darth_bachious | 4:610b5051182a | 260 | ref_angle = 0.0; |
darth_bachious | 4:610b5051182a | 261 | ref_vel = 0.0; |
darth_bachious | 4:610b5051182a | 262 | } |
darth_bachious | 4:610b5051182a | 263 | u = Kp*(ref_angle - angle) + Dp*(ref_vel - motor_vel); |
darth_bachious | 4:610b5051182a | 264 | motor_update(u); |
darth_bachious | 4:610b5051182a | 265 | |
darth_bachious | 4:610b5051182a | 266 | //switching states |
darth_bachious | 6:ccbbf4c77d35 | 267 | if ((abs(encoderPos)<20)&&abs((ref_vel - motor_vel)<0.02f)) |
darth_bachious | 4:610b5051182a | 268 | { |
darth_bachious | 4:610b5051182a | 269 | currentState = stateOperation; |
darth_bachious | 6:ccbbf4c77d35 | 270 | force_offset = measuredForce; |
darth_bachious | 4:610b5051182a | 271 | motor_update(0.0); |
darth_bachious | 5:4d5b077b3fe6 | 272 | led2=1; |
darth_bachious | 6:ccbbf4c77d35 | 273 | led=1; |
darth_bachious | 4:610b5051182a | 274 | } |
darth_bachious | 3:376fccdc7cd6 | 275 | |
darth_bachious | 4:610b5051182a | 276 | } |
darth_bachious | 4:610b5051182a | 277 | |
darth_bachious | 4:610b5051182a | 278 | void doOperation() |
darth_bachious | 4:610b5051182a | 279 | { |
darth_bachious | 9:16044ec419af | 280 | ref_acc = (force*arm + control_torque- virtualDamping*ref_vel)/virtualInertia; |
darth_bachious | 5:4d5b077b3fe6 | 281 | ref_vel += ref_acc*ADDMlooptime; |
darth_bachious | 9:16044ec419af | 282 | if(ref_vel>max_velocity) |
darth_bachious | 9:16044ec419af | 283 | ref_vel=max_velocity; |
darth_bachious | 9:16044ec419af | 284 | else if(ref_vel<-max_velocity) |
darth_bachious | 9:16044ec419af | 285 | ref_vel=-max_velocity; |
darth_bachious | 9:16044ec419af | 286 | |
darth_bachious | 9:16044ec419af | 287 | |
darth_bachious | 5:4d5b077b3fe6 | 288 | ref_angle += ref_vel*ADDMlooptime; |
darth_bachious | 5:4d5b077b3fe6 | 289 | if(ref_angle > WORKSPACEBOUND) |
darth_bachious | 5:4d5b077b3fe6 | 290 | { |
darth_bachious | 5:4d5b077b3fe6 | 291 | ref_vel = 0.0; |
darth_bachious | 5:4d5b077b3fe6 | 292 | ref_acc = 0.0; |
darth_bachious | 5:4d5b077b3fe6 | 293 | ref_angle = WORKSPACEBOUND; |
darth_bachious | 5:4d5b077b3fe6 | 294 | } else if(ref_angle < -WORKSPACEBOUND) |
darth_bachious | 5:4d5b077b3fe6 | 295 | { |
darth_bachious | 5:4d5b077b3fe6 | 296 | ref_vel = 0.0; |
darth_bachious | 5:4d5b077b3fe6 | 297 | ref_acc = 0.0; |
darth_bachious | 5:4d5b077b3fe6 | 298 | ref_angle = -WORKSPACEBOUND; |
darth_bachious | 5:4d5b077b3fe6 | 299 | } |
darth_bachious | 5:4d5b077b3fe6 | 300 | u = Kp*(ref_angle - angle) + Dp*(ref_vel - motor_vel); |
darth_bachious | 4:610b5051182a | 301 | motor_update(u); |
darth_bachious | 6:ccbbf4c77d35 | 302 | |
darth_bachious | 6:ccbbf4c77d35 | 303 | //no switching states for now |
darth_bachious | 5:4d5b077b3fe6 | 304 | } |
darth_bachious | 5:4d5b077b3fe6 | 305 | |
darth_bachious | 5:4d5b077b3fe6 | 306 | void loopfunction() |
darth_bachious | 5:4d5b077b3fe6 | 307 | { |
darth_bachious | 5:4d5b077b3fe6 | 308 | sensorUpdate(); |
darth_bachious | 5:4d5b077b3fe6 | 309 | switch(currentState) |
darth_bachious | 5:4d5b077b3fe6 | 310 | { |
darth_bachious | 5:4d5b077b3fe6 | 311 | case stateCalibration: |
darth_bachious | 5:4d5b077b3fe6 | 312 | doCalibration(); |
darth_bachious | 5:4d5b077b3fe6 | 313 | break; |
darth_bachious | 5:4d5b077b3fe6 | 314 | case stateHoming: |
darth_bachious | 5:4d5b077b3fe6 | 315 | doHoming(); |
darth_bachious | 5:4d5b077b3fe6 | 316 | break; |
darth_bachious | 5:4d5b077b3fe6 | 317 | case stateOperation: |
darth_bachious | 5:4d5b077b3fe6 | 318 | doOperation(); |
darth_bachious | 5:4d5b077b3fe6 | 319 | break; |
darth_bachious | 5:4d5b077b3fe6 | 320 | } |
darth_bachious | 4:610b5051182a | 321 | } |
darth_bachious | 0:2f89dec3e2ab | 322 | |
darth_bachious | 6:ccbbf4c77d35 | 323 | void updateTransparency() |
darth_bachious | 6:ccbbf4c77d35 | 324 | { |
darth_bachious | 6:ccbbf4c77d35 | 325 | transparancy++; |
darth_bachious | 6:ccbbf4c77d35 | 326 | if(transparancy>3) |
darth_bachious | 6:ccbbf4c77d35 | 327 | transparancy = 1; |
darth_bachious | 6:ccbbf4c77d35 | 328 | } |
darth_bachious | 6:ccbbf4c77d35 | 329 | |
darth_bachious | 6:ccbbf4c77d35 | 330 | void updatePassivity() |
darth_bachious | 6:ccbbf4c77d35 | 331 | { |
darth_bachious | 6:ccbbf4c77d35 | 332 | passivity++; |
darth_bachious | 6:ccbbf4c77d35 | 333 | if(passivity>1) |
darth_bachious | 6:ccbbf4c77d35 | 334 | passivity = 0; |
darth_bachious | 6:ccbbf4c77d35 | 335 | } |
darth_bachious | 6:ccbbf4c77d35 | 336 | |
darth_bachious | 6:ccbbf4c77d35 | 337 | float passivityLayer(float Ftl, float E_in) |
darth_bachious | 6:ccbbf4c77d35 | 338 | { |
darth_bachious | 6:ccbbf4c77d35 | 339 | tank = tank + E_in - prev_torque*(ref_angle-prev_ref_angle); |
darth_bachious | 6:ccbbf4c77d35 | 340 | if(tank>0.0f) |
darth_bachious | 6:ccbbf4c77d35 | 341 | { |
darth_bachious | 6:ccbbf4c77d35 | 342 | package_out = tank*beta; |
darth_bachious | 6:ccbbf4c77d35 | 343 | tank = tank - package_out; |
darth_bachious | 6:ccbbf4c77d35 | 344 | } else |
darth_bachious | 6:ccbbf4c77d35 | 345 | package_out = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 346 | |
darth_bachious | 6:ccbbf4c77d35 | 347 | float FMAX1 = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 348 | if(tank>0.0f) |
darth_bachious | 6:ccbbf4c77d35 | 349 | { |
darth_bachious | 8:5c891d5ebe45 | 350 | FMAX1 = abs(Ftl); |
darth_bachious | 6:ccbbf4c77d35 | 351 | } |
darth_bachious | 6:ccbbf4c77d35 | 352 | float FMAX2 = abs(tank/(ref_vel*looptime)); |
darth_bachious | 9:16044ec419af | 353 | float FMAX3 = 20.0; |
darth_bachious | 9:16044ec419af | 354 | if(identity==0) |
darth_bachious | 9:16044ec419af | 355 | { |
darth_bachious | 9:16044ec419af | 356 | FMAX3 = 0.7; |
darth_bachious | 9:16044ec419af | 357 | } |
darth_bachious | 6:ccbbf4c77d35 | 358 | prev_ref_angle = ref_angle; |
darth_bachious | 6:ccbbf4c77d35 | 359 | |
darth_bachious | 6:ccbbf4c77d35 | 360 | float Ftlc = 0.0; |
darth_bachious | 6:ccbbf4c77d35 | 361 | |
darth_bachious | 6:ccbbf4c77d35 | 362 | if((tank<Hd)&&(identity==1)) |
darth_bachious | 6:ccbbf4c77d35 | 363 | { |
darth_bachious | 6:ccbbf4c77d35 | 364 | Ftlc = - alpha*(Hd-tank)*ref_vel; |
darth_bachious | 6:ccbbf4c77d35 | 365 | } |
darth_bachious | 9:16044ec419af | 366 | //pc.printf("%f,%f,%f,%f\r\n",tank,Ftl,min(min(abs(Ftl),FMAX1),min(FMAX2,FMAX3)),Ftlc); |
darth_bachious | 6:ccbbf4c77d35 | 367 | //pc.printf("Ftlc: %f\r\n",Ftlc); |
darth_bachious | 6:ccbbf4c77d35 | 368 | //pc.printf("tank: %f\r\n",tank); |
darth_bachious | 6:ccbbf4c77d35 | 369 | if(Ftl>=0.0f) |
darth_bachious | 6:ccbbf4c77d35 | 370 | { |
darth_bachious | 6:ccbbf4c77d35 | 371 | prev_torque = min(min(abs(Ftl),FMAX1),min(FMAX2,FMAX3))+Ftlc; |
darth_bachious | 6:ccbbf4c77d35 | 372 | return min(min(abs(Ftl),FMAX1),min(FMAX2,FMAX3))+Ftlc; //min() only takes to arguments, so nested min()'s |
darth_bachious | 8:5c891d5ebe45 | 373 | //return 0.0; |
darth_bachious | 8:5c891d5ebe45 | 374 | } |
darth_bachious | 6:ccbbf4c77d35 | 375 | else |
darth_bachious | 6:ccbbf4c77d35 | 376 | { |
darth_bachious | 9:16044ec419af | 377 | prev_torque = -min(min(abs(Ftl),FMAX1),min(FMAX2,FMAX3))+Ftlc; |
darth_bachious | 8:5c891d5ebe45 | 378 | //return 0.0; |
darth_bachious | 9:16044ec419af | 379 | return -min(min(abs(Ftl),FMAX1),min(FMAX2,FMAX3))+Ftlc; |
darth_bachious | 6:ccbbf4c77d35 | 380 | } |
darth_bachious | 6:ccbbf4c77d35 | 381 | |
darth_bachious | 6:ccbbf4c77d35 | 382 | } |
darth_bachious | 6:ccbbf4c77d35 | 383 | |
darth_bachious | 7:984f363f5e87 | 384 | void generateOutput(float variable) |
darth_bachious | 7:984f363f5e87 | 385 | { |
darth_bachious | 7:984f363f5e87 | 386 | memcpy(&output[0],&counter,4); |
darth_bachious | 7:984f363f5e87 | 387 | memcpy(&output[4],&transparancy,4); |
darth_bachious | 7:984f363f5e87 | 388 | memcpy(&output[8],&passivity,4); |
darth_bachious | 7:984f363f5e87 | 389 | memcpy(&output[12],&variable,4); |
darth_bachious | 7:984f363f5e87 | 390 | memcpy(&output[16],&package_out,4); |
darth_bachious | 7:984f363f5e87 | 391 | //pc.printf("output:%i,%i,%i,%f,%f\r\n",counter,transparancy,passivity,variable,package_out); |
darth_bachious | 7:984f363f5e87 | 392 | |
darth_bachious | 7:984f363f5e87 | 393 | } |
darth_bachious | 9:16044ec419af | 394 | void generateStatus() |
darth_bachious | 9:16044ec419af | 395 | { |
darth_bachious | 9:16044ec419af | 396 | memcpy(&status[0],&counter,4); |
darth_bachious | 9:16044ec419af | 397 | memcpy(&status[4],&ref_angle,4); |
darth_bachious | 9:16044ec419af | 398 | memcpy(&status[8],&force,4); |
darth_bachious | 9:16044ec419af | 399 | memcpy(&status[12],&tank,4); |
darth_bachious | 9:16044ec419af | 400 | } |
darth_bachious | 7:984f363f5e87 | 401 | |
darth_bachious | 0:2f89dec3e2ab | 402 | void receiveUDP(void const *argument){ |
darth_bachious | 4:610b5051182a | 403 | while(true) |
darth_bachious | 4:610b5051182a | 404 | { |
darth_bachious | 0:2f89dec3e2ab | 405 | size = socket.receiveFrom(client, data, sizeof(data)); |
darth_bachious | 4:610b5051182a | 406 | if(size > 0) |
darth_bachious | 4:610b5051182a | 407 | { |
darth_bachious | 0:2f89dec3e2ab | 408 | data[size] = '\0'; |
darth_bachious | 7:984f363f5e87 | 409 | if(size>18) //first check, an minimum amount of data must have arrived |
darth_bachious | 4:610b5051182a | 410 | { |
darth_bachious | 7:984f363f5e87 | 411 | memcpy(&check,&data[0],4); |
darth_bachious | 7:984f363f5e87 | 412 | if(counter_received < check) //second check, data must be newer |
darth_bachious | 4:610b5051182a | 413 | { |
darth_bachious | 7:984f363f5e87 | 414 | counter_received=check; |
darth_bachious | 7:984f363f5e87 | 415 | memcpy(&received_transparancy,&data[4],4); |
darth_bachious | 7:984f363f5e87 | 416 | memcpy(&received_passivity,&data[8],4); |
darth_bachious | 7:984f363f5e87 | 417 | memcpy(&input,&data[12],4); |
darth_bachious | 7:984f363f5e87 | 418 | memcpy(&received_package,&data[16],4); |
darth_bachious | 7:984f363f5e87 | 419 | //pc.printf("data:%i,%i,%i,%f,%f\r\n",counter_received,received_transparancy,received_passivity,input,received_package); |
darth_bachious | 4:610b5051182a | 420 | } |
darth_bachious | 0:2f89dec3e2ab | 421 | } |
darth_bachious | 0:2f89dec3e2ab | 422 | } |
darth_bachious | 0:2f89dec3e2ab | 423 | } |
darth_bachious | 4:610b5051182a | 424 | } |
darth_bachious | 0:2f89dec3e2ab | 425 | |
darth_bachious | 0:2f89dec3e2ab | 426 | osThreadDef(receiveUDP, osPriorityNormal, DEFAULT_STACK_SIZE); |
darth_bachious | 0:2f89dec3e2ab | 427 | |
darth_bachious | 0:2f89dec3e2ab | 428 | int main(){ |
darth_bachious | 1:853939e38acd | 429 | inet_eth(); |
darth_bachious | 0:2f89dec3e2ab | 430 | inet_USB(); |
darth_bachious | 0:2f89dec3e2ab | 431 | |
darth_bachious | 0:2f89dec3e2ab | 432 | osThreadCreate(osThread(receiveUDP), NULL); |
darth_bachious | 0:2f89dec3e2ab | 433 | led2=1; |
darth_bachious | 0:2f89dec3e2ab | 434 | led=1; |
darth_bachious | 5:4d5b077b3fe6 | 435 | |
darth_bachious | 6:ccbbf4c77d35 | 436 | //Set all interrupt requests to 2nd place priority |
darth_bachious | 5:4d5b077b3fe6 | 437 | for(int n = 0; n < 86; n++) { |
darth_bachious | 5:4d5b077b3fe6 | 438 | NVIC_SetPriority((IRQn)n,1); |
darth_bachious | 5:4d5b077b3fe6 | 439 | } |
darth_bachious | 5:4d5b077b3fe6 | 440 | //Set out motor encoder interrupt to 1st place priority |
darth_bachious | 5:4d5b077b3fe6 | 441 | NVIC_SetPriority(PORTB_IRQn,0); |
darth_bachious | 6:ccbbf4c77d35 | 442 | |
darth_bachious | 5:4d5b077b3fe6 | 443 | controllerloop.attach(&controllertrigger,looptime); |
darth_bachious | 5:4d5b077b3fe6 | 444 | mainloop.attach(&loopfunction,ADDMlooptime); |
darth_bachious | 5:4d5b077b3fe6 | 445 | |
darth_bachious | 4:610b5051182a | 446 | M1_pwm.period(1.0/frequency_pwm); |
darth_bachious | 4:610b5051182a | 447 | EncoderA.rise(&encoderFunctionA); |
darth_bachious | 7:984f363f5e87 | 448 | |
darth_bachious | 7:984f363f5e87 | 449 | Button1.rise(&updateTransparency); |
darth_bachious | 7:984f363f5e87 | 450 | Button2.rise(&updatePassivity); |
darth_bachious | 6:ccbbf4c77d35 | 451 | |
darth_bachious | 4:610b5051182a | 452 | t.start(); |
darth_bachious | 3:376fccdc7cd6 | 453 | |
darth_bachious | 0:2f89dec3e2ab | 454 | while(true){ |
darth_bachious | 5:4d5b077b3fe6 | 455 | if(controller_check==1){ |
darth_bachious | 6:ccbbf4c77d35 | 456 | debug = 1; |
darth_bachious | 6:ccbbf4c77d35 | 457 | float received_input = update_delay(delayArrayINPUT,input); |
darth_bachious | 6:ccbbf4c77d35 | 458 | float current_transparancy = update_delay(delayArrayMODE,received_transparancy); |
darth_bachious | 6:ccbbf4c77d35 | 459 | float current_passivity = update_delay(delayArrayPASS,received_passivity); |
darth_bachious | 6:ccbbf4c77d35 | 460 | float package_in = update_delay(delayArrayENERGY,received_package); |
darth_bachious | 6:ccbbf4c77d35 | 461 | received_package = 0; //IMPORTANT, WILL EXPLODE OTHERWISE |
darth_bachious | 3:376fccdc7cd6 | 462 | |
darth_bachious | 6:ccbbf4c77d35 | 463 | if(identity==0) |
darth_bachious | 6:ccbbf4c77d35 | 464 | { |
darth_bachious | 6:ccbbf4c77d35 | 465 | transparancy = current_transparancy; |
darth_bachious | 6:ccbbf4c77d35 | 466 | passivity = current_passivity; |
darth_bachious | 6:ccbbf4c77d35 | 467 | if(transparancy==1) |
darth_bachious | 6:ccbbf4c77d35 | 468 | { |
darth_bachious | 6:ccbbf4c77d35 | 469 | float torque_tlc = Ktl*(received_input-ref_angle) - Dtl*ref_vel; |
darth_bachious | 6:ccbbf4c77d35 | 470 | if(current_passivity==1) |
darth_bachious | 6:ccbbf4c77d35 | 471 | control_torque = passivityLayer(torque_tlc,package_in); |
darth_bachious | 6:ccbbf4c77d35 | 472 | else |
darth_bachious | 6:ccbbf4c77d35 | 473 | control_torque = torque_tlc; |
darth_bachious | 7:984f363f5e87 | 474 | generateOutput(ref_angle); |
darth_bachious | 6:ccbbf4c77d35 | 475 | } |
darth_bachious | 6:ccbbf4c77d35 | 476 | else if(transparancy==2) |
darth_bachious | 6:ccbbf4c77d35 | 477 | { |
darth_bachious | 6:ccbbf4c77d35 | 478 | float torque_tlc = Ktl*(received_input-ref_angle) - Dtl*ref_vel; |
darth_bachious | 6:ccbbf4c77d35 | 479 | if(current_passivity==1) |
darth_bachious | 6:ccbbf4c77d35 | 480 | control_torque = passivityLayer(torque_tlc,package_in); |
darth_bachious | 6:ccbbf4c77d35 | 481 | else |
darth_bachious | 7:984f363f5e87 | 482 | control_torque = torque_tlc; |
darth_bachious | 7:984f363f5e87 | 483 | generateOutput(force); |
darth_bachious | 6:ccbbf4c77d35 | 484 | } |
darth_bachious | 6:ccbbf4c77d35 | 485 | else if(transparancy==3) |
darth_bachious | 6:ccbbf4c77d35 | 486 | { |
darth_bachious | 6:ccbbf4c77d35 | 487 | float torque_tlc = received_input*arm; |
darth_bachious | 6:ccbbf4c77d35 | 488 | if(current_passivity==1) |
darth_bachious | 6:ccbbf4c77d35 | 489 | control_torque = passivityLayer(torque_tlc,package_in); |
darth_bachious | 6:ccbbf4c77d35 | 490 | else |
darth_bachious | 7:984f363f5e87 | 491 | control_torque = torque_tlc; |
darth_bachious | 7:984f363f5e87 | 492 | generateOutput(ref_angle); |
darth_bachious | 6:ccbbf4c77d35 | 493 | } |
darth_bachious | 6:ccbbf4c77d35 | 494 | } |
darth_bachious | 6:ccbbf4c77d35 | 495 | else if(identity == 1) |
darth_bachious | 6:ccbbf4c77d35 | 496 | { |
darth_bachious | 6:ccbbf4c77d35 | 497 | if(transparancy==1) |
darth_bachious | 6:ccbbf4c77d35 | 498 | { |
darth_bachious | 6:ccbbf4c77d35 | 499 | float torque_tlc = Ktl*(received_input-ref_angle) - Dtl*ref_vel; |
darth_bachious | 6:ccbbf4c77d35 | 500 | if(current_passivity==1) |
darth_bachious | 6:ccbbf4c77d35 | 501 | control_torque = passivityLayer(torque_tlc,package_in); |
darth_bachious | 6:ccbbf4c77d35 | 502 | else |
darth_bachious | 7:984f363f5e87 | 503 | control_torque = torque_tlc; |
darth_bachious | 7:984f363f5e87 | 504 | generateOutput(ref_angle); |
darth_bachious | 6:ccbbf4c77d35 | 505 | } |
darth_bachious | 6:ccbbf4c77d35 | 506 | else if(transparancy==2) |
darth_bachious | 6:ccbbf4c77d35 | 507 | { |
darth_bachious | 6:ccbbf4c77d35 | 508 | float torque_tlc = received_input*arm; |
darth_bachious | 6:ccbbf4c77d35 | 509 | if(current_passivity==1) |
darth_bachious | 6:ccbbf4c77d35 | 510 | control_torque = passivityLayer(torque_tlc,package_in); |
darth_bachious | 6:ccbbf4c77d35 | 511 | else |
darth_bachious | 7:984f363f5e87 | 512 | control_torque = torque_tlc; |
darth_bachious | 7:984f363f5e87 | 513 | generateOutput(ref_angle); |
darth_bachious | 6:ccbbf4c77d35 | 514 | } |
darth_bachious | 6:ccbbf4c77d35 | 515 | else if(transparancy==3) |
darth_bachious | 6:ccbbf4c77d35 | 516 | { |
darth_bachious | 6:ccbbf4c77d35 | 517 | float torque_tlc = Ktl*(received_input-ref_angle) - Dtl*ref_vel; |
darth_bachious | 6:ccbbf4c77d35 | 518 | if(current_passivity==1) |
darth_bachious | 6:ccbbf4c77d35 | 519 | control_torque = passivityLayer(torque_tlc,package_in); |
darth_bachious | 6:ccbbf4c77d35 | 520 | else |
darth_bachious | 7:984f363f5e87 | 521 | control_torque = torque_tlc; |
darth_bachious | 7:984f363f5e87 | 522 | generateOutput(force); |
darth_bachious | 6:ccbbf4c77d35 | 523 | } |
darth_bachious | 6:ccbbf4c77d35 | 524 | } |
darth_bachious | 9:16044ec419af | 525 | pc.printf("force:%f, refpos:%f, pos:%f, tank:%f\r\n",force, ref_angle, angle, tank); |
darth_bachious | 7:984f363f5e87 | 526 | //pc.printf("received input: %i\r\n",received_input); |
darth_bachious | 9:16044ec419af | 527 | //pc.printf("ticks: %i\r\n",encoderPos); |
darth_bachious | 5:4d5b077b3fe6 | 528 | socket.sendTo(counterpart, output, sizeof(output)); |
darth_bachious | 9:16044ec419af | 529 | generateStatus(); |
darth_bachious | 9:16044ec419af | 530 | socket.sendTo(laptop,status,sizeof(status)); |
darth_bachious | 5:4d5b077b3fe6 | 531 | counter ++; |
darth_bachious | 6:ccbbf4c77d35 | 532 | led=!led; |
darth_bachious | 6:ccbbf4c77d35 | 533 | if(current_passivity==1) |
darth_bachious | 6:ccbbf4c77d35 | 534 | led2=0; |
darth_bachious | 6:ccbbf4c77d35 | 535 | else |
darth_bachious | 6:ccbbf4c77d35 | 536 | led2=1; |
darth_bachious | 5:4d5b077b3fe6 | 537 | controller_check = 0; |
darth_bachious | 6:ccbbf4c77d35 | 538 | debug = 0; |
darth_bachious | 0:2f89dec3e2ab | 539 | } |
darth_bachious | 4:610b5051182a | 540 | osDelay(0.1); //this might be the most ugliest piece of code that somehow still works. BK |
darth_bachious | 0:2f89dec3e2ab | 541 | } |
darth_bachious | 0:2f89dec3e2ab | 542 | } |