Mid level control code

Dependencies:   ros_lib_kinetic

Revision:
0:607bc887b6e0
Child:
1:2a43cf183a62
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jul 25 10:43:23 2018 +0000
@@ -0,0 +1,439 @@
+#include "mbed.h"
+#include "math.h"
+
+//#include "mbed.h"
+#include "mbed_events.h"
+
+//ADC SPI stuff
+#define PREAMBLE 0x06
+#define CHAN_1 0x30
+#define CHAN_2 0x70
+#define CHAN_3 0xB0
+#define CHAN_4 0xF0
+
+#define DATA_MASK 0x0F
+
+#define ADC_PRESSURE 1
+#define ADC_POSITION 3
+
+#define N_CHANNELS 8 //number of channels to control
+                        //1-3: front segment
+                        //4-6: rear segment
+                        //7-8: mid segment
+                
+//parameters to manually change                       
+#define LOW_LEVEL_SPI_FREQUENCY 10000000
+
+#define PATH_SAMPLE_TIME_S 0.05
+
+#define MAX_LENGTH_MM 100.0
+#define MAX_ACTUATOR_LENGTH 50.0
+#define MAX_SPEED_MMPS 24.3457
+#define PATH_TOLERANCE_MM 0.2 
+
+double dblMaxChamberLengths_mm[N_CHANNELS] = {100.0,50.0,50.0,50.0,50.0,50.0,30.0,30.0};
+
+
+
+int ii,jj,kk; //counting varaibles
+
+//-----These are the variables being shared between High-Level and Mid-Level-----------------------------------------------//
+
+double dblPSI[3][3]; //the message from high-level containing the chamber lengths in meters in following format:
+            /*
+            {L(front,1),   L(front,2),    L(front,3);
+             L(mid,1)  ,   L(mid,2)  ,    L(mid,3);
+             L(rear,1) ,   L(rear,2) ,    L(rear,3);}
+            */
+    
+double dblPosition_mtrs[N_CHANNELS]; //the actual chamber lengths in meters given as the change in length relative to neutral (should always be >=0)
+double dblPressure_bar[N_CHANNELS]; //the pressure in a given chamber in bar (1 bar  = 100,000 Pa).
+double dblTargetTime_s; //the time in seconds desired to reach the target (>0...!)
+
+//
+Semaphore semReplan(1);// this must be set every time new high-level transmissions are received to allow replanning to take place!
+//--------------------------------------------------------------------------------------------------------------------------//
+
+//boolean flag to indicate that new target information has been received
+//bool blnReplan;//set this when new transmission is received over ethernet
+
+//path variables
+double dblVelocity_mmps[N_CHANNELS];//the linear path velocity (not sent to actuator)
+double dblLinearPath_mm[N_CHANNELS]; //the current position of the linear path (not sent to actuator)
+double dblSmoothPath_mm[N_CHANNELS]; //the current position of the smooth path (not sent to actuator)
+double dblTargetChambLen_mm[N_CHANNELS]; //the currenly assigned final target position (actuator will reach this at end of path)
+double dblTargetActLen_mm[N_CHANNELS];
+double dblPathToActuator[N_CHANNELS];//the target position for the actuator (sent to actuator)
+
+int intDemPos_Tx[N_CHANNELS]; //13-bit value to be sent to the actuator
+int intPosSPI_Rx[N_CHANNELS]; //13 bit value received over SPI from the actuator
+int intPosADC_Rx[N_CHANNELS]; //12-bit ADC reading of potentiometer on actuator
+
+double dblPathTolerance; //how close the linear path must get to the target position before considering it a success.
+
+double dblActuatorConversion[N_CHANNELS] = {0.24176,0.24176,0.24176,0.24176,0.24176,0.36264,0.36264};
+
+double dblSmoothingFactor = 0.5;
+
+char chrErrorFlag[N_CHANNELS];
+
+Serial pc(USBTX, USBRX); // tx, rx for usb debugging
+
+SPI spi(PC_12,PC_11, PC_10); // mosi, miso, sclk
+
+DigitalOut cs_LL[N_CHANNELS] = {PF_10, PD_13, PE_7, PD_12, PD_14, PD_11, PD_15, PE_10};//chip select for low level controller
+DigitalOut cs_ADC[N_CHANNELS] = {PF_1, PF_0, PD_1, PD_0, PG_0, PE_1, PG_9, PG_12}; //chip select for ADC
+
+InterruptIn pinGate[N_CHANNELS] ={PE_11, PE_13, PF_3, PF_13, PF_15, PF_12, PF_11, PG_14};//gate interrupt pins
+
+DigitalOut pinReset(PD_2); //reset pin for all controllers.
+
+EventQueue queue(32 * EVENTS_EVENT_SIZE);
+
+Thread t(osPriorityRealtime);
+
+Thread threadReplan(osPriorityBelowNormal);
+Thread threadPathPlan(osPriorityNormal);
+
+Thread threadSimulateDemand(osPriorityHigh);
+
+Mutex mut[N_CHANNELS];
+
+Semaphore semPathPlan(1);//
+
+Timer timer;//timers are nice
+
+
+/*
+  unsigned int result1 = 0;
+  unsigned int result2 = 0;
+  unsigned int result3 = 0;
+  unsigned int result4 = 0;
+  
+  unsigned int result1a = 0;
+  unsigned int result1b = 0;
+*/
+
+
+
+
+double dblDemPosition[N_CHANNELS];
+double dblPosition[N_CHANNELS];
+double dblPressure[N_CHANNELS];
+
+int ThreadID[N_CHANNELS];
+
+bool blnDataReady[N_CHANNELS];
+
+unsigned int ReadADCPosition(int channel)
+{
+    unsigned int outputA;
+    unsigned int outputB;
+    unsigned int output;
+
+    spi.format(8,0);
+    spi.frequency(1000000);
+    
+    cs_ADC[channel] = 0;
+    spi.write(PREAMBLE);
+    outputA = spi.write(CHAN_3);
+    outputB = spi.write(0xFF);
+    cs_ADC[channel] = 1;
+    
+    outputA = outputA & DATA_MASK;
+    outputA = outputA<<8;
+    output = (outputA | outputB);
+    
+    return output;
+}
+    
+unsigned int ReadADCPressure(int channel)
+{
+    unsigned int outputA;
+    unsigned int outputB;
+    unsigned int output;
+
+    spi.format(8,0);
+    spi.frequency(1000000);
+    
+    cs_ADC[channel] = 0;
+    spi.write(PREAMBLE);
+    outputA = spi.write(CHAN_1);
+    outputB = spi.write(0xFF);
+    cs_ADC[channel] = 1;
+    
+    outputA = outputA & DATA_MASK;
+    outputA = outputA<<8;
+    output = (outputA | outputB);
+    
+    return output;
+}
+
+void TransmitData(int channel) 
+{
+    //get data from controller
+    spi.format(16,2);
+    spi.frequency(LOW_LEVEL_SPI_FREQUENCY);
+    
+    cs_LL[channel] = 0;//select relevant chip
+    intPosSPI_Rx[channel] = spi.write(intDemPos_Tx[channel]); //transmit & receive
+    cs_LL[channel] = 1;//deselect chip
+    
+    //sort out received data
+    chrErrorFlag[channel] = intPosSPI_Rx[channel]>>13;
+    intPosSPI_Rx[channel] = intPosSPI_Rx[channel] & 0x1FFF;
+    dblPosition_mtrs[channel] = (double)intPosSPI_Rx[channel]/8191*MAX_ACTUATOR_LENGTH/dblActuatorConversion[channel];
+}
+
+//common rise handler function 
+
+void common_rise_handler(int channel)
+{
+    //check if data is ready for tranmission
+    if (blnDataReady[channel])
+    {
+        // Add transmit task to event queue
+        blnDataReady[channel] = 0;//data no longer ready
+        ThreadID[channel] = queue.call(TransmitData,channel);//schedule transmission
+    }
+}
+
+
+
+//common_fall handler functions
+void common_fall_handler(int channel) 
+{
+    //cancel relevant queued event    
+    queue.cancel(ThreadID[channel]);
+}
+
+//stub rise functions
+void rise0(void) { common_rise_handler(0); }
+void rise1(void) { common_rise_handler(1); }
+void rise2(void) { common_rise_handler(2); }
+void rise3(void) { common_rise_handler(3); }
+void rise4(void) { common_rise_handler(4); }
+void rise5(void) { common_rise_handler(5); }
+void rise6(void) { common_rise_handler(6); }
+void rise7(void) { common_rise_handler(7); }
+
+//stub fall functions
+void fall0(void) { common_fall_handler(0); }
+void fall1(void) { common_fall_handler(1); }
+void fall2(void) { common_fall_handler(2); }
+void fall3(void) { common_fall_handler(3); }
+void fall4(void) { common_fall_handler(4); }
+void fall5(void) { common_fall_handler(5); }
+void fall6(void) { common_fall_handler(6); }
+void fall7(void) { common_fall_handler(7); }
+
+void startPathPlan()
+{
+    semPathPlan.release();
+}
+
+//this function will be called when a new transmission is received from high level
+void ReplanPath()
+{
+    //while(1)
+    //{
+        //semReplan.wait();//wait until called
+        //printf("replan!\r\n");
+        for (ii = 0; ii < N_CHANNELS; ii++)
+        {
+            mut[ii].lock();
+        }
+        
+        //update front segment
+        dblTargetChambLen_mm[0] = dblPSI[0][0]*1000;
+        dblTargetChambLen_mm[1] = dblPSI[0][1]*1000;
+        dblTargetChambLen_mm[2] = dblPSI[0][2]*1000;
+        //update mid segment
+        dblTargetChambLen_mm[6] = dblPSI[1][0]*1000;
+        dblTargetChambLen_mm[7] = dblTargetChambLen_mm[6]; //same because two pumps are used
+        //update rear segment
+        dblTargetChambLen_mm[3] = dblPSI[2][0]*1000;
+        dblTargetChambLen_mm[4] = dblPSI[2][1]*1000;
+        dblTargetChambLen_mm[5] = dblPSI[2][2]*1000;
+        
+        for (ii = 0; ii < N_CHANNELS; ii++)
+        {
+            mut[ii].unlock();
+        }
+
+        for (ii = 0; ii< N_CHANNELS; ii++)
+        {
+            mut[ii].lock();//lock variables to avoid race condition
+            
+            //check to see if positions are achievable
+            if(dblTargetChambLen_mm[ii]>dblMaxChamberLengths_mm[ii]) 
+            {
+                dblTargetChambLen_mm[ii] = dblMaxChamberLengths_mm[ii]; 
+            }
+            
+            if(dblTargetChambLen_mm[ii]<0.0) 
+            {
+                dblTargetChambLen_mm[ii] = 0.0; 
+            }
+            
+            dblTargetActLen_mm[ii] = dblTargetChambLen_mm[ii]*dblActuatorConversion[ii];
+                
+            //work out new velocities
+            dblVelocity_mmps[ii] = (dblTargetActLen_mm[ii] - dblLinearPath_mm[ii]) / dblTargetTime_s;
+            
+            //check to see if velocities are achievable
+            if(abs(dblVelocity_mmps[ii]) > MAX_SPEED_MMPS)
+            {
+                if(dblVelocity_mmps[ii]>0)
+                {
+                    dblVelocity_mmps[ii] = MAX_SPEED_MMPS;
+                }
+                else 
+                {
+                    dblVelocity_mmps[ii] = -1*MAX_SPEED_MMPS;
+                }
+            }
+            
+            mut[ii].unlock(); //unlock mutex.
+        }
+    //}
+    
+    
+}
+
+void CalculatePath()
+{
+    while(1)
+    {
+        semPathPlan.wait();
+        //if(blnReplan)
+//        {
+//            blnReplan = 0;//remove flag
+//            ReplanPath(dblPSI, dblTargetTime_s);
+//        }
+        for(ii = 0; ii < N_CHANNELS; ii++)
+        {
+            //calculate next step in linear path
+            mut[ii].lock();//lock relevant mutex
+            dblLinearPath_mm[ii] = dblLinearPath_mm[ii] + dblVelocity_mmps[ii]*PATH_SAMPLE_TIME_S;
+            //check tolerance
+            if (abs(dblLinearPath_mm[ii] - dblTargetActLen_mm[ii]) <= dblPathTolerance)
+            {
+                dblVelocity_mmps[ii] = 0; //stop linear path generation when linear path is within tolerance of target position.
+            }
+            mut[ii].unlock();//unlock relevant mutex
+            
+            //calculate next step in smooth path
+            dblSmoothPath_mm[ii] = dblSmoothingFactor*dblLinearPath_mm[ii] + (1.0-dblSmoothingFactor)*dblSmoothPath_mm[ii];
+            
+            //convert to actuator distances
+            dblPathToActuator[ii] = dblSmoothPath_mm[ii];
+            
+            intDemPos_Tx[ii] = (int) dblPathToActuator[ii]/MAX_ACTUATOR_LENGTH*8191;//convert to a 13-bit number;
+            intDemPos_Tx[ii] = intDemPos_Tx[ii] & 0x1FFF; //ensure number is 13-bit 
+            
+          
+            blnDataReady[ii] = 1;//signal that data ready
+
+        }
+        printf("%d, %f,%f,%f, %f\r\n",timer.read_ms(), dblTargetActLen_mm[0] ,dblVelocity_mmps[0], dblLinearPath_mm[0], dblSmoothPath_mm[0]);
+    }
+}
+
+void SimulateDemand()
+{
+    while(1)
+    {
+        mut[0].lock();
+        if(kk == 0)
+        {
+            dblPSI[0][0] = (double) 10.0;
+            dblTargetTime_s = 1.0;
+        }
+        else
+        { 
+            dblPSI[0][0] = (double) 0.0; 
+            dblTargetTime_s = 2.0;
+        }
+        
+        kk = 1 - kk;
+        
+        
+        //semReplan.release();
+        
+        mut[0].unlock();
+        ReplanPath();
+    
+        Thread::wait(7000);
+    }
+}
+
+
+
+Ticker PathCalculationTicker;
+
+int main() 
+{
+    //initialise relevant variables
+    for(ii = 0; ii<N_CHANNELS; ii++)
+    {
+        //all chip selects in off state
+        cs_LL[ii] = 1;
+        cs_ADC[ii] = 1;
+        
+        //data ready flags set to not ready
+        blnDataReady[ii] = 0;
+    }
+    
+    //calculate some control variables
+    dblPathTolerance = 0.1;//MAX_SPEED_MMPS * PATH_SAMPLE_TIME_S * 1.05; //path tolerance. 
+    
+    pinReset = 1; //initialise reset pin to not reset the controllers.
+    
+    //say something nice to the user.
+    pc.baud(9600);
+    printf("Hi, there! I'll be your mid-level controller for today.\r\n");
+    
+    // Start the event queue
+    t.start(callback(&queue, &EventQueue::dispatch_forever));
+    
+    //set up the interrupts
+
+    //set up rise interrupts MIGHT NOT NEED TO BE POINTERS
+    pinGate[0].rise(&rise0);
+    pinGate[1].rise(&rise1);
+    pinGate[2].rise(&rise2);
+    pinGate[3].rise(&rise3);
+    pinGate[4].rise(&rise4);
+    pinGate[5].rise(&rise5);
+    pinGate[6].rise(&rise6);
+    pinGate[7].rise(&rise7);
+    
+    //set up fall interrupts MIGHT NOT NEED TO BE POINTERS
+    pinGate[0].fall(&fall0);
+    pinGate[1].fall(&fall1);
+    pinGate[2].fall(&fall2);
+    pinGate[3].fall(&fall3);
+    pinGate[4].fall(&fall4);
+    pinGate[5].fall(&fall5);
+    pinGate[6].fall(&fall6);
+    pinGate[7].fall(&fall7);
+    
+    timer.start();
+    kk = 0;
+    
+    threadSimulateDemand.start(SimulateDemand);
+    threadPathPlan.start(CalculatePath); //start planning thread
+    PathCalculationTicker.attach(&startPathPlan, PATH_SAMPLE_TIME_S); //set up planning thread to recur at fixed intervals
+    threadReplan.start(ReplanPath);//start Replanning thread 
+     Thread::wait(1);  
+     
+      
+    while(1) { 
+    
+    
+    
+    Thread::wait(osWaitForever); 
+    }
+}
+