motor_controller.c
Go to the documentation of this file.00001
00066 #include <includes.h>
00067
00068
00069 static volatile signed long int mc_pwm = 0;
00070 static volatile fixed mc_target_current = 0;
00071
00072 static volatile fixed mc_c1 = 0;
00073 static volatile fixed mc_new_c1 = 0;
00074 static volatile fixed mc_c2 = 0;
00075 static volatile fixed mc_new_c2 = 0;
00076 static volatile fixed mc_command_current = 0;
00077
00078
00079 static volatile unsigned long int mc_therm_off = 0;
00080 static volatile unsigned long int mc_mech_off = 0;
00081 static volatile unsigned long int mc_off = 0;
00082 static volatile unsigned long int mc_sleep = 0;
00083 static volatile unsigned long int mc_shutdown = 0;
00084 static volatile unsigned long int mc_direction = 0;
00085
00086 static MC_DATA mc_data;
00087 static long int mc_positive = 1;
00088 static long int mc_negative = 1;
00089 static unsigned long int mc_phase;
00090
00091 static float mc_save_stiff;
00092 static float mc_save_damp;
00093 static float mc_save_comm;
00094
00116 void mc_init(float max_volts,
00117 float max_current,
00118 float min_current,
00119 float max_target,
00120 float min_target,
00121 float thermal_current_limit,
00122 float thermal_time_constant,
00123 float kp,
00124 float ki,
00125 float kd,
00126 int max_pwm,
00127 int error_limit,
00128 float smart_error_limit,
00129 MC_OPERATION op,
00130 FIXED_VOID_F current,
00131 FLOAT_VOID_F position,
00132 FLOAT_VOID_F velocity)
00133 {
00134 mc_data.operation = op;
00135
00136 mc_data.motor_voltage_max = max_volts;
00137 mc_data.current_max = float_to_fixed(max_current);
00138 mc_data.current_min = float_to_fixed(min_current);
00139 mc_data.target_max = float_to_fixed(max_target);
00140 mc_data.target_min = float_to_fixed(min_target);
00141
00142 mc_data.thermal_limit = float_to_fixed((thermal_current_limit*thermal_current_limit)*thermal_time_constant);
00143 mc_data.tau_inv = float_to_fixed(1.0/thermal_time_constant);
00144 mc_data.thermal_safe = fixed_mult(float_to_fixed(0.75), mc_data.thermal_limit);
00145 mc_data.thermal_diff = float_to_fixed(1.0/(thermal_current_limit - fixed_to_float(mc_data.thermal_safe)));
00146 mc_data.dt = float_to_fixed(1.0/(float)(1000*SCHED_SPEED));
00147
00148 mc_data.kp = float_to_fixed(kp);
00149 mc_data.ki = float_to_fixed(ki);
00150 mc_data.kd = float_to_fixed(kd);
00151 mc_data.integral = 0;
00152 mc_data.max_pwm = max_pwm;
00153 mc_data.max_integral = float_to_fixed((((float)max_pwm)/ki));
00154 mc_data.error_limit = error_limit;
00155 mc_data.smart_error_limit = float_to_fixed(smart_error_limit);
00156 mc_data.smart_error_limit_inverse = float_to_fixed(1.0*10.0/smart_error_limit);
00157 mc_data.get_current = current;
00158 mc_data.get_position = position;
00159 mc_data.get_velocity = velocity;
00160 }
00161
00167 void mc_set_target_current(float new_current)
00168 {
00169 fixed curr = float_to_fixed(new_current);
00170 mc_set_target_current_fixed(curr);
00171 }
00172
00179 static void mc_set_target_current_fixed(fixed current){
00180
00181 fixed curr = current;
00182 if (curr < mc_data.target_min){
00183 error_occurred(ERROR_MC_TCURR_OOB);
00184 curr = mc_data.target_min;
00185 }
00186 if (curr > mc_data.target_max){
00187 error_occurred(ERROR_MC_TCURR_OOB);
00188 curr = mc_data.target_max;
00189 }
00190 mc_target_current = curr;
00191 }
00192
00197 void mc_set_unsafe_target_current(float new_current)
00198 {
00199 fixed curr = float_to_fixed(new_current);
00200 mc_target_current = curr;
00201 }
00202
00213 void mc_compliant_control(void){
00214 float pos_rads = mc_data.get_position();
00215 fixed pos = float_to_fixed(pos_rads);
00216 fixed vel = float_to_fixed(mc_data.get_velocity());
00217 fixed control = mc_command_current - fixed_mult(mc_c1, pos) - fixed_mult(mc_c2, vel);
00218 mc_set_target_current_fixed(control);
00219 mc_pid_current();
00220 }
00221
00227 void mc_set_command_current(float new_command)
00228 {
00229 mc_command_current = float_to_fixed(new_command);
00230 mc_save_comm = new_command;
00231
00232 mc_c1 = mc_new_c1;
00233 mc_c2 = mc_new_c2;
00234 }
00235 float mc_get_command_current(void){
00236 return mc_save_comm;
00237 }
00238
00244 void mc_set_stiffness(float new_c1){
00245 mc_new_c1 = float_to_fixed(new_c1);
00246 mc_save_stiff = new_c1;
00247
00248 }
00249 float mc_get_stiffness(void){
00250 return mc_save_stiff;
00251 }
00252
00258 void mc_set_dampness(float new_c2){
00259 mc_new_c2 = float_to_fixed(new_c2);
00260 mc_save_damp = new_c2;
00261
00262 }
00263 float mc_get_dampness(void){
00264 return mc_save_damp;
00265 }
00266
00278 void mc_direction_control(MOTOR_DIRECTION direction, MOTOR_CONTROL command)
00279 {
00280 int dir = direction;
00281 if (dir == MC_POSITIVE){
00282 mc_positive = command;
00283 } else if (dir == MC_NEGATIVE){
00284 mc_negative = command;
00285 }
00286 }
00287
00295 static int mc_is_running(void){
00296 int running = (!mc_off) && (!mc_sleep) && (!mc_shutdown) && (!mc_therm_off) && (!mc_mech_off);
00297 if (!running)error_occurred(ERROR_MC_NOT_RUNNING);
00298 return running;
00299 }
00300
00308 MC_DATA* mc_get_parameters(void)
00309 {
00310 return &mc_data;
00311 }
00312
00317 int mc_get_pwm(void)
00318 {
00319 return mc_pwm;
00320 }
00321
00330 void mc_update_watchdog(void)
00331 {
00332 if (!mc_shutdown && !mc_off && !mc_therm_off && !mc_mech_off){
00333 if(FIO0PIN & (1<<6)){
00334 FIO0CLR = (1<<6);
00335 }
00336 else {
00337 FIO0SET = (1<<6);
00338 }
00339 }
00340 }
00341
00349 void mc_set_shutdown(int shutdown){
00350 unsigned long sd = ((unsigned long)shutdown) & 0x7FFF;
00351 mc_shutdown = sd;
00352 }
00353
00360 void mc_set_sleep(int sleep){
00361 unsigned long sl = ((unsigned long)sleep) & 0x7FFF;
00362 mc_sleep = sl;
00363 }
00364
00372 static void mc_turnoff(MC_SAFETY_CAUSE reason){
00373 switch(reason){
00374 case MC_THERM: mc_therm_off = 1;
00375 error_occurred(ERROR_MC_TEMP_OFF);
00376 break;
00377 case MC_MECH: mc_mech_off = 1;
00378 error_occurred(ERROR_MC_MECH_OFF);
00379 break;
00380 default: mc_off = 1;
00381 error_occurred(ERROR_MC_SHUTOFF);
00382 break;
00383 }
00384
00385 mc_pwm = 0;
00386 PWMMR2 = 0;
00387 PWMMR6 = 0;
00388 PWMLER = (1<<6)|(1<<2);
00389
00390 mcu_led_green_on();
00391 }
00392
00400 static void mc_turnon(MC_SAFETY_CAUSE reason){
00401 switch(reason){
00402 case MC_THERM: mc_therm_off = 0;
00403 error_occurred(ERROR_MC_TEMP_ON);
00404 break;
00405 case MC_MECH: mc_mech_off = 0;
00406 error_occurred(ERROR_MC_MECH_ON);
00407 break;
00408 default:
00409 break;
00410 }
00411
00412 mcu_led_green_off();
00413 }
00414
00419 void mc_set_pwm(int pwm)
00420 {
00421 const unsigned long int full = PWMMR0;
00422 const unsigned long int offset = 14;
00423
00424 if (!mc_is_running()){
00425 pwm = 0;
00426 } else if (pwm < 0) {
00427 pwm = pwm * mc_negative;
00428 } else if (pwm > 0) {
00429 pwm = pwm * mc_positive;
00430 }
00431
00432 pwm = mc_data.operation * pwm;
00433
00434 mc_pwm = pwm;
00435
00436 mc_update_watchdog();
00437
00438
00439 if (pwm > mc_data.max_pwm){
00440 pwm = mc_data.max_pwm;
00441 error_occurred(ERROR_MC_PWM_LIMIT);
00442 }
00443 else if (pwm < -1*mc_data.max_pwm){
00444 pwm = -1*mc_data.max_pwm;
00445 error_occurred(ERROR_MC_PWM_LIMIT);
00446 }
00447
00448 if (mc_phase == 0){
00449 if(pwm < 0) {
00450 PWMMR2 = 0;
00451 PWMMR6 = -1 * pwm;
00452 PWMLER = (1<<2)|(1<<6);
00453 }
00454 else {
00455 PWMMR2 = pwm;
00456 PWMMR6 = 0;
00457 PWMLER = (1<<2)|(1<<6);
00458 }
00459 mc_phase = 1;
00460 } else {
00461 if(pwm < 0) {
00462 PWMMR2 = full - (pwm * -1) - offset;
00463 PWMMR6 = full;
00464 PWMLER = (1<<2)|(1<<6);
00465 } else {
00466 PWMMR2 = full;
00467 PWMMR6 = full - (pwm) - offset;
00468 PWMLER = (1<<2)|(1<<6);
00469 }
00470 mc_phase = 0;
00471 }
00472 }
00473
00474 static float mc_mult;
00476 float mc_get_mult(void){ return mc_mult;}
00486 void mc_pid_current(void)
00487 {
00488 volatile fixed mc_error = 0;
00489 static unsigned char start_count = 2;
00490 signed long int curr_pwm = 0;
00491 long long int pid_sum, p_component, i_component;
00492 fixed thermal_multiplier, mechanical_multiplier;
00493
00494 mc_update_watchdog();
00495
00496 if (!start_count){
00497
00498 fixed current = mc_data.get_current();
00499 fixed target_current = mc_target_current;
00500 thermal_multiplier = mc_get_thermal_limiter(current);
00501 mechanical_multiplier = mc_smart_check_current(current);
00502
00503 if (mc_is_running()){
00504
00505
00506 mc_error = (target_current - current);
00507
00508 if (mc_negative && mc_positive){
00509 mc_data.integral += mc_error;
00510 }
00511
00512
00513 if (mc_data.integral > mc_data.max_integral){
00514 mc_data.integral = mc_data.max_integral;
00515 error_occurred(ERROR_MC_INTEG_SATUR);
00516 } else if (mc_data.integral < -1*mc_data.max_integral){
00517 mc_data.integral = -1*mc_data.max_integral;
00518 error_occurred(ERROR_MC_INTEG_SATUR);
00519 }
00520
00521
00522
00523 p_component = fixed_mult_to_long((mc_error),(mc_data.kp));
00524 i_component = fixed_mult_to_long((mc_data.integral),(mc_data.ki));
00525 pid_sum = p_component + i_component;
00526
00527
00528 if(pid_sum > FIXED_MAX) {
00529 pid_sum = FIXED_MAX;
00530 error_occurred(ERROR_MC_FIXED_LIMIT);
00531 } else if (pid_sum < -1*FIXED_MAX) {
00532 pid_sum = -1*FIXED_MAX;
00533 error_occurred(ERROR_MC_FIXED_LIMIT);
00534 }
00535
00536 if(thermal_multiplier < mechanical_multiplier){
00537 pid_sum = fixed_mult(pid_sum, thermal_multiplier);
00538 } else {
00539 pid_sum = fixed_mult(pid_sum, mechanical_multiplier);
00540 }
00541
00542 curr_pwm = fixed_to_int((pid_sum));
00543
00544
00545 if (curr_pwm > mc_data.max_pwm){
00546 curr_pwm = mc_data.max_pwm;
00547 error_occurred(ERROR_MC_PWM_LIMIT);
00548 }
00549 else if (curr_pwm < -1*mc_data.max_pwm){
00550 curr_pwm = -1*mc_data.max_pwm;
00551 error_occurred(ERROR_MC_PWM_LIMIT);
00552 }
00553
00554 mc_set_pwm(curr_pwm);
00555
00556 } else {
00557 mc_set_pwm(0);
00558 }
00559 } else {
00560 start_count--;
00561 }
00562 }
00563
00570 void mc_run_no_control(void)
00571 {
00572 if (mc_is_running()){
00573 mc_update_watchdog();
00574
00575 }
00576 }
00577
00588 static fixed mc_smart_check_current(fixed current){
00589
00590
00591 static fixed current_error = 0;
00592 fixed motor_current = current;
00593 static fixed multiplier = FIXED_ONE;
00594
00595
00596
00597
00598 if (motor_current > 0){
00599 current_error = current_error + (motor_current - mc_data.current_max);
00600 } else if (motor_current < 0){
00601 current_error = current_error - (motor_current - mc_data.current_min);
00602 }
00603 if (current_error <= 0){
00604 current_error = 0;
00605 if (mc_mech_off){
00606 mc_turnon(MC_MECH);
00607 }
00608 }
00609
00610
00611 multiplier = FIXED_ONE - (fixed_mult(current_error , mc_data.smart_error_limit_inverse));
00612 if (multiplier < 0){multiplier = 0;}
00613 mc_mult = fixed_to_float(multiplier);
00614
00615
00616
00617
00618
00619 if (current_error >= mc_data.smart_error_limit){
00620 mc_turnoff(MC_MECH);
00621 }
00622
00623
00624
00625
00626 return multiplier;
00627
00628 }
00629
00641 static fixed mc_get_thermal_limiter(fixed current){
00642
00643
00644
00645 static fixed multiplier = FIXED_ONE;
00646 static fixed a = 0;
00647
00648
00649 fixed a_dot_dt;
00650 fixed motor_current = current;
00651 a_dot_dt = fixed_mult((fixed_mult(motor_current, motor_current)-fixed_mult(mc_data.tau_inv, a)), mc_data.dt);
00652 a = a + a_dot_dt;
00653
00654
00655 if (a < mc_data.thermal_safe){
00656 multiplier = FIXED_ONE;
00657 if (mc_therm_off){
00658 mc_turnon(MC_THERM);
00659 }
00660 } else if (a >= mc_data.thermal_safe && a < mc_data.thermal_limit){
00661 multiplier = FIXED_ONE - (fixed_mult(a - mc_data.thermal_safe, mc_data.thermal_diff));
00662 error_occurred(ERROR_MC_TEMP_SAFE);
00663 } else if (a >= mc_data.thermal_limit){
00664 mc_turnoff(MC_THERM);
00665 multiplier = 0;
00666 } else {
00667 multiplier = FIXED_ONE;
00668 }
00669
00670 return multiplier;
00671
00672 }
00673
00674