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