Basic Mid-Level control for the rebuilt MorphGI control unit, using PWM to communicate with the low level controllers.

Dependencies:   ros_lib_kinetic

Committer:
WD40andTape
Date:
Tue Aug 07 15:31:59 2018 +0000
Revision:
10:1b6daba32452
Parent:
9:cd3607ba5643
Child:
11:7029367a1840
Moved final bits of low level communication code into the class. Tested and working. However stack overflow occurs on the ML during joystick steering.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WD40andTape 7:5b6a2cefbf3b 1 // STANDARD IMPORTS
WD40andTape 7:5b6a2cefbf3b 2 #include "math.h"
WD40andTape 7:5b6a2cefbf3b 3 // MBED IMPORTS
dofydoink 0:607bc887b6e0 4 #include "mbed.h"
WD40andTape 6:f0a18e28a322 5 #include "mbed_events.h"
WD40andTape 7:5b6a2cefbf3b 6 // CUSTOM IMPORTS
WD40andTape 7:5b6a2cefbf3b 7 #include "HLComms.h"
WD40andTape 8:d6657767a182 8 #include "LLComms.h"
dofydoink 0:607bc887b6e0 9
WD40andTape 7:5b6a2cefbf3b 10 // SIMPLE CHANNEL SELECTION
dofydoink 0:607bc887b6e0 11 #define ADC_PRESSURE 1
dofydoink 0:607bc887b6e0 12 #define ADC_POSITION 3
WD40andTape 7:5b6a2cefbf3b 13
WD40andTape 7:5b6a2cefbf3b 14 #define N_CHANNELS 8 // Number of channels to control
WD40andTape 7:5b6a2cefbf3b 15 // 1-3: front segment; 4-6: rear segment; 7-8: mid segment
dofydoink 0:607bc887b6e0 16
WD40andTape 7:5b6a2cefbf3b 17 // SPI SETTINGS
dofydoink 0:607bc887b6e0 18 #define LOW_LEVEL_SPI_FREQUENCY 10000000
WD40andTape 7:5b6a2cefbf3b 19 // PATH GENERATION SETTINGS
WD40andTape 6:f0a18e28a322 20 #define PATH_SAMPLE_TIME_S 0.005 //0.109
dofydoink 0:607bc887b6e0 21 #define MAX_LENGTH_MM 100.0
WD40andTape 3:c83291bf9fd2 22 #define MAX_ACTUATOR_LENGTH 52.2
dofydoink 0:607bc887b6e0 23 #define MAX_SPEED_MMPS 24.3457
WD40andTape 7:5b6a2cefbf3b 24 #define PATH_TOLERANCE_MM 0.2 // How close the linear path must get to the target position before considering it a success.
WD40andTape 7:5b6a2cefbf3b 25
WD40andTape 7:5b6a2cefbf3b 26 #define BAUD_RATE 9600 //115200
WD40andTape 7:5b6a2cefbf3b 27
WD40andTape 7:5b6a2cefbf3b 28 // COMMS SETTINGS
WD40andTape 7:5b6a2cefbf3b 29 const short int SERVER_PORT = 80;
dofydoink 0:607bc887b6e0 30
WD40andTape 6:f0a18e28a322 31 //const double DBL_MAX_CHAMBER_LENGTHS_MM[N_CHANNELS] = {80.0,80.0,80.0,80.0,80.0,80.0,80.0,80.0};
WD40andTape 7:5b6a2cefbf3b 32 //const double DBL_ACTUATOR_CONVERSION[N_CHANNELS] = {0.30586,0.30586,0.30586,0.30586,0.30586,0.4588,0.4588}; // Convert from chamber lengths to actuator lengths
WD40andTape 7:5b6a2cefbf3b 33 const double DBL_ACTUATOR_CONVERSION[N_CHANNELS] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0}; // Convert from chamber lengths to actuator
WD40andTape 4:303584310071 34 const double DBL_SMOOTHING_FACTOR = 0.5; // 0<x<=1, where 1 is no smoothing
WD40andTape 7:5b6a2cefbf3b 35 const double DBL_PATH_TOLERANCE = MAX_SPEED_MMPS * PATH_SAMPLE_TIME_S * 1.05; // Path tolerance in mm with 5% tolerance
dofydoink 0:607bc887b6e0 36
WD40andTape 7:5b6a2cefbf3b 37 // PATH VARIABLES
WD40andTape 7:5b6a2cefbf3b 38 double dblVelocity_mmps[N_CHANNELS] = { 0.0 }; // The linear path velocity (not sent to actuator)
WD40andTape 7:5b6a2cefbf3b 39 double dblLinearPathCurrentPos_mm[N_CHANNELS]={ 0.0 }; // The current position of the linear path (not sent to actuator)
WD40andTape 7:5b6a2cefbf3b 40 double dblTargetActPos_mm[N_CHANNELS] = { 0.0 }; // The final target position for the actuator
dofydoink 0:607bc887b6e0 41
WD40andTape 7:5b6a2cefbf3b 42 Serial pc(USBTX, USBRX); // tx, rx for usb debugging
WD40andTape 8:d6657767a182 43 LLComms llcomms(LOW_LEVEL_SPI_FREQUENCY);//(N_CHANNELS);
WD40andTape 3:c83291bf9fd2 44
WD40andTape 10:1b6daba32452 45 Thread threadLowLevelSPI(osPriorityRealtime);
WD40andTape 4:303584310071 46 Thread threadReceiveAndReplan(osPriorityBelowNormal);
WD40andTape 4:303584310071 47 Thread threadSmoothPathPlan(osPriorityNormal);
dofydoink 0:607bc887b6e0 48
WD40andTape 4:303584310071 49 Mutex mutPathIn;
WD40andTape 7:5b6a2cefbf3b 50 Semaphore semPathPlan(1);
dofydoink 0:607bc887b6e0 51
WD40andTape 7:5b6a2cefbf3b 52 Timer timer;
WD40andTape 7:5b6a2cefbf3b 53 Ticker PathCalculationTicker;
dofydoink 0:607bc887b6e0 54
WD40andTape 7:5b6a2cefbf3b 55 void startPathPlan() { // Plan a new linear path after receiving new target data
WD40andTape 4:303584310071 56 semPathPlan.release(); // Uses threadReceiveAndReplan which is below normal priority to ensure consistent transmission to LL
dofydoink 0:607bc887b6e0 57 }
dofydoink 0:607bc887b6e0 58
WD40andTape 7:5b6a2cefbf3b 59 // This function will be called when a new transmission is received from high level
WD40andTape 7:5b6a2cefbf3b 60 void ReceiveAndReplan() {
WD40andTape 7:5b6a2cefbf3b 61 HLComms hlcomms(SERVER_PORT);
WD40andTape 6:f0a18e28a322 62
WD40andTape 6:f0a18e28a322 63 int error_code;
WD40andTape 7:5b6a2cefbf3b 64 error_code = hlcomms.setup_server();
WD40andTape 6:f0a18e28a322 65 if( error_code == -1 ) return;
WD40andTape 7:5b6a2cefbf3b 66 error_code = hlcomms.accept_connection();
WD40andTape 7:5b6a2cefbf3b 67 if( error_code == -1 ) {
WD40andTape 7:5b6a2cefbf3b 68 hlcomms.close_server();
WD40andTape 7:5b6a2cefbf3b 69 return;
WD40andTape 7:5b6a2cefbf3b 70 }
WD40andTape 6:f0a18e28a322 71
WD40andTape 7:5b6a2cefbf3b 72 int ii;
WD40andTape 7:5b6a2cefbf3b 73 struct msg_format input; //hlcomms.msg_format
WD40andTape 4:303584310071 74
WD40andTape 6:f0a18e28a322 75 while( true ) {
WD40andTape 6:f0a18e28a322 76 // RECEIVE MESSAGE
WD40andTape 9:cd3607ba5643 77 error_code = hlcomms.receive_message();
WD40andTape 6:f0a18e28a322 78 if( error_code == NSAPI_ERROR_NO_CONNECTION ) { // -3004
WD40andTape 6:f0a18e28a322 79 printf("Client disconnected.\n\r");
WD40andTape 7:5b6a2cefbf3b 80 hlcomms.close_server();
WD40andTape 6:f0a18e28a322 81 return;
WD40andTape 6:f0a18e28a322 82 } else if( error_code < 0 ) {
WD40andTape 6:f0a18e28a322 83 printf("Error %i. Could not send data over the TCP socket. "
WD40andTape 6:f0a18e28a322 84 "Perhaps the server socket is not connected to a remote host? "
WD40andTape 6:f0a18e28a322 85 "Or the socket is set to non-blocking or timed out?\n\r", error_code);
WD40andTape 7:5b6a2cefbf3b 86 hlcomms.close_server();
WD40andTape 6:f0a18e28a322 87 return;
WD40andTape 6:f0a18e28a322 88 }
WD40andTape 6:f0a18e28a322 89 //printf("Message received.\r\n");
WD40andTape 9:cd3607ba5643 90 input = hlcomms.process_message();
WD40andTape 1:2a43cf183a62 91
WD40andTape 7:5b6a2cefbf3b 92 // PROCESS INPUT
WD40andTape 7:5b6a2cefbf3b 93 double dblTargetChambLen_mm[N_CHANNELS]; // The currenly assigned final target position (actuator will reach this at end of path)
WD40andTape 6:f0a18e28a322 94 printf("REPLAN, %f\r\n",input.duration);
WD40andTape 7:5b6a2cefbf3b 95 // Update front segment
WD40andTape 6:f0a18e28a322 96 dblTargetChambLen_mm[0] = input.psi[0][0]*1000;
WD40andTape 6:f0a18e28a322 97 dblTargetChambLen_mm[1] = input.psi[0][1]*1000;
WD40andTape 6:f0a18e28a322 98 dblTargetChambLen_mm[2] = input.psi[0][2]*1000;
WD40andTape 7:5b6a2cefbf3b 99 // Update mid segment
WD40andTape 6:f0a18e28a322 100 dblTargetChambLen_mm[6] = input.psi[1][0]*1000;
WD40andTape 7:5b6a2cefbf3b 101 dblTargetChambLen_mm[7] = dblTargetChambLen_mm[6]; // Same because two pumps are used
WD40andTape 7:5b6a2cefbf3b 102 // Update rear segment
WD40andTape 6:f0a18e28a322 103 dblTargetChambLen_mm[3] = input.psi[2][0]*1000;
WD40andTape 6:f0a18e28a322 104 dblTargetChambLen_mm[4] = input.psi[2][1]*1000;
WD40andTape 6:f0a18e28a322 105 dblTargetChambLen_mm[5] = input.psi[2][2]*1000;
dofydoink 0:607bc887b6e0 106
WD40andTape 6:f0a18e28a322 107 bool isTimeChanged = 0;
WD40andTape 6:f0a18e28a322 108 double dblMaxRecalculatedTime = input.duration;
WD40andTape 7:5b6a2cefbf3b 109 mutPathIn.lock(); // Lock variables to avoid race condition
WD40andTape 4:303584310071 110 for (ii = 0; ii< N_CHANNELS; ii++) {
dofydoink 0:607bc887b6e0 111 //check to see if positions are achievable
WD40andTape 6:f0a18e28a322 112 /*if(dblTargetChambLen_mm[ii]>DBL_MAX_CHAMBER_LENGTHS_MM[ii]) {
WD40andTape 4:303584310071 113 dblTargetChambLen_mm[ii] = DBL_MAX_CHAMBER_LENGTHS_MM[ii];
WD40andTape 6:f0a18e28a322 114 isTimeChanged = 1;
dofydoink 0:607bc887b6e0 115 }
WD40andTape 4:303584310071 116 if(dblTargetChambLen_mm[ii]<0.0) {
WD40andTape 6:f0a18e28a322 117 dblTargetChambLen_mm[ii] = 0.0;
WD40andTape 6:f0a18e28a322 118 isTimeChanged = 1;
WD40andTape 6:f0a18e28a322 119 }*/
WD40andTape 6:f0a18e28a322 120 dblTargetActPos_mm[ii] = dblTargetChambLen_mm[ii]*DBL_ACTUATOR_CONVERSION[ii];
WD40andTape 6:f0a18e28a322 121 //!! LIMIT CHAMBER LENGTHS TOO
WD40andTape 6:f0a18e28a322 122 if( dblTargetActPos_mm[ii]<0.0 || dblTargetActPos_mm[ii]>25.0 ) {
WD40andTape 6:f0a18e28a322 123 dblTargetActPos_mm[ii] = min( max( 0.0 , dblTargetActPos_mm[ii] ) , 25.0 );
WD40andTape 6:f0a18e28a322 124 isTimeChanged = 1;
WD40andTape 6:f0a18e28a322 125 }
WD40andTape 6:f0a18e28a322 126 }
WD40andTape 6:f0a18e28a322 127 double dblActPosChange;
WD40andTape 6:f0a18e28a322 128 short sgn;
WD40andTape 7:5b6a2cefbf3b 129 for (ii = 0; ii< N_CHANNELS; ii++) { // Work out new velocities
WD40andTape 6:f0a18e28a322 130 dblActPosChange = dblTargetActPos_mm[ii] - dblLinearPathCurrentPos_mm[ii];
WD40andTape 6:f0a18e28a322 131 if( fabs(dblActPosChange) < DBL_PATH_TOLERANCE ) {
WD40andTape 6:f0a18e28a322 132 dblActPosChange = 0.0;
WD40andTape 6:f0a18e28a322 133 isTimeChanged = 1;
dofydoink 0:607bc887b6e0 134 }
WD40andTape 6:f0a18e28a322 135 if( input.duration < 0.000000001 ) {
WD40andTape 6:f0a18e28a322 136 sgn = (dblActPosChange > 0) ? 1 : ((dblActPosChange < 0) ? -1 : 0);
WD40andTape 6:f0a18e28a322 137 dblVelocity_mmps[ii] = sgn * MAX_SPEED_MMPS;
WD40andTape 6:f0a18e28a322 138 isTimeChanged = 1;
WD40andTape 6:f0a18e28a322 139 } else {
WD40andTape 6:f0a18e28a322 140 dblVelocity_mmps[ii] = dblActPosChange / input.duration;
WD40andTape 6:f0a18e28a322 141 }
WD40andTape 7:5b6a2cefbf3b 142 // Check to see if velocities are achievable
WD40andTape 6:f0a18e28a322 143 if(abs(dblVelocity_mmps[ii]) > MAX_SPEED_MMPS) {
WD40andTape 6:f0a18e28a322 144 if(dblVelocity_mmps[ii]>0) {
WD40andTape 6:f0a18e28a322 145 dblVelocity_mmps[ii] = MAX_SPEED_MMPS;
WD40andTape 6:f0a18e28a322 146 } else {
WD40andTape 6:f0a18e28a322 147 dblVelocity_mmps[ii] = -1*MAX_SPEED_MMPS;
WD40andTape 6:f0a18e28a322 148 }
WD40andTape 6:f0a18e28a322 149 isTimeChanged = 1;
WD40andTape 6:f0a18e28a322 150 }
WD40andTape 6:f0a18e28a322 151 double dblRecalculatedTime;
WD40andTape 6:f0a18e28a322 152 if( fabs(dblVelocity_mmps[ii]) < 0.000000001 ) {
WD40andTape 6:f0a18e28a322 153 dblRecalculatedTime = 0;
WD40andTape 6:f0a18e28a322 154 } else {
WD40andTape 6:f0a18e28a322 155 dblRecalculatedTime = (dblTargetActPos_mm[ii] - dblLinearPathCurrentPos_mm[ii]) / dblVelocity_mmps[ii];
WD40andTape 6:f0a18e28a322 156 }
WD40andTape 6:f0a18e28a322 157 if( dblRecalculatedTime > dblMaxRecalculatedTime ) {
WD40andTape 6:f0a18e28a322 158 dblMaxRecalculatedTime = dblRecalculatedTime;
WD40andTape 6:f0a18e28a322 159 }
WD40andTape 6:f0a18e28a322 160 }
WD40andTape 6:f0a18e28a322 161 if( isTimeChanged ) {
WD40andTape 6:f0a18e28a322 162 if( dblMaxRecalculatedTime < input.duration ) {
WD40andTape 6:f0a18e28a322 163 dblMaxRecalculatedTime = input.duration;
WD40andTape 6:f0a18e28a322 164 }
WD40andTape 7:5b6a2cefbf3b 165 for (ii = 0; ii< N_CHANNELS; ii++) { // Work out new velocities
WD40andTape 6:f0a18e28a322 166 dblVelocity_mmps[ii] = (dblTargetActPos_mm[ii] - dblLinearPathCurrentPos_mm[ii]) / dblMaxRecalculatedTime;
WD40andTape 6:f0a18e28a322 167 }
WD40andTape 6:f0a18e28a322 168 }
WD40andTape 7:5b6a2cefbf3b 169 mutPathIn.unlock(); // Unlock mutex
WD40andTape 6:f0a18e28a322 170
WD40andTape 6:f0a18e28a322 171 printf("Sending message...\r\n");
WD40andTape 6:f0a18e28a322 172 // SEND MESSAGE
WD40andTape 9:cd3607ba5643 173 hlcomms.make_message(&dblMaxRecalculatedTime);
WD40andTape 9:cd3607ba5643 174 error_code = hlcomms.send_message();
WD40andTape 6:f0a18e28a322 175 if( error_code < 0 ) {
WD40andTape 6:f0a18e28a322 176 printf("Error %i. Could not send data over the TCP socket. "
WD40andTape 6:f0a18e28a322 177 "Perhaps the server socket is not bound or not set to listen for connections? "
WD40andTape 6:f0a18e28a322 178 "Or the socket is set to non-blocking or timed out?\n\r", error_code);
WD40andTape 7:5b6a2cefbf3b 179 hlcomms.close_server();
WD40andTape 6:f0a18e28a322 180 return;
WD40andTape 6:f0a18e28a322 181 }
WD40andTape 6:f0a18e28a322 182 printf("Message sent.\r\n");
WD40andTape 6:f0a18e28a322 183 }
WD40andTape 6:f0a18e28a322 184
dofydoink 0:607bc887b6e0 185 }
dofydoink 0:607bc887b6e0 186
WD40andTape 4:303584310071 187 void CalculateSmoothPath() {
dofydoink 5:712e7634c779 188 int jj;
WD40andTape 1:2a43cf183a62 189 double dblMeasuredSampleTime;
WD40andTape 7:5b6a2cefbf3b 190 double dblSmoothPathCurrentPos_mm[N_CHANNELS] = { 0.0 }; // The current position of the smooth path (not sent to actuator)
WD40andTape 7:5b6a2cefbf3b 191 //double dblPosition_mtrs[N_CHANNELS]; // The actual chamber lengths in meters given as the change in length relative to neutral (should always be >=0)
WD40andTape 7:5b6a2cefbf3b 192 //double dblPressure_bar[N_CHANNELS]; // The pressure in a given chamber in bar (1 bar = 100,000 Pa)
WD40andTape 4:303584310071 193 while(1) {
dofydoink 0:607bc887b6e0 194 semPathPlan.wait();
WD40andTape 1:2a43cf183a62 195
WD40andTape 1:2a43cf183a62 196 // If run time is more than 50 us from expected, calculate from measured time step
WD40andTape 4:303584310071 197 if (fabs(PATH_SAMPLE_TIME_S*1000000 - timer.read_us()) > 50) {
dofydoink 5:712e7634c779 198 dblMeasuredSampleTime = timer.read();
WD40andTape 4:303584310071 199 } else {
WD40andTape 1:2a43cf183a62 200 dblMeasuredSampleTime = PATH_SAMPLE_TIME_S;
WD40andTape 1:2a43cf183a62 201 }
WD40andTape 4:303584310071 202 timer.reset();
WD40andTape 1:2a43cf183a62 203
dofydoink 5:712e7634c779 204 for(jj = 0; jj < N_CHANNELS; jj++) {
WD40andTape 7:5b6a2cefbf3b 205 //dblPressure_bar[jj] = ReadADCPressure_bar(jj); // Read pressure from channel
WD40andTape 7:5b6a2cefbf3b 206 //dblPosition_mtrs[jj] = ReadADCPosition_mtrs(jj); // Read position from channel
WD40andTape 1:2a43cf183a62 207
WD40andTape 7:5b6a2cefbf3b 208 // Calculate next step in linear path
WD40andTape 7:5b6a2cefbf3b 209 mutPathIn.lock(); // Lock relevant mutex
WD40andTape 7:5b6a2cefbf3b 210 dblLinearPathCurrentPos_mm[jj] = dblLinearPathCurrentPos_mm[jj] + dblVelocity_mmps[jj]*dblMeasuredSampleTime;
WD40andTape 7:5b6a2cefbf3b 211 if(dblLinearPathCurrentPos_mm[jj] < 0.0) {
WD40andTape 7:5b6a2cefbf3b 212 dblLinearPathCurrentPos_mm[jj] = 0.00;
WD40andTape 7:5b6a2cefbf3b 213 }
WD40andTape 7:5b6a2cefbf3b 214 // Check tolerance
WD40andTape 7:5b6a2cefbf3b 215 if (fabs(dblLinearPathCurrentPos_mm[jj] - dblTargetActPos_mm[jj]) <= DBL_PATH_TOLERANCE) {
WD40andTape 7:5b6a2cefbf3b 216 dblVelocity_mmps[jj] = 0.0; // Stop linear path generation when linear path is within tolerance of target position
WD40andTape 7:5b6a2cefbf3b 217 }
WD40andTape 7:5b6a2cefbf3b 218 mutPathIn.unlock(); // Unlock relevant mutex
dofydoink 0:607bc887b6e0 219
WD40andTape 7:5b6a2cefbf3b 220 // Calculate next step in smooth path
dofydoink 5:712e7634c779 221 dblSmoothPathCurrentPos_mm[jj] = DBL_SMOOTHING_FACTOR*dblLinearPathCurrentPos_mm[jj] + (1.0-DBL_SMOOTHING_FACTOR)*dblSmoothPathCurrentPos_mm[jj];
WD40andTape 8:d6657767a182 222 llcomms.mutChannel[jj].lock(); // MUTEX LOCK
WD40andTape 10:1b6daba32452 223 llcomms.demandPosition[jj] = (int) ((dblSmoothPathCurrentPos_mm[jj]/MAX_ACTUATOR_LENGTH)*8191);// Convert to a 13-bit number
WD40andTape 10:1b6daba32452 224 llcomms.demandPosition[jj] = llcomms.demandPosition[jj] & 0x1FFF; // Ensure number is 13-bit
WD40andTape 8:d6657767a182 225 llcomms.mutChannel[jj].unlock(); // MUTEX UNLOCK
dofydoink 0:607bc887b6e0 226
WD40andTape 10:1b6daba32452 227 llcomms.isDataReady[jj] = 1; // Signal that data ready
WD40andTape 4:303584310071 228 } // end for
WD40andTape 7:5b6a2cefbf3b 229
WD40andTape 6:f0a18e28a322 230 //printf("%f, %d\r\n",dblSmoothPathCurrentPos_mm[0], intDemandPos_Tx[0]);
WD40andTape 6:f0a18e28a322 231 /*printf("%f, %f, %f, %f, %f, %f, %f, %f\r\n",dblLinearPathCurrentPos_mm[0],dblLinearPathCurrentPos_mm[1],dblLinearPathCurrentPos_mm[2],
WD40andTape 6:f0a18e28a322 232 dblLinearPathCurrentPos_mm[3],dblLinearPathCurrentPos_mm[4],dblLinearPathCurrentPos_mm[5],dblLinearPathCurrentPos_mm[6],dblLinearPathCurrentPos_mm[7]);*/
WD40andTape 6:f0a18e28a322 233 //printf("%f\r\n",dblLinearPathCurrentPos_mm[0]);
WD40andTape 7:5b6a2cefbf3b 234
WD40andTape 4:303584310071 235 } // end while
WD40andTape 3:c83291bf9fd2 236 }
dofydoink 0:607bc887b6e0 237
WD40andTape 9:cd3607ba5643 238 int main() {
WD40andTape 7:5b6a2cefbf3b 239 pc.baud(BAUD_RATE);
dofydoink 0:607bc887b6e0 240 printf("Hi, there! I'll be your mid-level controller for today.\r\n");
dofydoink 5:712e7634c779 241 wait(3);
WD40andTape 9:cd3607ba5643 242
dofydoink 0:607bc887b6e0 243 timer.start();
WD40andTape 7:5b6a2cefbf3b 244
WD40andTape 10:1b6daba32452 245 threadLowLevelSPI.start(callback(&llcomms.queue, &EventQueue::dispatch_forever)); // Start the event queue
WD40andTape 7:5b6a2cefbf3b 246 threadReceiveAndReplan.start(ReceiveAndReplan);// Start replanning thread
WD40andTape 7:5b6a2cefbf3b 247 threadSmoothPathPlan.start(CalculateSmoothPath); // Start planning thread
WD40andTape 7:5b6a2cefbf3b 248
WD40andTape 7:5b6a2cefbf3b 249 PathCalculationTicker.attach(&startPathPlan, PATH_SAMPLE_TIME_S); // Set up planning thread to recur at fixed intervals
dofydoink 0:607bc887b6e0 250
WD40andTape 7:5b6a2cefbf3b 251 Thread::wait(1);
WD40andTape 1:2a43cf183a62 252 while(1) {
WD40andTape 1:2a43cf183a62 253 Thread::wait(osWaitForever);
dofydoink 0:607bc887b6e0 254 }
WD40andTape 7:5b6a2cefbf3b 255 }