Mircea Murar
/
Smart_Axis_2015_08_30_v12
SMC Axis control
main.cpp
- Committer:
- Mircea3M
- Date:
- 2016-04-12
- Revision:
- 0:bf14022d00d5
File content as of revision 0:bf14022d00d5:
#include "mbed.h" #include "I2C.h" #include "SLCD.h" // v12 // partea de control merge // intrarile de la controlerul SMC sunt inversate #define NO_POWER_SUPPLY 0x7F #define LECP6_IN_ALARM 0x60 #define RETURN_TO_ORIGIN 0x02 #define LECP6_SCAN_INPUTS 0x07 #define LECP6_MOVES 0x08 #define LECP6_DONE 0x09 #define LECP6_SETUP 0x0A #define LECP6_JOG 0x15 #define POSITION_OVERFLOW 0x11 #define POSITION_UNDERFLOW 0x12 #define POSITION_RECORDED 0x30 #define ESC 0x40 #define BUILD_CTRL 0x50 #define CTRL_CREATED 0x51 #define CTRL_RUN 0x52 #define LECP6_RST 0xFF Ticker operating_led; Ticker equipment_status; // 4 digit LCD SLCD slcd; /* I2C I2C_Comm(PTC9,PTC8); I2C I2C_LCD(PTC2,PTC1); const int addr = 0x90; //Serial UART_Comm(PTA2, PTA1); */ DigitalOut LED(PTE29); DigitalOut Relay_CTRL(PTE31); DigitalOut HP_Output(PTB19); DigitalIn Board_But_Left(PTC12); DigitalIn Board_But_Right(PTC3); // MCU Digital Output to control Axis/Gripper /* DigitalOut DO_A3_IN0(PTE18); DigitalOut DO_A4_IN1(PTE17); DigitalOut DO_A5_IN2(PTE16); DigitalOut DO_A6_IN3(PTE6); DigitalOut DO_A7_IN4(PTE3); DigitalOut DO_A8_IN5(PTE2); */ DigitalOut DO_A9_SETUP(PTA14); DigitalOut DO_A10_HOLD(PTA6); DigitalOut DO_A11_DRIVE(PTA7); DigitalOut DO_A12_RESET(PTC16); DigitalOut DO_A13_SVON(PTC13); // MCU Digital Input for feedback from Axis/Gripper DigitalIn DI_B1_OUT0(PTE19); DigitalIn DI_B2_OUT1(PTE1); DigitalIn DI_B3_OUT2(PTD7); DigitalIn DI_B4_OUT3(PTA17); DigitalIn DI_B5_OUT4(PTA16); DigitalIn DI_B6_OUT5(PTA15); DigitalIn DI_B7_BUSY(PTA13); DigitalIn DI_B8_AREA(PTD2); DigitalIn DI_B9_SETON(PTD4); DigitalIn DI_B10_INP(PTD6); DigitalIn DI_B11_SVRE(PTD7); DigitalIn DI_B12_ESTOP(PTD5); DigitalIn DI_B13_ALARM(PTE0); BusOut step_number(PTE18,PTE17,PTE16,PTE6,PTE3,PTE2); BusIn equipment_active_step(PTE19, PTE1, PTD7, PTA17, PTA16, PTA15); BusIn equipment_system_status(PTA13, PTD2, PTD4, PTD6, PTD7, PTD5, PTE0); DigitalIn OPEN_CLOSE(PTB2); /* I2C ioLCD(PTC1,PTC2); DigitalIn HP_Input(PTB18); */ DigitalIn BUT_Verde(PTE30); DigitalIn BUT_Maro(PTB20); DigitalIn BUT_Portocaliu(PTE23); DigitalIn BUT_Rosu(PTB2); /* DigitalOut DO_1(PTA12); DigitalOut DO_2(PTA4); */ void config(); void operating_flag(); void LECP6_read_inputs(); void axis_position(); void showIndex_Inc(int); void showMessage(int); bool LECP_alarms(); void LECP_alarms_rst(); bool LECP6_SVRE(); bool LECP6_BUSY(); bool LECP_move_axis(); bool LECP_return_to_origin(); void LECP6_disable_outputs(); void LECP_Jog(); void LECP_Build_Control(); void LECP_Run_Control(); void LECP_Run(int*); bool equipment_ready = false, equip_in_alarm = false; int sys_Status, equip_active; int move_forward = 0, move_backward = 0; float memorised_positions[10]; float control_sequences[10][10]; int number_of_mem_positions = 0; float position; float positions[] = { 0.0, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 85.0, 90.0, 95.0, 100.0, 110.0, 120.0, 130.0, 140.0, 150.0, -0.1,-0.25,-0.5,-1.0,-2.5,-5.0,-10.0,-15.0,-20.0,-25.0,-30.0,-35.0,-40.0,-45.0,-50.0,-55.0,-60.0,-65.0,-70.0,-75.0,-80.0,-85.0,-90.0,-95.0,-100.0,-110.0,-120.0,-130.0,-140.0,-150.0 }; int main() { config(); control_sequences[1][0] = 3; control_sequences[1][1] = 20.0; control_sequences[1][2] = 50.0; control_sequences[1][3] = 25.0; /* int contr[10]; contr[0] = 4; contr[1] = 5; contr[2] = 28; contr[3] = 58; contr[4] = 35; */ //LECP_return_to_origin(); //LECP_Run(contr); while(1) { /******* RETURN TO ORIGIN ********/ if(sys_Status != NO_POWER_SUPPLY) { if(!equip_in_alarm && (!equipment_ready || !Board_But_Left)) { showMessage(RETURN_TO_ORIGIN); equipment_ready = LECP_return_to_origin(); } } /********* JOGING ***********/ if(equipment_ready && !BUT_Portocaliu) { showMessage(LECP6_JOG); LECP_Jog(); } /******** CONTROL ***********/ if(equipment_ready && !BUT_Maro) { showMessage(BUILD_CTRL); LECP_Build_Control(); } /******** RUN CONTROL SEQUENCE ********/ if(equipment_ready && !BUT_Verde) { showMessage(CTRL_RUN); LECP_Run_Control(); } } } void LECP_Run(int* ctrl) { // in functia aceasta sa introduc si return to origin int move_axis_task = 0, alarm = 0; int last_step = ctrl[0], step; while(BUT_Rosu && !equip_in_alarm && equipment_ready && !alarm) { // cat timp nu este oprita secventa de control switch(move_axis_task) { case 0: // check if axis is not in fault or alarm while(equip_in_alarm) { } move_axis_task++; // next task break; case 1: DO_A13_SVON = true; // turn servo on; if(LECP6_SVRE()) { move_axis_task++; // next task } else { alarm = 1; move_axis_task = 100; } break; case 2: for( step = 1; step < last_step && !equip_in_alarm; step++) { step_number = ctrl[step]; if(step_number == 0 ) position = 0; else position = position + positions[step_number]; DO_A11_DRIVE = true; // set drive bit slcd.clear(); slcd.Home(); wait_ms(50); DO_A11_DRIVE = false; // reset drive bit slcd.printf("%.1f", position); do { wait_ms(10); } while(DI_B10_INP); do { wait_ms(10); } while(LECP6_BUSY()); } if(!equip_in_alarm) move_axis_task = 0; // next task else { alarm = 2; move_axis_task = 100; } break; default: break; } } DO_A13_SVON = false; // turn servo off; } /*** BUILD CONTROL SEQUENCES BASES ON MEMORIZED POSITIONS ***/ void LECP_Build_Control() { bool control_seq_finished = false, position_memorized = false, delay_selected = false; int selected_memorized_position = 0, ctrl_sequence = 0, pos_sequence = 0, delay_value = 0; float sel_mem_pos_value = 0.0; // add a new control sequence control_sequences[0][0]++; while(!control_seq_finished && equipment_ready) { if(!BUT_Portocaliu) { // swap thrgough memorized positions position_memorized = 0; while(!position_memorized) { // show actual memorized position sel_mem_pos_value = memorised_positions[selected_memorized_position]; // clear display slcd.clear(); // go home display slcd.Home(); // disable dots slcd.DP3(false); slcd.DP2(false); // print value slcd.printf("%.1f", sel_mem_pos_value); wait(1.0); // select another position from positions list if(!Board_But_Right && selected_memorized_position < number_of_mem_positions ) { selected_memorized_position++; } if(!Board_But_Left && selected_memorized_position > 0 ) { selected_memorized_position--; } // memorize in the control sequence the selected position from available ones if(!BUT_Verde) { ctrl_sequence = control_sequences[0][0]; control_sequences[ctrl_sequence][++pos_sequence] = sel_mem_pos_value; showMessage(POSITION_RECORDED); position_memorized = true; } // cancel if(!BUT_Rosu) { position_memorized = true; } } wait(1.0); // goto } // selectare delay if(!BUT_Maro) { delay_selected = false; while(!delay_selected) { // clear display & go home slcd.clear(); slcd.Home(); // disable dots slcd.DP3(false); slcd.DP2(false); // print value slcd.printf("%d", delay_value); if(!Board_But_Right && delay_value < 5 ) { delay_value++; } if(!Board_But_Left && delay_value > 0 ) { delay_value--; } if(!BUT_Verde) { // memorize in the control sequence the selected position from available ones ctrl_sequence = control_sequences[0][0]; control_sequences[ctrl_sequence][++pos_sequence] = 999.0; // delay special identification code control_sequences[ctrl_sequence][++pos_sequence] = delay_value; showMessage(POSITION_RECORDED); delay_selected = true; } // cancel if(!BUT_Rosu) { delay_selected = true; } wait(1.0); } } // finish control sequence if(!BUT_Verde) { control_seq_finished = true; // save number of positions in the control sequence control_sequences[ctrl_sequence][0] = pos_sequence; showMessage(CTRL_CREATED); } // cancel control sequence if(!BUT_Rosu) { showMessage(ESC); control_seq_finished = true; for(int i = 0; i < 10; i++) { control_sequences[ctrl_sequence][i] = 0; } control_sequences[0][0]--; } } } /*** Run control sequence ***/ void LECP_Run_Control() { // decompozitie pozitii in pozitiile momorate in controler si in delay-uri; int operations[10] = {0}, index, i, j; float decompose; if(position != 0.0) { LECP_return_to_origin(); } while(BUT_Rosu) { // cat timp nu este oprita secventa de control // decompozitie doar o singura data va trebui rulata index = 1; for( i = 1; i <= control_sequences[1][0]; i++) { //decompose = control_sequences[1][i]-position; if(i>1) { decompose = control_sequences[1][i]-control_sequences[1][i-1]; } else decompose = control_sequences[1][i]-position; if(decompose > 0 && decompose != 999.0 ) { while(decompose) { for( j = 1; positions[j] < decompose && j <= 30; j++) { } if(decompose > 0) decompose -= positions[j]; operations[index++] = j; } } if(decompose < 0) { while(decompose) { for( j = 31; positions[j] > decompose && j <= 60; j++) { } if(decompose < 0) decompose = decompose + ( positions[j] * -1.0); operations[index++] = j; } } if(decompose == 999.0) { wait(control_sequences[1][i++]); } /* for(int k = 0; k < index; k++) { if(previous <= control_sequences[1][i]) { move_forward = operations[k]; // nu e prea bine dar va merge } else { move_backward = operations[k] + 30; } LECP_move_axis(); } */ } // add the absolute 0 position - pentru a nu avea offset la prima pozitie pentru dupa primul ciclu operations[index++] = 0; operations[0] = index; LECP_Run(operations); } } /*** SHOW INDEX and CORESPONDING INCREMENT WHILE JOGING***/ void showIndex_Inc(int index) { slcd.DP3(false); slcd.DP2(false); slcd.DP1(false); slcd.clear(); slcd.Home(); slcd.printf(" %d",index); // print actual position index wait(0.5); slcd.clear(); slcd.Home(); slcd.printf("%.1f", positions[index]); // print position increment coresponding to the actual position index wait(0.5); } /*** Display Axis Calculated Poistion ***/ void axis_position() { slcd.clear(); slcd.Home(); if(position < 10) { slcd.CharPosition = 2; } if(position < 100 && position > 10) { slcd.CharPosition = 1; } if(position >= 100) { slcd.CharPosition = 0; } slcd.DP3(false); slcd.DP2(false); slcd.printf("%.1f", position); wait(0.5); if(position > 155.0 || position < 0.0 ) { slcd.printf("A.L.M. .", position); wait(1.0); } } /*** MOVE COMMAND ***/ bool LECP_move_axis() { int move_axis_task = 0, alarm = 0; bool move_axis_done = 0; // load step data if(move_forward) step_number = move_forward; else step_number = move_backward; move_forward = move_backward = 0; showMessage(LECP6_SCAN_INPUTS); do { switch(move_axis_task) { case 0: // if not in fault or alarm DO_A13_SVON = true; // turn servo on; move_axis_task++; // next task wait(0.25); break; case 1: // check if SVRE bit is on if(LECP6_SVRE()) { DO_A11_DRIVE = true; // set drive bit showMessage(LECP6_MOVES); DO_A11_DRIVE = false; // reset drive bit move_axis_task++; // next task } else { alarm = 1; move_axis_task = 100; } break; case 2: if(!LECP6_BUSY()) { // check to see if LECP6 is busy for move_axis_task++; // next task } else { alarm = 2; move_axis_task = 100; } break; case 3: do { wait(0.25); } while(DI_B10_INP); DO_A13_SVON = false; showMessage(LECP6_DONE); move_axis_done = true; move_axis_task++; break; default: break; } } while(!move_axis_done || alarm); if(alarm) { LECP6_disable_outputs(); return 0; } position += positions[step_number]; // calculate new position axis_position(); return 1; } /*** Configure Smart Axis ***/ void config() { LECP6_disable_outputs(); // configure RED LED to toglle every 1.0 second operating_led.attach(&operating_flag,1.0); equipment_status.attach(&LECP6_read_inputs, 0.25); wait(2.0); } /*** read inputs from LCPE ***/ void LECP6_read_inputs() { sys_Status = equipment_system_status; equip_active = equipment_active_step; // check if there is power to CTRL unit of SMC axis if(sys_Status == NO_POWER_SUPPLY) { showMessage(NO_POWER_SUPPLY); equipment_ready = 0; } // check for alarms if(equip_in_alarm && !Board_But_Left && !Board_But_Right) { // if alarms and both FRDM-kl46z are pressed reset alarms showMessage(LECP6_RST); LECP_alarms_rst(); equip_in_alarm = LECP_alarms(); } else { // show alarm message and raise flag if(sys_Status != NO_POWER_SUPPLY && (sys_Status & LECP6_IN_ALARM)) { showMessage(LECP6_IN_ALARM); equip_in_alarm = true; } } } /********************************************testate****************************************************/ /*** Disable outputs from uC to LCPE ***/ void LECP6_disable_outputs() { DO_A9_SETUP = DO_A10_HOLD = DO_A11_DRIVE = DO_A12_RESET = DO_A13_SVON = false; step_number = 0; } /*** 1 second operating led ***/ void operating_flag() { LED = !LED; } void showMessage(int message) { slcd.clear(); slcd.Home(); if(message == POSITION_OVERFLOW) { slcd.printf("oF "); } if(message == POSITION_UNDERFLOW) { slcd.printf("uF "); } if(message == POSITION_RECORDED) { slcd.printf("R.E.C. "); } if(message == ESC) { slcd.printf("e.s.c. "); } if(message == RETURN_TO_ORIGIN) { slcd.printf("o.r.i.g."); } if(message == NO_POWER_SUPPLY) { slcd.printf("n.o.P.S"); } if(message == LECP6_SCAN_INPUTS) { slcd.printf("s.c.a.n"); } if(message == LECP6_MOVES) { slcd.printf("m.o.v.e"); } if(message == LECP6_DONE) { slcd.printf("d.o.n.e"); } if(message == LECP6_SETUP) { slcd.printf("s.e.t. "); } if(message == LECP6_JOG) { slcd.printf("j.o.g. "); } if(message == BUILD_CTRL) { slcd.printf("C.t.r.N"); } if(message == CTRL_CREATED) { slcd.printf("C.t.r.S"); } if(message == CTRL_RUN) { slcd.printf("r.u.n. "); } if(message == LECP6_IN_ALARM) { slcd.printf("A.L.r. "); } if(message == LECP6_RST) { slcd.printf("R.S.T. "); } wait(1.0); } /*** RETURN TO ORIGIN COMMAND ***/ bool LECP_return_to_origin() { int task = 0, alarm = 0; bool ret_to_orig_done = false; do { switch(task) { case 0: while(equip_in_alarm) { } task++; break; case 1: // turn servo on DO_A13_SVON = true; if(LECP6_SVRE()) task++; else { alarm = 2; task = 99; } break; case 2: DO_A9_SETUP = true; // set drive bit showMessage(LECP6_SETUP); while(DI_B9_SETON) { wait(0.1); } while(LECP6_BUSY()) { } DO_A9_SETUP = false; // reset drive bit task++; break; case 3: DO_A13_SVON = false; showMessage(LECP6_DONE); ret_to_orig_done = true; position = 0.0; task++; break; default: break; } } while(!ret_to_orig_done && !alarm); if(alarm) { LECP6_disable_outputs(); return 0; // issues were identified while return to origin procedure } axis_position(); return 1; // succesfully returned to origin } /*** FREE JOG WITH AXIS & POSITION RECORD***/ void LECP_Jog() { bool jog_finished = false; int position_index = 1; while(!jog_finished && equipment_ready && !equip_in_alarm) { showIndex_Inc(position_index); axis_position(); if(!Board_But_Right) { // move forward if actual position + position coresponding to the actual increment does result in a axis position overflow if((position + positions[position_index]) <= 150) { move_forward = position_index; } else { showMessage(POSITION_OVERFLOW); } } if(!Board_But_Left) { // move backward if actual position - position coresponding to the actual increment does result in a axis position underflow if((position + positions[position_index+30]) >= 0) { move_backward = position_index + 30; } else { showMessage(POSITION_OVERFLOW); } } if(!BUT_Portocaliu && position_index < 31) { position_index++; // increase actual increment } if(!BUT_Maro && position_index > 0) { position_index--; // decrease actual increment } if(!BUT_Verde) { // record axis position number_of_mem_positions++; memorised_positions[number_of_mem_positions] = position; showMessage(POSITION_RECORDED); } if(!BUT_Rosu) { // end free axis jog showMessage(ESC); jog_finished = true; } if(move_forward || move_backward) { // move axis forward or backward accordingly to the coresponding actual index position LECP_move_axis(); } } } /*** CHECK FOR LCEP ALARMS ***/ bool LECP_alarms() { // check for alarms if(DI_B12_ESTOP || DI_B13_ALARM) return 1; else return 0; } /*** RESET LCEP ALARMS ***/ void LECP_alarms_rst() { DO_A12_RESET = true; wait(0.5); DO_A12_RESET = false; } /*** CHECK IF SVRE BIT BECAME ACTIVE AFTER SERVO ON CMD ***/ bool LECP6_SVRE() { // check if SVRE bit is on as an action to Servo ON int timeout = 0; do { //wait(0.1); wait_ms(50); timeout++; if(timeout >= 10) return 0; } while(DI_B11_SVRE); return 1; } /*** CHECK IF LCPE IS BUSY PERFORMING AN OPERATION ***/ bool LECP6_BUSY() { int timeout = 0; do { wait(0.1); timeout++; if(timeout >= 10) return 1; } while(!DI_B7_BUSY); return 0; }