Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: ros_lib_kinetic
Revision 42:5a5ad23a4bb1, committed 2021-06-24
- Comitter:
- dofydoink
- Date:
- Thu Jun 24 20:34:47 2021 +0000
- Parent:
- 41:0e3898b29230
- Commit message:
- first
Changed in this revision
--- a/LLComms.cpp Thu Sep 03 16:30:23 2020 +0000
+++ b/LLComms.cpp Thu Jun 24 20:34:47 2021 +0000
@@ -4,30 +4,25 @@
LLComms::LLComms() :
queue(32 * EVENTS_EVENT_SIZE), //32 //8 * EVENTS_EVENT_SIZE
- pinGate6(PA_5),
spi_0(PC_12, PC_11, PC_10),
- spi_1(PF_9, PF_8, PF_7),
- spi_2(PB_15, PC_2, PB_13),
+// spi_1(PF_9, PF_8, PF_7),
+// spi_2(PB_15, PC_2, PB_13),
// These interrupt pins have to be declared AFTER SPI declaration. No Clue Why.
pinGate0(PF_11),
pinGate1(PG_14),
pinGate2(PF_15),
- pinGate3(PF_12),
- pinGate4(PF_3),
- pinGate5(PC_7),
- pinGate7(PE_13),
- pinGate8(PF_4),
+ //pinGate3(PF_12),
pinReset(PD_2)
{ // Constructor
spi_0.format(16,2);
spi_0.frequency(LOW_LEVEL_SPI_FREQUENCY);
- spi_1.format(16,2);
- spi_1.frequency(LOW_LEVEL_SPI_FREQUENCY);
- spi_2.format(16,2);
- spi_2.frequency(LOW_LEVEL_SPI_FREQUENCY);
+// spi_1.format(16,2);
+// spi_1.frequency(LOW_LEVEL_SPI_FREQUENCY);
- PinName LLPins[N_CHANNELS] = {PD_15, PE_10, PD_11, PD_14, PE_7, PB_1, PB_12, PD_13, PB_5};
+
+ PinName LLPins[N_CHANNELS] = {PD_15, PE_10, PD_14};//, PD_11};//, PE_7, PB_1, PB_12, PD_13, PB_5};
+
for (short int i=0; i<N_CHANNELS; i++) {
isDataReady[i] = 0;
cs_LL[i] = new DigitalOut(LLPins[i]);
@@ -50,27 +45,26 @@
pinReset=0; // Reset controllers to be safe
wait(0.25);
pinReset = 1; // Ready to go
+
+// pinReset.mode(PullUp); // Initialise reset pin to not reset the controllers.
+// wait(0.25);
+// pinReset.write(0); // Reset controllers to be safe
+// wait(0.25);
+// pinReset.mode(PullUp); // Ready to go
+// wait(0.25);
// Set up rise interrupts MIGHT NOT NEED TO BE POINTERS
pinGate0.rise(callback(this,&LLComms::rise0));
pinGate1.rise(callback(this,&LLComms::rise1));
pinGate2.rise(callback(this,&LLComms::rise2));
- pinGate3.rise(callback(this,&LLComms::rise3));
- pinGate4.rise(callback(this,&LLComms::rise4));
- pinGate5.rise(callback(this,&LLComms::rise5));
- pinGate6.rise(callback(this,&LLComms::rise6));
- pinGate7.rise(callback(this,&LLComms::rise7));
- pinGate8.rise(callback(this,&LLComms::rise8));
+ //pinGate3.rise(callback(this,&LLComms::rise3));
+
// Set up fall interrupts MIGHT NOT NEED TO BE POINTERS
pinGate0.fall(callback(this,&LLComms::fall0));
pinGate1.fall(callback(this,&LLComms::fall1));
pinGate2.fall(callback(this,&LLComms::fall2));
- pinGate3.fall(callback(this,&LLComms::fall3));
- pinGate4.fall(callback(this,&LLComms::fall4));
- pinGate5.fall(callback(this,&LLComms::fall5));
- pinGate6.fall(callback(this,&LLComms::fall6));
- pinGate7.fall(callback(this,&LLComms::fall7));
- pinGate8.fall(callback(this,&LLComms::fall8));
+ //pinGate3.fall(callback(this,&LLComms::fall3));
+
}
//LLComms::~LLComms(void) { } // Destructor
@@ -141,6 +135,7 @@
} else {
inboundMsg = spi->write(dummyMsg);
}
+ //rawMsg[i] = inboundMsg;
if((unsigned int)inboundMsg != dummyMsg) { // Message is not dummy which is only used for reply
typeBit = inboundMsg>>1 & 0x1;
inboundMsgsData[typeBit] = inboundMsg>>7 & 0x1FF;
@@ -158,18 +153,21 @@
// Construct messages
unsigned int intPositionMsg = formatMessage(0,demandPosition_mm[channel],MAX_ACTUATOR_LIMIT_MM);
unsigned int intVelocityMsg = formatMessage(1,demandSpeed_mmps[channel],MAX_SPEED_MMPS);
-
+ //unsigned int rawMsg[3];
*cs_LL[channel] = 0; // Select relevant chip
unsigned int outboundMsgs[2] = { intPositionMsg , intVelocityMsg };
unsigned int inboundMsgsData[2] = { 0 };
bool isSPIsuccess = false;
- if( channel < 4 ) {
+ if( channel < 3 ) {
isSPIsuccess = PerformMasterSPI(&spi_0,outboundMsgs,inboundMsgsData);
- } else if( channel < 7 ) {
- isSPIsuccess = PerformMasterSPI(&spi_1,outboundMsgs,inboundMsgsData);
- } else {
- isSPIsuccess = PerformMasterSPI(&spi_2,outboundMsgs,inboundMsgsData);
- }
+ } //else {
+// isSPIsuccess = PerformMasterSPI(&spi_1,outboundMsgs,inboundMsgsData,rawMsg);
+// }
+// else if( channel < 7 ) {
+// isSPIsuccess = PerformMasterSPI(&spi_1,outboundMsgs,inboundMsgsData);
+// } else {
+// isSPIsuccess = PerformMasterSPI(&spi_2,outboundMsgs,inboundMsgsData);
+// }
*cs_LL[channel] = 1; // Deselect chip
if( isSPIsuccess ) {
isDataReady[channel] = 0; // Data no longer ready, i.e. we now require new data
@@ -180,15 +178,25 @@
pressureSensor_bar[channel] = ((double)inboundMsgsData[1]/511) * (double)MAX_PRESSURE_LIMIT;
pressureSensor_bar[channel] = min( max(pressureSensor_bar[channel],0.0) , (double)MAX_PRESSURE_LIMIT );
} else { // Data is STILL ready and will be resent at the next pin interrupt
- //printf("SPI failed: %d%d. Resending.\n\r",isPositionValid,isPressureValid);
+ printf("SPI failed: %d. Resending.\n\r",channel);
}
mutChannel[channel].unlock();//unlock mutex for specific channel
+
+ // if(channel ==3){
+// printf("%x\t%x\t%x\r\n",rawMsg[0], rawMsg[1], rawMsg[2] );
+// }
+
+// printf("%d, ", channel);
+// if(channel == 3){
+// printf("\r\n");
+// }
}
// Common rise handler function
void LLComms::common_rise_handler(int channel) {
//printf("%d %d common_rise_handler\n\r",channel,isDataReady[channel]);
+ //countervar++;
if (isDataReady[channel]) { // Check if data is ready for transmission
ThreadID[channel] = queue.call(this,&LLComms::SendReceiveData,channel); // Schedule transmission
}
@@ -203,19 +211,10 @@
void LLComms::rise0(void) { common_rise_handler(0); }
void LLComms::rise1(void) { common_rise_handler(1); }
void LLComms::rise2(void) { common_rise_handler(2); }
-void LLComms::rise3(void) { common_rise_handler(3); }
-void LLComms::rise4(void) { common_rise_handler(4); }
-void LLComms::rise5(void) { common_rise_handler(5); }
-void LLComms::rise6(void) { common_rise_handler(6); }
-void LLComms::rise7(void) { common_rise_handler(7); }
-void LLComms::rise8(void) { common_rise_handler(8); }
+//void LLComms::rise3(void) { common_rise_handler(3); }
+
// Stub fall functions
void LLComms::fall0(void) { common_fall_handler(0); }
void LLComms::fall1(void) { common_fall_handler(1); }
void LLComms::fall2(void) { common_fall_handler(2); }
-void LLComms::fall3(void) { common_fall_handler(3); }
-void LLComms::fall4(void) { common_fall_handler(4); }
-void LLComms::fall5(void) { common_fall_handler(5); }
-void LLComms::fall6(void) { common_fall_handler(6); }
-void LLComms::fall7(void) { common_fall_handler(7); }
-void LLComms::fall8(void) { common_fall_handler(8); }
\ No newline at end of file
+//void LLComms::fall3(void) { common_fall_handler(3); }
--- a/LLComms.h Thu Sep 03 16:30:23 2020 +0000
+++ b/LLComms.h Thu Jun 24 20:34:47 2021 +0000
@@ -35,6 +35,12 @@
double positionSensor_mm[N_CHANNELS]; // The actual chamber lengths in meters given as the change in length relative to neutral (should always be >=0)
unsigned int pressureSensor_uint[N_CHANNELS];
double pressureSensor_bar[N_CHANNELS]; // The pressure in a given chamber in bar (1 bar = 100,000 Pa)
+ unsigned int formatMessage(short int type, double dblValue, double dblMaxValue);
+ //bool CheckMessage(int msg, short int trueType);
+ bool CheckMessage(int msg);
+ bool PerformMasterSPI(SPI *spi, unsigned int outboundMsgs[], unsigned int inboundMsgsData[]);
+ void SendReceiveData(int channel);
+ int countervar;
LLComms(); // Constructor
//~LLComms(); // Destructor
@@ -42,50 +48,30 @@
private:
// PIN DECLARATIONS
- InterruptIn pinGate6; // This pin HAS TO BE defined before SPI set up. No Clue Why.
SPI spi_0; // mosi, miso, sclk
- SPI spi_1;
- SPI spi_2;
+ //SPI spi_1; // mosi, miso, sclk
DigitalOut* cs_LL[N_CHANNELS]; // Chip select for low level controller
//DigitalOut* cs_ADC[N_CHANNELS]; // Chip select for ADC
// These interrupt pins have to be declared AFTER SPI declaration. No Clue Why.
InterruptIn pinGate0;
InterruptIn pinGate1;
InterruptIn pinGate2;
- InterruptIn pinGate3;
- InterruptIn pinGate4;
- InterruptIn pinGate5;
- InterruptIn pinGate7;
- InterruptIn pinGate8;
- DigitalOut pinReset; // Reset pin for all controllers.
+ //InterruptIn pinGate3;
+ DigitalInOut pinReset; // Reset pin for all controllers.
int ThreadID[N_CHANNELS];
- unsigned int formatMessage(short int type, double dblValue, double dblMaxValue);
- //bool CheckMessage(int msg, short int trueType);
- bool CheckMessage(int msg);
- bool PerformMasterSPI(SPI *spi, unsigned int outboundMsgs[], unsigned int inboundMsgsData[]);
- void SendReceiveData(int channel);
+
void common_rise_handler(int channel);
void common_fall_handler(int channel);
void rise0(void);
void rise1(void);
void rise2(void);
- void rise3(void);
- void rise4(void);
- void rise5(void);
- void rise6(void);
- void rise7(void);
- void rise8(void);
+ //void rise3(void);
void fall0(void);
void fall1(void);
void fall2(void);
- void fall3(void);
- void fall4(void);
- void fall5(void);
- void fall6(void);
- void fall7(void);
- void fall8(void);
+ //void fall3(void);
};
--- a/MLSettings.h Thu Sep 03 16:30:23 2020 +0000 +++ b/MLSettings.h Thu Jun 24 20:34:47 2021 +0000 @@ -4,18 +4,20 @@ #define MLSETTINGS_H // GENERAL SETTINGS -const unsigned short int N_CHANNELS = 9; // Number of channels to control +const unsigned short int N_CHANNELS = 3; // Number of channels to control // 1-3: front segment; 4-6: rear segment; 7-8: mid segment const int BAUD_RATE = 115200; //9600; //115200 +const float PI = 3.14159265359; // HL COMMUNICATION SETTINGS const bool IS_DHCP = false; const unsigned short int HL_COMMS_FREQ_HZ = 200; // Frequency at which communications can happen with HL, if messages are waiting // REAL TIME FREQUENCIES -const short int SENSOR_FEEDBACK_HZ = 20; // Frequency at which sensor messages are queued / published to HL -const float LL_DEMANDS_FREQ_HZ = 50; -const unsigned int LOW_LEVEL_SPI_FREQUENCY = 10000000; +const short int SENSOR_FEEDBACK_HZ = 5; // Frequency at which sensor messages are queued / published to HL +const float LL_DEMANDS_FREQ_HZ = 5; +const unsigned int LOW_LEVEL_SPI_FREQUENCY = 1000000; +const double HHC_READ_FREQ_HZ = 50; const float MAX_PRESSURE_LIMIT = 12.0; @@ -23,5 +25,18 @@ const float MAX_ACTUATOR_LIMIT_MM = 40.0; const float MAX_ACTUATOR_LENGTH_MM = 52.2; const float MAX_SPEED_MMPS = 24.3457; +const float MAX_DRIVE_SEGMENT_POSITION = 8.0;//the maximum pressure attainable by LL +const double MAX_EXTENSION_PRESSURE = 6.0; //the desired maximum operating pressure. +const double MAX_DRIVE_SEGMENT_SPEED = 4.0; +const double SAFE_CONTRACT_SPEED = 2.0; +const double MAX_STEER_SPEED_RADpS = 1.3; //1.212 rad/s was calculated +const double SAFE_SPEED_MMpS = 8.0; +const double ANCHOR_POSITION = 25.0; +const double HOME_DRIVE_POSITION = 0.0; + +// KINEMATIC LIMTS & CONSTANTS +const float MAX_THETA_RAD = 3.665191429; //210 degrees +const float ACTUATOR_OFFSET = 6.0; //mm +const double ACT_CONV = 6.055836122; // mm/mL convert injected volume in [mL] to actuator distance in [mm] #endif \ No newline at end of file
--- a/main.cpp Thu Sep 03 16:30:23 2020 +0000
+++ b/main.cpp Thu Jun 24 20:34:47 2021 +0000
@@ -2,155 +2,841 @@
#include "math.h"
// MBED IMPORTS
#include "mbed.h"
-#include "mbed_events.h"
+
// CUSTOM IMPORTS
#include "MLSettings.h"
-#include "HLComms.h"
-#include "LLComms.h"
+//#include "HLComms.h"
+
+#define N_CHANNELS 4
// DEMAND VARIABLES
-double dblDemandSpeed_mmps[N_CHANNELS] = { 0.0 }; // The linear path velocity (not sent to actuator)
-double dblDemandPosition_mm[N_CHANNELS] = { 0.0 }; // The final target position for the actuator
Serial pc(USBTX, USBRX); // tx, rx for usb debugging
-LLComms llcomms;
-HLComms hlcomms(HL_COMMS_FREQ_HZ);
+
+//HLComms hlcomms(HL_COMMS_FREQ_HZ);
+
+double limDouble(double var, double min, double max){
+ double output = var;
+ if(var <min){
+ output = min;
+ }
+ if (var>max){
+ output = max;
+ }
+ return output;
+}
+
+
+//Ticker setDemandsTicker;
+
+
+//joystick input pins
+
+InterruptIn pinZeroIn (PD_4);
+InterruptIn pinCycleIn (PD_6);
+InterruptIn pinSucIn (PD_7);
+InterruptIn pinGasIn (PF_5);
+InterruptIn pinDebugIn (PF_9);
+InterruptIn pinFlushIn (PG_1);
+
+DigitalIn pinWashIn (PD_5);
+DigitalIn pinFwd (PD_3);
+DigitalIn pinRev (PC_3);
+
+
+AnalogIn pinJSX (PC_0);
+AnalogIn pinJSY (PF_3);
+
+DigitalOut pinFlushOut (PG_0);
+DigitalOut pinGasOut (PD_0);
+DigitalOut pinWashOut (PF_1);
+DigitalOut pinSucOut (PD_1);
+DigitalOut pinThirdPump(PF_2);
+DigitalOut pinJetOut (PF_0);
+
+//DigitalIn arPins[7] = {pinZeroIn, pinCycleIn, pinSucIn, pinWashIn, pinGasIn, pinFwd, pinRev};
+
+Thread threadReadHHC(osPriorityHigh);
+Thread threadSendFeedback(osPriorityNormal);
+
+Semaphore semReadHHC(1);
+Semaphore semSendFeedback(1);
+Semaphore semReceiveAndReplan(1);
+
+//Ticker SendSensorDataTicker;
+Ticker tickerReadHHC;
+Ticker tickerSendFeedback;
+
+void signalReadHHC(){
+ semReadHHC.release();
+}
+
+void signalSendFeedback() {
+ semSendFeedback.release();
+}
+
+//support function states;
+
+bool isZero = 0;
+bool isCycle = 0;
+bool isSuc = 0;
+bool isWash = 0;
+bool isGas = 0;
+bool isFwd = 0;
+bool isRev = 0;
+bool isBusy = 0;
+bool DemPos=0;
+bool isDebug = 0;
+
+//set up PWM output pins for Demand POSITION AND VELOCITY
+PwmOut pinPosOut[N_CHANNELS] = {PB_15, PB_8, PB_9 ,PC_6};
+PwmOut pinVelOut[N_CHANNELS] = {PB_10, PA_0, PB_11 ,PB_3};
+
-Thread threadLowLevelSPI(osPriorityRealtime);
-Thread threadSetDemands(osPriorityNormal);
-Thread threadReceiveAndReplan(osPriorityBelowNormal);
-Thread threadSensorFeedback(osPriorityBelowNormal);
+void FlushActivate(){
+ if(!isBusy){
+ pinFlushOut = 1;
+ }
+}
+
+void FlushStop(){
+ if(!isBusy){
+ pinFlushOut = 0;
+ }
+}
+
+void ZeroActivate(){
+ if(!isBusy){
+ isZero = 1;
+ }
+}
+void ZeroStop(){
+
+}
+
+void DebugActivate(){
+ isDebug = 1;
+}
+
+void DebugStop(){
+ isDebug = 0;
+}
+
+void CycleActivate(){
+ if(!isBusy){
+ isCycle = 1;
+ }
+}
+void CycleStop(){
+
+}
+
+void GasActivate(){
+ if(!isBusy){
+ pinGasOut = 1;
+ }
+}
+void GasStop(){
+ pinGasOut = 0;
+}
+
+void SucActivate(){
+ if(!isBusy){
+ pinSucOut = 1;
+ }
+}
+void SucStop(){
+ pinSucOut = 0;
+}
+
+bool isChange = 1;
+
+Timer timer1;
+
+Ticker DemTicker;
+
+int intAnchorDirection = 0;
+
+
+
+//global variables
+double dblSensitivity = 1.0;
+double dblDriveStep = 0.05;
+bool isSteerLock = 0;
+double dblAlpha;
+double dblBeta;
+double dblTheta;
+double dblPhi;
+double dblS;
+double dblSdot;
+double dblX[3];
+double dblXdot[3];
+double dblAlphaDot;
+double dblBetaDot;
+double dblDeltaAlpha;
+double dblDeltaBeta;
+
+double x_axis_sign = -1.0;
+
+//kinematic constants
+double K_theta = 0.77;// rad/mL
+double d_theta = 0.3;// no unit
-Mutex mutPathIn;
-Semaphore semLLcomms(1);
-Semaphore semSensorData(1);
+void SendFeedback(){
+ //support function interrupt states
+ while(1){
+ semSendFeedback.wait();
+ if(!isBusy){
+ if(pinFwd.read()){
+ isFwd = 1;
+ } else {
+ isFwd = 0;
+ }
+
+ if(pinRev.read()){
+ isRev = 1;
+ } else {
+ isRev = 0;
+ }
+
+ if(pinSucIn.read()){
+ isSuc = 1;
+ } else {
+ isSuc = 0;
+ }
+
+ if(pinWashIn.read()){
+ isWash = 1;
+ } else {
+ isWash = 0;
+ }
+
+ if(pinGasIn.read()){
+ isGas = 1;
+ } else {
+ isGas = 0;
+ }
+
+
+ //
+ //printf("\r\n");
+ //printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t", isZero, isGas, isSuc, isRev, isWash, isCycle, isFwd, isDebug);
+ //
+ // double dblJSXprint = pinJSX.read();
+ // double dblJSYprint = pinJSY.read();
+ // printf("X:%f\tY:%f\t", dblJSXprint, dblJSYprint);
+
+ // printf("%f\t",dblAlphaDot);
+ // printf("%f\t",dblBetaDot);
+ // printf(":: ");
+ //
+ // printf("%f\t",dblAlpha);
+ // printf("%f\t",dblBeta);
+ // printf(":: ");
+ //
+ // printf("%f\t",dblTheta);
+ // printf("%f\t",dblPhi);
+ // printf(":: ");
+ printf("\t");
+
+ printf("%f\t",dblX[1]);
+ printf("%f\t",dblX[0]);
+ printf("%f\t",dblX[2]);
+ printf(":: ");
+
+ // printf("%f\t",dblXdot[0]);
+ // printf("%f\t",dblXdot[2]);
+ // printf("%f\t",dblXdot[1]);
+ // printf(":: ");
+
+ printf("%f\t",dblS);
+ printf("%f\t",dblSdot);
+ printf("\r\n");
+ }
+ }
+}
-Ticker setDemandsTicker;
-Ticker SendSensorDataTicker;
+double DeadZone(double var, double threshold, double max, double min){
+
+ double output = var;
+ output -= 0.5;
+ min -= 0.5;
+ max -= 0.5;
+
+ if(output > threshold){
+ output = (output - threshold);
+ output /= (max - threshold);
+ } else if(output < -1.0*threshold){
+ output = -1.0*(output + threshold);
+ output /= (threshold + min);
+ } else {
+ output = 0.0;
+ }
+
+ output = limDouble(output, -1.0, 1.0);
+ return output;
+}
+
+double ConvertToPWM(double target, double max){
+ double output;
+ output = target*0.8/max ;
+ output += 0.1;
+ return output;
+}
-void sendSensorData() {
- while( true ) {
- semSensorData.wait();
- hlcomms.send_sensor_message(llcomms.positionSensor_uint,llcomms.pressureSensor_uint);
+void SetFrontDemand(double demandPos[], double demandVel[]){
+
+ double demandPos_abs[3];
+ double demandVel_abs[3];
+ double pwmPos_front[3];
+ double pwmVel_front[3];
+
+ for(int ii = 0; ii<3; ii++){
+ demandPos_abs[ii] = abs(demandPos[ii]);
+ demandVel_abs[ii] = abs(demandVel[ii]);
+ pwmPos_front[ii] = ConvertToPWM(demandPos_abs[ii], (double)MAX_ACTUATOR_LIMIT_MM);
+ pwmVel_front[ii] = ConvertToPWM(demandVel_abs[ii], (double)MAX_SPEED_MMPS);
+ pinPosOut[ii].write(pwmPos_front[ii]);
+ pinVelOut[ii].write(pwmVel_front[ii]);
+
+ }
+
+/*
+ //print for debugging
+ printf("X: ");
+ for(int ii = 0; ii<3; ii++){
+ printf("%f\t",pwmPos_front[ii]);
+ }
+ printf("Xdot: ");
+ for(int ii = 0; ii<3; ii++){
+ printf("%f\t",pwmVel_front[ii]);
+ }
+ */
+}
+
+void SetDriveDemand(double drivePos, double driveVel){
+
+ double drivePos_abs;
+ double driveVel_abs;
+ double pwmPos_drive;
+ double pwmVel_drive;
+
+ drivePos_abs = abs(drivePos);
+ driveVel_abs = abs(driveVel);
+
+ pwmPos_drive = ConvertToPWM(drivePos_abs, MAX_DRIVE_SEGMENT_POSITION);
+ pwmVel_drive = ConvertToPWM(driveVel_abs, MAX_DRIVE_SEGMENT_SPEED);
+
+ pinPosOut[3].write(pwmPos_drive);
+ pinVelOut[3].write(pwmVel_drive);
+
+ /*
+ //print for debugging
+ printf("S:%f\tSdot:%f\t",pwmPos_drive,pwmVel_drive);
+ */
+}
+
+double GetMaxTravelTime(double startPositions[], double endPositions[], double speed){
+ double arT[3];
+ for(int ii = 0; ii< 3; ii++){
+ arT[ii] = endPositions[ii] - startPositions[ii];
+ arT[ii] /= speed;
+ arT[ii] = abs(arT[ii]);
+ }
+ double Tmax = 0.0;
+ for(int ii = 0; ii<3; ii++){
+ if( Tmax < arT[ii] ){
+ Tmax = arT[ii];
+ }
+ }
+ return Tmax;
+}
+
+void UpdateFrontSegPosition(double position[]){
+ for(int ii = 0; ii<3; ii++){
+ dblX[ii] = position[ii];
}
}
-void signalSendSensorData() {
- semSensorData.release();
+void GoToNeutralPose(double speed){
+ isBusy = 1;
+ double T_wait;
+ double arSpeed[3] = {speed, speed, speed};
+ double arPosition[3] = {ACTUATOR_OFFSET, ACTUATOR_OFFSET, ACTUATOR_OFFSET};
+ SetFrontDemand(arPosition, arSpeed);
+
+ //T_wait = 40.0 / speed;
+ T_wait = GetMaxTravelTime(dblX, arPosition, speed);
+ T_wait += 0.25;//add a little bit of time for security
+ //print for debug
+ printf("\r\nGoing to neutral. %f\r\n", T_wait);
+
+ wait(T_wait);
+ UpdateFrontSegPosition(arPosition);
+ //isZero = 0;
+ isBusy = 0;
+}
+
+void GoToAnchorPose(double speed){
+ //reset front segment position
+ //isAnchor = 0;
+ isBusy = 1;
+ double T_wait;
+ double arSpeed[3] = {speed, speed, speed};
+ double arStartPosition[3];
+ //save starting position
+ for (int ii = 0; ii<3; ii++){
+ arStartPosition[ii] = dblX[ii];
+ }
+
+ double arAnchorPosition[3] = {ACTUATOR_OFFSET, ACTUATOR_OFFSET, ACTUATOR_OFFSET};
+
+//Go to neutral
+ GoToNeutralPose(speed);
+
+ //select direction of anchor
+ arAnchorPosition[intAnchorDirection] = ANCHOR_POSITION;
+ intAnchorDirection++; //rotate next anchoring position
+ if(intAnchorDirection >= 3){
+ intAnchorDirection = 0;
+ }
+//go to anchor position
+ SetFrontDemand(arAnchorPosition, arSpeed);
+ T_wait = GetMaxTravelTime(dblX, arAnchorPosition, speed);
+ T_wait += 0.25;//add a little bit of time for security
+ printf("Going to anchor. %f s\r\n", T_wait);
+ wait(T_wait);
+
+ //update front segment position.
+ UpdateFrontSegPosition(arAnchorPosition);
+
+//contract
+ SetDriveDemand(HOME_DRIVE_POSITION, SAFE_CONTRACT_SPEED);
+ T_wait = dblS - HOME_DRIVE_POSITION;
+ T_wait /= SAFE_CONTRACT_SPEED;
+ printf("Contracting. %f s\r\n", T_wait);
+ wait(T_wait);
+ //update drive segment position
+ dblS = HOME_DRIVE_POSITION;
+
+//go back to neutral pose
+ GoToNeutralPose(speed);
+
+//go back to starting position
+ SetFrontDemand(arStartPosition, arSpeed);
+ T_wait = GetMaxTravelTime(dblX, arStartPosition, speed);
+ T_wait += 0.25;//add a little bit of time for security
+ printf("Going to intial position. %f\r\n", T_wait);
+ wait(T_wait);
+ //UpdateFrontSegPosition(arStartPosition);
+ for(int ii = 0; ii<3; ii++){
+ dblX[ii] = arStartPosition[ii];
+ }
+
+ //print for debug
+ isBusy = 0;
+}
+
+
+void GoToCustomPose(double position[], double speed){
+ //reset front segment position
+ //isBusy = 1;
+ double T_wait;
+ double arSpeed[3] = {speed, speed, speed};
+ for (int ii = 0; ii<3; ii++){
+ position[ii] = limDouble(position[ii], 0.0, (double)MAX_ACTUATOR_LIMIT_MM);
+ }
+ SetFrontDemand(position, arSpeed);
+
+ //T_wait = 40.0 / speed;
+ T_wait = GetMaxTravelTime(dblX, position, speed);
+ T_wait += 0.25;//add a little bit of time for security
+ //print for debug
+ printf("\r\nGoing to custom pose. T_wait: %f s \r\n", T_wait);
+ wait(T_wait);
+ UpdateFrontSegPosition(position);
+ printf("Done\r\n");
+ //isBusy = 0;
+}
+
+
+void AllGoTo(double position, double speed){
+ //reset front segment position
+ //isBusy = 1;
+ double T_wait;
+ double arSpeed[3] = {speed, speed, speed};
+ position = limDouble(position, 0.0, (double)MAX_ACTUATOR_LIMIT_MM);
+
+ double arPosition[3] = {position, position, position};
+ SetFrontDemand(arPosition, arSpeed);
+
+ //T_wait = 40.0 / speed;
+ T_wait = GetMaxTravelTime(dblX, arPosition, speed);
+ T_wait += 0.25;//add a little bit of time for security
+ //print for debug
+ printf("\r\nMoving all to %f mm. T_wait: %f\r\n",position, T_wait);
+
+ wait(T_wait);
+ UpdateFrontSegPosition(arPosition);
+ printf("Done\r\n");
+ //isBusy = 0;
+}
+
+void FlushSyringes(int repetitions){
+ //isBusy = 1;
+ printf("\r\n\r\n:::Flushing Syringes:::\r\n");
+ pinFlushOut = 1;
+ wait(1.0);
+ for(int ii = 0; ii<repetitions; ii++){
+ AllGoTo(40.0,20.0);
+ wait(0.5);
+ AllGoTo(0.0,2.0);
+ wait(0.5);
+ }
+ pinFlushOut = 0;
+ printf("Done\r\n");
+ //isBusy = 0;
+}
+
+void FlushSegment(int repetitions){
+ //isBusy = 1;
+ printf("\r\n\r\n:::Flushing Segment:::\r\n");
+ FlushSyringes(1);//ensure syringes are flushed.
+ double arZero[3] = {0.0, 0.0, 0.0};
+
+ double flushPosition = 30.0;
+
+ double arFlushPose1[3] = {flushPosition, 0.0, 0.0};
+ double arFlushPose2[3] = {0.0, flushPosition, 0.0};
+ double arFlushPose3[3] = {0.0, 0.0, flushPosition};
+ for(int ii = 0; ii<repetitions; ii++){
+ //flush first chamber
+ printf("Flushing first chamber\r\n");
+ GoToCustomPose(arFlushPose1, SAFE_SPEED_MMpS);
+ AllGoTo(0.0, SAFE_SPEED_MMpS);
+
+ //flush second chamber
+ printf("Flushing second chamber\r\n");
+ GoToCustomPose(arFlushPose2, SAFE_SPEED_MMpS);
+ AllGoTo(0.0, SAFE_SPEED_MMpS);
+
+ //flush third chamber
+ printf("Flushing third chamber\r\n");
+ GoToCustomPose(arFlushPose3, SAFE_SPEED_MMpS);
+ AllGoTo(0.0, SAFE_SPEED_MMpS);
+
+ FlushSyringes(1);//flush syringes
+ }
+ printf("Done\r\n");
+ //isBusy = 0;
}
-// This function will be called when a new transmission is received from high level
-void ReceiveAndReplan() {
+void FlushTubing(int repetitions){
+ //isBusy = 1;
+ printf("\r\n\r\n:::Flushing Tubing:::\r\n");
+ for (int ii = 0; ii<repetitions; ii++){
+ AllGoTo(40.0,15.0);
+ pinFlushOut = 1;
+ wait(1.0);
+ AllGoTo(0.0, 2.0);
+ pinFlushOut = 0;
+ wait(0.5);
+ }
+}
- SendSensorDataTicker.attach(&signalSendSensorData, 1/(float)SENSOR_FEEDBACK_HZ); // Set up planning thread to recur at fixed intervals
+
+void DebugMode(){
+ isBusy = 1;
+ printf("\r\nEntering debug mode. Going to zero.\r\n");
+ double zeroPos[3] = {0.0, 0.0, 0.0};
+ double safeVel[3] = {SAFE_SPEED_MMpS, SAFE_SPEED_MMpS, SAFE_SPEED_MMpS};
- struct demands_struct input;
- DigitalOut SupportPins[4] = {PE_4, PE_2, PE_3, PE_6};
+
+ SetFrontDemand(zeroPos, safeVel);
+ SetDriveDemand(0.0, SAFE_CONTRACT_SPEED);
+ double T_wait = GetMaxTravelTime(dblX, zeroPos, SAFE_SPEED_MMpS);
+ T_wait += 0.25;
+ wait(T_wait);
+ UpdateFrontSegPosition(zeroPos);
+ printf("Done\r\nPlease enter command\r\n");
+
+ int countSyringeFlush = 0;
+ int countSegmentFlush = 0;
+ int countTubingFlush = 0;
- while( true ) {
- hlcomms.newData.wait();
- input = hlcomms.get_demands();
- // SUPPORT FUNCTIONS
- // [isInsufflate,isSuction,isWashLens,isJet]
- for(short int i=0; i<4; i++) {
- if(i<2) { // Active low, i.e. 0 = Off
- SupportPins[i].write((short int)input.utitilies_bool[i]);
- } else { // Active high, i.e. 1 = Off
- SupportPins[i].write((short int)(!input.utitilies_bool[i]));
+ while(isDebug){
+ isBusy = 1;
+ //printf("x\r\n");
+
+ if( pinZeroIn.read() ){
+ //printf("zero%d\r\n",countSyringeFlush);
+
+ if(countSyringeFlush == 0){
+ printf("\r\n Syringe Flush Selected\r\n");
+ }
+ countSyringeFlush++;
+ countSegmentFlush = 0;
+ countTubingFlush = 0;
+ if(countSyringeFlush > 50){
+ FlushSyringes(4);
+ countSyringeFlush = 0;
}
+ //printf("%d\r\n", countSyringeFlush);
+
+ }else {
+ countSyringeFlush = 0;
+ }
+
+ if( pinSucIn.read() ){
+ //printf("suc%d\r\n", countSegmentFlush);
+
+ if(countSegmentFlush == 0){
+ printf("\r\n Segment Flush Selected\r\n");
+ }
+ countSyringeFlush = 0;
+ countSegmentFlush++;
+ countTubingFlush = 0;
+ if(countSegmentFlush > 50){
+ FlushSegment(2);
+ countSegmentFlush = 0;
+ }
+ }else {
+ countSegmentFlush = 0;
+ }
+
+ if( pinWashIn.read() ){
+ //printf("wash%d\r\n", countTubingFlush);
+ if(countTubingFlush == 0){
+ printf("\r\n Tubing Flush Selected\r\n");
+ }
+ countSyringeFlush = 0;
+ countSegmentFlush = 0;
+ countTubingFlush++;
+ if(countTubingFlush > 50){
+ FlushTubing(2);
+ countTubingFlush = 0;
+ }
+ }else {
+ countTubingFlush = 0;
}
- // PROCESS INPUT
- double maxTimesToTarget_s[3] = { -1.0 };
- //[8,7,6,4,3,-1,-1,0,-1]
- //FRONT = channels 0,1,2
- //MID = channels 3,4(,5)
- //REAR = channels (6,)7(,8)
- // Lock mutex, preventing setDemandsForLL from running
- mutPathIn.lock();
- for(short int segNum=0; segNum<3; segNum++) {
- // Limit requested speed
- if( input.speeds_mmps[segNum] > 0 ) {
- double limitedSpeed_mmps = min( max( 0.0 , input.speeds_mmps[segNum] ) , (double)MAX_SPEED_MMPS );
- // For each actuator, limit the input position, calculate the position change, and select the absolute max
- double dblDistanceToTarget_mm[3] = { -1.0 };
- double maxDistanceToTarget_mm = 0.0;
- for(short int i=0; i<3; i++) {
- short int channel = segNum*3+i;
- if(channel>=N_CHANNELS) {
- continue;
+
+ wait(0.1);
+ }
+
+ GoToNeutralPose(SAFE_SPEED_MMpS);
+ //reset front segment position
+ dblAlpha = 0.0;
+ dblBeta = 0.0;
+ printf("\r\nManual control enabled\r\n");
+ isBusy = 0;
+}
+
+void ReadHHC(){
+ printf("Homing. Please wait...\r\n");
+
+
+ double startingPos[3] = {ACTUATOR_OFFSET, ACTUATOR_OFFSET, ACTUATOR_OFFSET};
+ double startingVel[3] = {SAFE_SPEED_MMpS, SAFE_SPEED_MMpS, SAFE_SPEED_MMpS};
+ SetFrontDemand(startingPos, startingVel);
+ SetDriveDemand(HOME_DRIVE_POSITION, SAFE_CONTRACT_SPEED);
+ wait(5);
+ printf("Done.\r\n");
+ threadSendFeedback.start(SendFeedback);
+ tickerSendFeedback.attach(&signalSendFeedback, 1/(float)SENSOR_FEEDBACK_HZ);
+ while(1){
+ semReadHHC.wait();
+
+ if(isZero){
+ GoToNeutralPose(SAFE_SPEED_MMpS);
+ //reset front segment position
+ dblAlpha = 0.0;
+ dblBeta = 0.0;
+ isZero = 0;
+ printf("Done\r\n");
+ }
+
+ if(isCycle){
+ GoToAnchorPose(SAFE_SPEED_MMpS);
+ isCycle = 0;
+ printf("Done\r\n");
+ }
+ if(isDebug){
+ DebugMode();
+ }
+
+ if(!isSteerLock){
+ //read Joystick sensors
+ double dblJSX = pinJSX.read();
+ double dblJSY = pinJSY.read();
+
+ dblJSX = DeadZone(dblJSX, 0.07, 0.85, 0.15);
+ dblJSY = DeadZone(dblJSY, 0.07, 0.85, 0.15);
+
+ if(pinWashIn.read()){
+ pinWashOut = 0;
+ }else{
+ pinWashOut = 1;
+ }
+
+ //convert to angular velocity for front segment
+
+ //Find changes in angle
+ dblDeltaAlpha = dblJSX * x_axis_sign * dblSensitivity * MAX_STEER_SPEED_RADpS / HHC_READ_FREQ_HZ;
+ dblDeltaBeta = dblJSY*dblSensitivity*MAX_STEER_SPEED_RADpS/HHC_READ_FREQ_HZ;
+ //convert to speeds in [rad/s]
+ dblAlphaDot = dblDeltaAlpha*HHC_READ_FREQ_HZ;
+ dblBetaDot = dblDeltaBeta*HHC_READ_FREQ_HZ;
+
+ //calculate required velocity based on current possition and new inputs.
+ dblPhi = atan2(dblBeta,dblAlpha);
+ double dblPhiDot = dblAlpha * dblBetaDot - dblBeta * dblAlphaDot;
+ dblPhiDot /= (dblAlpha * dblAlpha + dblBeta*dblBeta);
+ if( fabs( cos(dblPhi) ) >= 0.7106781 ){
+ dblTheta = dblAlpha / cos(dblPhi);
+ double dblThetaDot = dblAlphaDot * cos(dblPhi) + dblAlpha * dblPhiDot * sin(dblPhi);
+ dblThetaDot /= cos(dblPhi)*cos(dblPhi);
+ double dblPsi[3];
+ for (int ii =0; ii<3; ii++){
+ dblPsi[ii] = dblPhi - ii*2*PI/3;
+ if(dblBeta == 0){
+ dblXdot[ii] = ACT_CONV * K_theta*( cos(dblPsi[ii]) + d_theta);
+ dblXdot[ii] *= ( dblAlphaDot - dblBetaDot * sin(dblPsi[ii]) ) / cos(dblPhi);
}
- double dblCurrentPosition_mm = llcomms.positionSensor_mm[channel];
- if(input.psi_mm[channel]<0 || dblCurrentPosition_mm<0) { // If requested position is negative or the sensor feedback is erroneous
- continue;
+ else{
+ dblXdot[ii] = ACT_CONV * K_theta * ( ( cos(dblPsi[ii]) + d_theta) * dblThetaDot - dblTheta * sin(dblPsi[ii]) * dblPhiDot);
+ }
+ }
+ }
+ else {
+ dblTheta = dblBeta / sin(dblPhi);
+ double dblThetaDot = dblBetaDot * sin(dblPhi) + dblBeta * dblPhiDot * cos(dblPhi);
+ dblThetaDot /= sin(dblPhi)*sin(dblPhi);
+ double dblPsi[3];
+ for (int ii =0; ii<3; ii++){
+ dblPsi[ii] = dblPhi - ii*2*PI/3;
+ if(dblAlpha == 0){
+ dblXdot[ii] = ACT_CONV * K_theta * ( cos(dblPsi[ii]) + d_theta);
+ dblXdot[ii] *= ( dblBetaDot - dblAlphaDot * sin(dblPsi[ii]) ) / sin(dblPhi);
}
- // Limit actuator position
- input.psi_mm[channel] = min( max( 0.0 , input.psi_mm[channel] ) , (double)MAX_ACTUATOR_LIMIT_MM );
- // Calculate actuator position change
- dblDistanceToTarget_mm[i] = fabs(input.psi_mm[channel] - dblCurrentPosition_mm);
- // Select the max absolute actuator position change
- if(dblDistanceToTarget_mm[i]>maxDistanceToTarget_mm) {
- maxDistanceToTarget_mm = dblDistanceToTarget_mm[i];
+ else{
+ dblXdot[ii] = ACT_CONV * K_theta * ( ( cos(dblPsi[ii]) + d_theta ) * dblThetaDot - dblTheta * sin(dblPsi[ii]) * dblPhiDot);
}
}
- // For max actuator position change, calculate the time to destination at the limited speed
- maxTimesToTarget_s[segNum] = fabs(maxDistanceToTarget_mm) / limitedSpeed_mmps;
- // For each actuator, replan target position and velocity as required
- for(short int i=0; i<3; i++) {
- short int channel = segNum*3+i;
- // If requested actuator position change is already within tolerance, do NOT replan that actuator
- if( dblDistanceToTarget_mm[i] <= 0.0 ) continue;
- // Calculate velocity for each motor to synchronise movements to complete in max time
- // Set dblDemandPosition_mm and dblDemandSpeed_mmps
- dblDemandPosition_mm[channel] = input.psi_mm[channel];
- dblDemandSpeed_mmps[channel] = dblDistanceToTarget_mm[i] / maxTimesToTarget_s[segNum];
+ }
+ //calculate new angles for next front segment position
+ dblAlpha += dblDeltaAlpha; // update new alpha postion
+ dblBeta += dblDeltaBeta; // update new beta position
+
+ dblAlpha = limDouble(dblAlpha, (double)-1.0*MAX_THETA_RAD, (double)MAX_THETA_RAD);
+ dblBeta = limDouble(dblBeta, (double)-1.0*MAX_THETA_RAD, (double)MAX_THETA_RAD);
+ dblPhi = atan2(dblBeta,dblAlpha); // update new phi position
+ if( fabs( cos(dblPhi) ) >= 0.7106781 ){
+ dblTheta = dblAlpha / cos(dblPhi);//calculate new theta value
+ }
+ else {
+ dblTheta = dblBeta / sin(dblPhi);
+ }
+ dblTheta = limDouble(dblTheta, 0.0, (double)MAX_THETA_RAD ); //limit angle
+ //update alpha and beta if limit has occured
+ dblAlpha = dblTheta *cos(dblPhi);
+ dblBeta = dblTheta *sin(dblPhi);
+
+ double dblPsi[3];
+ for (int ii = 0; ii <3; ii++) {//calculate new acuator positions
+ dblPsi[ii] = dblPhi - ii*2*PI/3;
+ dblX[ii] = ACT_CONV * K_theta * ( cos(dblPsi[ii]) + d_theta) * dblTheta;
+ //add offset
+ dblX[ii] += ACTUATOR_OFFSET;
+
+ //limit positions
+ dblX[ii] = limDouble( dblX[ii], 0.0, (double)MAX_ACTUATOR_LIMIT_MM );
+ }
+ //calculate new drive segment position
+ //read drive segment buttons
+ //double dblDriveStep = 0.4;
+
+ //printf("pin:%d\t", pinFwd.read());
+
+ if(pinFwd.read()){
+ if(!pinRev.read()){
+ dblSdot = SAFE_CONTRACT_SPEED;
+ } else{
+ dblSdot = 0.0;
}
} else {
- maxTimesToTarget_s[segNum] = -1.0;
+ if(pinRev.read()){
+ dblSdot = -1.0*SAFE_CONTRACT_SPEED;
+ } else{
+ dblSdot = 0.0;
+ }
}
+
+ dblS += dblSdot/HHC_READ_FREQ_HZ;
+ //limit extension (uses word position, but actually refers to pressure)
+ dblS = limDouble( dblS, 0.0, (double)MAX_EXTENSION_PRESSURE );
+
+// printf("S:%f\tSdot:%f\t", dblS, dblSdot);
+ //Send signals to actuators.
+ SetFrontDemand(dblX, dblXdot);//front segment
+ SetDriveDemand(dblS, dblSdot);//drive segment
+
+
}
- // Unlock mutex, allowing setDemandsForLL to run again
- mutPathIn.unlock();
-
- // SEND MESSAGE
- hlcomms.send_durations_message(maxTimesToTarget_s);
}
-
-}
-
-void startLLcomms() { // Send new demands to LL after receiving new target data
- semLLcomms.release(); // Uses threadSetDemands which is normal priority
}
-void setDemandsForLL() {
-
- while(1) {
- semLLcomms.wait();
- mutPathIn.lock(); // Lock relevant mutex
- for(short int i=0; i<N_CHANNELS; i++) { // For each LL
- llcomms.mutChannel[i].lock(); // MUTEX LOCK
- llcomms.demandPosition_mm[i] = dblDemandPosition_mm[i];
- llcomms.demandSpeed_mmps[i] = dblDemandSpeed_mmps[i];
- llcomms.mutChannel[i].unlock(); // MUTEX UNLOCK
- llcomms.isDataReady[i] = 1; // Signal that data ready
- } // end for
- mutPathIn.unlock(); // Unlock relevant mutex
- } // end while(1)
-
+void SetUp(){
+ for(int ii = 0; ii<N_CHANNELS; ii++){
+ pinPosOut[ii].write(0.0);
+ pinVelOut[ii].write(0.0);
+ }
}
int main() {
+ pinThirdPump = 1;
+ pinJetOut = 1;
+ pinWashOut = 1;
pc.baud(BAUD_RATE);
- //printf("ML engage. Compiled at %s\r\n.",__TIME__);
- wait(3);
+ for(int ii = 0; ii<N_CHANNELS; ii++){
+ pinPosOut[ii].period_ms(2.0);
+ pinVelOut[ii].period_ms(2.0);
+ }
+ wait(1.0);
+ printf("ML engage. Compiled at %s\r\n",__TIME__);
+
+
+ //set up support function interrupts
+ //Rising
- threadLowLevelSPI.start(callback(&llcomms.queue, &EventQueue::dispatch_forever)); // Start the event queue
- threadReceiveAndReplan.start(ReceiveAndReplan);// Start replanning thread
- threadSetDemands.start(setDemandsForLL); // Start planning thread
- threadSensorFeedback.start(sendSensorData); // Start sensor feedback thread
+ pinZeroIn.mode(PullNone);
+ pinCycleIn.mode(PullNone);
+ pinWashIn.mode(PullNone);
+ pinGasIn.mode(PullNone);
+ pinSucIn.mode(PullNone);
+ pinFwd.mode(PullNone);
+ pinRev.mode(PullNone);
+ pinFlushIn.mode(PullDown);
+ pinDebugIn.mode(PullDown);
+
+ pinZeroIn.rise(&ZeroActivate);
+ pinCycleIn.rise(&CycleActivate);
+ pinFlushIn.rise(&FlushActivate);
+ pinSucIn.rise(&SucActivate);
+ pinGasIn.rise(&GasActivate);
+ pinDebugIn.rise(&DebugActivate);
+ //falling
+ pinZeroIn.fall(&ZeroStop);
+ pinCycleIn.fall(&CycleStop);
+ pinFlushIn.fall(&FlushStop);
+ pinSucIn.fall(&SucStop);
+ pinGasIn.fall(&GasStop);
+ pinDebugIn.fall(&DebugStop);
+ threadReadHHC.start(ReadHHC);
- setDemandsTicker.attach(&startLLcomms, 1/(float)LL_DEMANDS_FREQ_HZ); // Set up LL comms thread to recur at fixed intervals
- Thread::wait(1);
+ tickerReadHHC.attach(&signalReadHHC, 1/(float)HHC_READ_FREQ_HZ); // set up
+
+
while(1) {
Thread::wait(osWaitForever);
}