TheRobotStudio ROSA
/
trs_slave
Code for the mbed NXP LPC1768 To be used on The Robot Studio Slave Boards License : Simplified BSD
main.cpp
- Committer:
- therobotstudio
- Date:
- 2015-02-11
- Revision:
- 6:8a0250a4877a
- Parent:
- 5:52e3137c2831
File content as of revision 6:8a0250a4877a:
/* * Copyright (c) 2013, The Robot Studio * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Created on: Feb 27, 2013 * Author: Cyril Jourdan (cyril.jourdan@therobotstudio.com) */ #define COMPILE_MAIN_CODE_TRS_SLAVE #ifdef COMPILE_MAIN_CODE_TRS_SLAVE /*** Includes ***/ #include "include/eposCmd.h" /*** Defines ***/ #define OPEN_ARROW 0x3C //< = 60 #define CLOSE_ARROW 0x3E //< = 62 #define NUMBER_OF_ARROWS 5 //SPI RxTx FIFO bits #define TNF 0x02 #define TFE 0x01 #define RNE 0x04 #define CALIB_DELAY 1500 #define NUMBER_OF_CALIB 1 /*** Variables ***/ SPISlave device(p5, p6, p7, p8); // mosi, miso, sclk, ssel DigitalIn sync_master(p11); //previously p25 DigitalIn calibDonePin(p23); DigitalOut logicPin(p26); //to record with Logic analyser on an event, pin high. uint8_t numberEpos2Boards = 1; char dataChecksum = 0x00; char cmdChecksum = 0x00; uint8_t writeBufferSPI[NUMBER_MAX_EPOS2_PER_SLAVE][NUMBER_BYTES_PER_MSG]; uint8_t readBufferSPI[NUMBER_MAX_EPOS2_PER_SLAVE][NUMBER_BYTES_PER_MSG]; int32_t tempCalibEnc[NUMBER_OF_CALIB][NUMBER_MAX_EPOS2_PER_SLAVE]; int32_t meanCalibEnc[NUMBER_MAX_EPOS2_PER_SLAVE]; int32_t distanceFromMean[NUMBER_OF_CALIB][NUMBER_MAX_EPOS2_PER_SLAVE]; int32_t minDistFromMean[NUMBER_MAX_EPOS2_PER_SLAVE]; int32_t maxDistFromMean[NUMBER_MAX_EPOS2_PER_SLAVE]; int32_t calibOffset[NUMBER_MAX_EPOS2_PER_SLAVE]; int counter = 0; int16_t forceVal[NB_SAMPLES_MEDIAN]; int16_t sortForceVal[NB_SAMPLES_MEDIAN]; //int16_t lastForceVal[NUMBER_EPOS2_BOARDS][NB_SAMPLES_MEDIAN]; /*** Functions ***/ bool verifyChecksum() //check the data comming from the master over SPI { for(int i=0; i<NUMBER_MAX_EPOS2_PER_SLAVE; i++) { for(int j=0; j<NUMBER_BYTES_PER_MSG; j++) { cmdChecksum += readBufferSPI[i][j]; } } cmdChecksum++; //add 1 to obtain 0x00 //pc.printf("sum 0x%02X\n\r", cmdChecksum); if(cmdChecksum == 0x00) return true; else return false; } void calculateSPIChecksum() //compute checksum for the data sent to the master over SPI { int sum = 0; for(int i=0; i<NUMBER_MAX_EPOS2_PER_SLAVE; i++) { for(int j=0; j<NUMBER_BYTES_PER_MSG; j++) { sum += writeBufferSPI[i][j]; } } dataChecksum = (char)(~sum); //reverse 0 and 1, and cast as byte } int16_t getMedianForceVal(const int8_t nodeID) { //logicPin = 1; for(int m=0; m<NB_SAMPLES_MEDIAN; m++) { sortForceVal[m] = getForce(nodeID); wait_us(100); //adjust this } //sort values for(int m=1; m<NB_SAMPLES_MEDIAN; ++m) { int16_t n = sortForceVal[m]; int p; for(p = m-1; (p >=0) && (n<sortForceVal[p]); p--) { sortForceVal[p+1] = sortForceVal[p]; } sortForceVal[p+1] = n; } //logicPin = 0; return sortForceVal[2]; } /*** INTERRUPT (for catching Emergency error frames) ***/ void interrupt() { CANMessage canmsg; int64_t data = 0x0000000000000000; int8_t nodeID = 0; int16_t cobID = 0; //read the can message that has triggered the interrupt cantoepos.read(canmsg); //pc.printf("Interrupt frame : [%02X] [%02X %02X %02X %02X %02X %02X %02X %02X]\n", canmsg.id, canmsg.data[7], canmsg.data[6], canmsg.data[5], canmsg.data[4], canmsg.data[3], canmsg.data[2], canmsg.data[1], canmsg.data[0]); nodeID = 0x00F & canmsg.id; cobID = 0x0FF0 & canmsg.id; for(int i=0; i<=canmsg.len; i++) { data = data | (canmsg.data[i]<<i*8); } //check nodeID first if((nodeID >= 1) && (nodeID <= numberEpos2Boards)) //was nodeID >= 0 before ??? { switch(cobID) { case COB_ID_TRANSMIT_PDO_1_ENABLE : //getPosition //pc.printf("getPosition Node ID : [%d], PDO COB-ID [%02X], data = %d\n", nodeID, cobID, data); encPosition[nodeID - 1] = data; break; case COB_ID_TRANSMIT_PDO_2_ENABLE : //getCurrent averaged //pc.printf("getCurrent Node ID : [%d], PDO COB-ID [%02X], data = %d\n", nodeID, cobID, data); avgCurrent[nodeID - 1] = data; break; case COB_ID_TRANSMIT_PDO_3_ENABLE : //getVelocity //pc.printf("getVelocity Node ID : [%d], PDO COB-ID [%02X], data = %d\n", nodeID, cobID, data); velocity[nodeID - 1] = data; break; case COB_ID_TRANSMIT_PDO_4_ENABLE : //getPotiPosition //pc.printf("getPotiPosition Node ID : [%d], PDO COB-ID [%02X], data = %d\n", nodeID, cobID, data); potiPosArray[nodeID - 1] = data; break; case COB_ID_EMCY_DEFAULT : //Emergency frame //pc.printf("Emergency frame, Node ID : [%d], PDO COB-ID [%02X], data = %02X\n", nodeID, cobID, data); //pc.printf("EF [%02X][%02X %02X %02X %02X %02X %02X %02X %02X]\n", canmsg.id, canmsg.data[7], canmsg.data[6], canmsg.data[5], canmsg.data[4], canmsg.data[3], canmsg.data[2], canmsg.data[1], canmsg.data[0]); pc.printf("EF%02X-%02X%02X\n\r", canmsg.id, canmsg.data[1], canmsg.data[0]); ledchain[1] = 1; //nh.logerror("Emergency frame"); boardStatus[nodeID-1] = 1; //first step : fault reset on controlword //pc.printf("Node %d - STEP 1 - faultResetControlword\n", nodeID); //Debug for fault detection on brachii //faultResetControlword(nodeID); break; case COB_ID_SDO_SERVER_TO_CLIENT_DEFAULT : //SDO Acknoledgement frame int32_t regData = 0x00000000; regData = (int32_t)data; //pc.printf("Node %d - regData [%02X]\n", nodeID, regData); if(regData == 0x00604060) //Controlword { if(boardStatus[nodeID-1] == 1) { boardStatus[nodeID-1] = 2; //second step : shutdown controlword //pc.printf("Node %d - STEP 2 - shutdownControlwordIT\n", nodeID); shutdownControlwordIT(nodeID); } else if(boardStatus[nodeID-1] == 2) { boardStatus[nodeID-1] = 3; //third step : Switch On & Enable Operation on Controlword //pc.printf("Node %d - STEP 3 - switchOnEnableOperationControlwordIT\n", nodeID); switchOnEnableOperationControlwordIT(nodeID); } else if(boardStatus[nodeID-1] == 3) { boardStatus[nodeID-1] = 4; //ask for statusword to check if the board has reset well //pc.printf("Node %d - STEP 4 - getStatusword\n", nodeID); getStatusword(nodeID); } } else if(regData == 0x0060414B) //read Statusword { //int32_t swData = 0x00000000; //pc.printf("Node %d - Statusword [%02X]\n", nodeID, canmsg.data[4]); //pc.printf("Statusword frame : [%02X] [%02X %02X %02X %02X %02X %02X %02X %02X]\n", canmsg.id, canmsg.data[7], canmsg.data[6], canmsg.data[5], canmsg.data[4], canmsg.data[3], canmsg.data[2], canmsg.data[1], canmsg.data[0]); if(boardStatus[nodeID-1] == 4) { //swData = data >> 32; int8_t fault = 0x00; fault = (canmsg.data[4] & 0x08) >> 3; if(fault == 0) //reset OK { boardStatus[nodeID-1] = 0; //Board is reset and enable OK pc.printf("%d OK\n\r", nodeID); ledchain[1] = 0; } else //try to reset again { //pc.printf("Node %d - try to reset again\n", nodeID); boardStatus[nodeID-1] = 1; //go back to first step : fault reset on controlword //pc.printf("Node %d - STEP 1 - faultResetControlword\n", nodeID); faultResetControlword(nodeID); } } } break; default : pc.printf("Unknown frame [%02X][%02X %02X %02X %02X %02X %02X %02X %02X]\n\r", canmsg.id, canmsg.data[7], canmsg.data[6], canmsg.data[5], canmsg.data[4], canmsg.data[3], canmsg.data[2], canmsg.data[1], canmsg.data[0]); } //end switch } else { pc.printf("NODEID ERROR\n\r"); } } //end interrupt void commandPlayer() //called in main every 20ms { //at least one cmd played bool cmdPlayLED = false; for(int i= 0; i<NUMBER_MAX_EPOS2_PER_SLAVE; i++) { uint8_t node_ID = readBufferSPI[i][0]; uint8_t node_mode = readBufferSPI[i][1]; int32_t value = readBufferSPI[i][2] + (readBufferSPI[i][3]<<8) + (readBufferSPI[i][4]<<16) + (readBufferSPI[i][5]<<24); if((node_ID >= 1) && (node_ID <= numberEpos2Boards)) { if(node_mode != 0xFF) { switch (node_mode) { //WARNING : changing mode requires 1 cycle, so "else" case has been added, commands needs to be sent at least twice to be applied when the mode change. case POSITION: //first change modes of motors that will be triggered later if(activMode[node_ID-1] != POSITION) setModeOfOperationPDO(node_ID, VALUE_POSITION_MODE); else setPosition(node_ID, value + calibOffset[node_ID-1]); break; case CURRENT: //first change modes of motors that will be triggered later (like CURRENT mode needs some time to be active) //pc.printf("setCurrent(%d, %d)\n", motorCmdBuffer[i].nodeID, motorCmdBuffer[i].value); if(activMode[node_ID-1] != CURRENT) setModeOfOperationPDO(node_ID, VALUE_CURRENT_MODE); else setCurrent(node_ID, value); break; case VELOCITY: //first change modes of motors that will be triggered later if(activMode[node_ID-1] != VELOCITY) setModeOfOperationPDO(node_ID, VALUE_VELOCITY_MODE); else setVelocity(node_ID, value); break; default: break; } ledchain[3] = 1; //switch on when cmd is applied cmdPlayLED = true; } else //idle mode 0xFF { if(!cmdPlayLED) ledchain[3] = 0; //switch off when slave is idle, i.e. all cmd in a set are 0xFF } } wait_us(10); } } void updateTxSPIBuffer() { for(int i=1; i<=numberEpos2Boards; i++) { //uint8_t node_id = i; getPosition(i); wait_us(200); getCurrent(i); wait_us(200); //getForce(i); wait_us(200); } //build the motorDataSet_msg for(int i=0; i<numberEpos2Boards; i++) { uint8_t node_id = i+1; int32_t position = encPosition[i] - calibOffset[i]; int16_t force = getForce(11); //get hand force //position writeBufferSPI[i][0] = position; writeBufferSPI[i][1] = position>>8; writeBufferSPI[i][2] = position>>16; writeBufferSPI[i][3] = position>>24; /* //position writeBufferSPI[i][0] = encPosition[node_id-1]; writeBufferSPI[i][1] = encPosition[node_id-1]>>8; writeBufferSPI[i][2] = encPosition[node_id-1]>>16; writeBufferSPI[i][3] = encPosition[node_id-1]>>24; */ //current writeBufferSPI[i][4] = avgCurrent[node_id-1]; writeBufferSPI[i][5] = avgCurrent[node_id-1]>>8; //force //force writeBufferSPI[i][6] = force; writeBufferSPI[i][7] = force>>8; //writeBufferSPI[i][6] = 0; //writeBufferSPI[i][7] = 0; //pc.printf("%d\n", force); //pc.printf("[%d] pos=%d cur=%d\n", node_id, encPosition[node_id-1], avgCurrent[node_id-1]); //force = getMedianForceVal(node_id); //medForce[node_id-1]; } } void initBufferSPI() { //init the SPI arrays for(int i=0; i<NUMBER_MAX_EPOS2_PER_SLAVE; i++) { for(int j=0; j<NUMBER_BYTES_PER_MSG; j++) { writeBufferSPI[i][j] = 0x00; readBufferSPI[i][j] = 0x00; } } /* for(int n=0; n<NUMBER_MAX_EPOS2_PER_SLAVE; n++) { //position writeBufferSPI[n][0] = 0xA0+n; writeBufferSPI[n][1] = 0xB0+n; writeBufferSPI[n][2] = 0x00; writeBufferSPI[n][3] = 0x00; //current writeBufferSPI[n][4] = 0xC0+n; writeBufferSPI[n][5] = 0x00; //force writeBufferSPI[n][6] = 0xD0+n; writeBufferSPI[n][7] = 0x00; }*/ } void calibrate() { pc.printf("- Start Calibration\n\r"); //set all boards to current mode for(int i=1; i<=numberEpos2Boards; i++) { setModeOfOperationPDO(i, VALUE_CURRENT_MODE); } ledchain[2] = 1; wait_ms(20); for(int j=1; j<=numberEpos2Boards; j++) { //pc.printf("- Calibration number %d\n\r", j); //trigger current in certain order setCurrent(j, 100); wait_ms(20); } ledchain[3] = 1; /* pc.printf("- Offsets will be recorded in 5 sec..."); wait_ms(1000); pc.printf("4..."); ledchain[0] = 1; wait_ms(1000); ledchain[0] = 0; ledchain[1] = 1; pc.printf("3..."); wait_ms(1000); ledchain[1] = 0; ledchain[2] = 1; pc.printf("2..."); wait_ms(1000); ledchain[2] = 0; ledchain[3] = 1; pc.printf("1..."); wait_ms(1000); ledchain[3] = 0; pc.printf("0..."); */ /* //save current encoder position as calib offset for(int i=0; i<numberEpos2Boards; i++) { int nodeid = i+1; getPosition(nodeid); wait_us(500); calibOffset[i] = encPosition[i]; //pc.printf("%d\n\r", calibOffset[i]); } pc.printf("OK\n\r"); *//* pc.printf("current to zero\n\r"); for(int i=0; i<numberEpos2Boards; i++) { int nodeid = i+1; setCurrent(nodeid, 0); wait_us(500); }*/ //For case where motor start from zero for(int i=0; i<numberEpos2Boards; i++) { calibOffset[i] = 0; } } /*** Main ***/ int main() { pc.baud(115200); pc.printf("*** Start Slave Main - DCX Left Arm ***\n\r"); logicPin = 0; uint8_t my_val = 0x00; //to read and empty the SPI FIFO buffer initBufferSPI(); //sync_master = 0; char rByte = 0x00; char threeArrows = 0; bool threeArrowsFound = false; bool slaveSelected = false; bool checksumReceived = false; bool cmdValid = false; int i = 0; //msg int j = 0; //byte number pc.printf("--- Initialise EPOS2 boards ---\n\r"); ledchain[0] = 1; while(initEposBoard(numberEpos2Boards) == EPOS2_OK) { numberEpos2Boards++; } numberEpos2Boards--; //because it has been increment one time too much at the end of the while loop ledchain[1] = 1; pc.printf("--- Enable Interrupts ---\n\r"); //attach the interrupt function cantoepos.attach(&interrupt); __enable_irq(); pc.printf("--- Calibrate Arm ---\n\r"); calibrate(); device.reply(0x62); //Prime SPI with first reply //gather first pack of data //get the sensor values updateTxSPIBuffer(); //update checksum calculateSPIChecksum(); //then start the main loop pc.printf("--- Start main loop ---\n\r"); ledchain[0] = 0; ledchain[1] = 0; ledchain[2] = 0; ledchain[3] = 0; while(1) { ledchain[0] = 0; //not selected by master ledchain[3] = 0; //no commands played //wait, the master will put the pin high at some point, for 10us while(sync_master == 0) { // logicPin = 1; wait_us(1); // logicPin = 0; } slaveSelected = true; ledchain[0] = 1; while(LPC_SSP1->SR & RNE) // While RNE-Bit = 1 (FIFO receive buffer not empty)... my_val = LPC_SSP1->DR; // Read the byte in the buffer /* { my_val = LPC_SSP1->DR; // Read the byte in the buffer logicPin = 1; wait_us(1); logicPin = 0; } */ //reset for a new message i = 0; j = 0; threeArrows = 0; threeArrowsFound = false; checksumReceived = false; logicPin = 1; __disable_irq(); while(slaveSelected) { //SPI polling if(device.receive()) { rByte = device.read(); // Read byte from master //pc.printf("0x%02X ", rByte); if(threeArrows < 3) { if(rByte == OPEN_ARROW) { threeArrows++; //pc.printf("3A++\n\r"); } else { //threeArrows = 0; //startReceiving = false; //pc.printf("error3A\n"); //slaveSelected = false; } if(threeArrows == 3) { device.reply(writeBufferSPI[i][j]); threeArrowsFound = true; } else { device.reply(0x62); //close arrow : > } } else { readBufferSPI[i][j] = rByte; j++; //write next byte next time if(j >= NUMBER_BYTES_PER_MSG) { j = 0; i++; //next node if(i >= NUMBER_MAX_EPOS2_PER_SLAVE) { //finished reading the array /* for(int n=0; n<1; n++) { pc.printf("0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", readBufferSPI[n][0], readBufferSPI[n][1], readBufferSPI[n][2], readBufferSPI[n][3], readBufferSPI[n][4], readBufferSPI[n][5], readBufferSPI[n][6]); } */ //reset threeArrows = 0; i = 0; j = 0; slaveSelected = false; //to end the while loop /* logicPin = 1; wait_us(1); logicPin = 0;*/ } } if(slaveSelected) device.reply(writeBufferSPI[i][j]); else device.reply(dataChecksum); //checksum } }//if wait_us(1); }//while slaveSelected //wait_us(30); //logicPin = 1; //read the checksum while(!checksumReceived) { //pc.printf("w"); if(device.receive()) { cmdChecksum = device.read(); //pc.printf("%02X\n", cmdChecksum); cmdValid = verifyChecksum(); checksumReceived = true; //exit while loop } wait_us(1); } __enable_irq(); logicPin = 0; /* //print some data: for(int n=0; n<1; n++) { pc.printf("%02X %02X %02X %02X %02X %02X %02X %02X\n", readBufferSPI[n][0], readBufferSPI[n][1], readBufferSPI[n][2], readBufferSPI[n][3], readBufferSPI[n][4], readBufferSPI[n][5], readBufferSPI[n][6], readBufferSPI[n][7]); } */ //pc.printf("%02X\n", readBufferSPI[0][4]); wait_us(30); /* logicPin = 1; wait_us(10); logicPin = 0; wait_us(20); */ //if checksum is correct, then play the cmds if(cmdValid) { logicPin = 1; //play the commands commandPlayer(); cmdValid = false; //reset for next packet logicPin = 0; } /* wait_us(20); logicPin = 1; wait_us(10); logicPin = 0; */ //get the sensor values ready to be sent for the next loop //update the writeBufferSPI updateTxSPIBuffer(); //test with known data first //compute checksum calculateSPIChecksum(); //logicPin = 0; //ledchain[0] = 0; wait_us(10); }// main while end }// main end #endif //COMPILE_MAIN_CODE_TRS_SLAVE