void setup() { // put your setup code here, to run once: pinMode(pinHeater, OUTPUT); pinMode(pinThermistor, INPUT); digitalWrite(pinHeater, 0); Serial.begin(57600); Serial.setTimeout(250); // Set timeout to 250ms // Restore calibration if already set. thermCalibrated = true; if(EEPROM.read(thermStepSetAddr) == 0) { unsigned char setPoint[4]; for(int i = 0; i < 4; i++) setPoint[i] = EEPROM.read(thermStepAddr+i); thermStep = *((float*)setPoint); } else { thermCalibrated = false; } if(EEPROM.read(thermYIntSetAddr) == 0) { unsigned char setPoint[4]; for(int i = 0; i < 4; i++) setPoint[i] = EEPROM.read(thermYIntAddr+i); thermYInt = *((float*)setPoint); } else { thermCalibrated = false; } pid.SetOutputLimits(0.0f, 1.0f); pid.SetSampleTime(250); // 250ms compute period pid.SetMode(MANUAL); }
void PIDControl::optionsPID(int setTimePoint) { //tell the PID to range between 0 and the full window size myPID.SetOutputLimits(0, setTimePoint); //turn the PID on myPID.SetMode(AUTOMATIC); }
void onSetAngleOutputLimits() { Serial.println("Receiving Angle output limits command..."); float lMin, lMax; readLimitsArgs(&lMin, &lMax); anglePID.SetOutputLimits(lMin, lMax); cmdMessenger.sendCmd(kStatus, "Angle output limits set"); }
void motorsInit( int leftPin, int rightPin ) { servoLeft.attach(leftPin); servoRight.attach(rightPin); servoLeft.writeMicroseconds(servoSpeedLeft); servoRight.writeMicroseconds(servoSpeedRight); #ifdef USE_PID Input = 0; Setpoint = 0; turningPID.SetMode(AUTOMATIC); turningPID.SetOutputLimits(-SERVO_DRIVE_TURN_SPEED, SERVO_DRIVE_TURN_SPEED); #endif }
void setup() { pinMode(MOSFET_PIN, OUTPUT); pinMode(HEAT_ON_LED_PIN, OUTPUT); pid.SetOutputLimits(-PID_OUTPUT_RANGE, PID_OUTPUT_RANGE); pid_autotune.SetOutputStep(PID_OUTPUT_RANGE); pid_autotune.SetControlType(1); // PID control type. EEPROM.begin(EEPROM_TOTAL_BYTES); byte* p = (byte*)(void*)&settings; for (unsigned int i = 0; i < sizeof(settings); i++) { *p++ = EEPROM.read(EEPROM_SETTINGS_LOCATION + i); } update_pid_tunings(); handle_enabled(); }
void setup() { Wire.begin(myAddress); Wire.onReceive(i2cReceive); Wire.onRequest(i2cRequest); pinMode(limit_switch_pin, INPUT); mySerial.begin(9600); // Serial commuication to motor controller start. setpoint = 0.0; calibration(); // Running the calibration code on every start up input = encoderRead(); myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(-127, 127); myPID.SetSampleTime(20); }
/* Calcule les pwm a appliquer pour un asservissement en vitesse en trapeze * <> value_pwm_left : la pwm a appliquer sur la roue gauche [-255,255] * <> value_pwm_right : la pwm a appliquer sur la roue droite [-255,255] * */ void speedControl(int* value_pwm_left, int* value_pwm_right){ /* si le robot est en train de tourner, et qu'on lui donne une consigne de vitesse, il ne va pas partir droit * solution = decomposer l'asservissement en vitesse en 2 : * -> stopper le robot (les 2 vitesses = 0) * -> lancer l'asservissement en vitesse */ static int start_time; static bool initDone = false; if(!initDone){ start_time = 0; pwm = 0; currentSpeed = 0; consigne = 0; pid4SpeedControl.Reset(); pid4SpeedControl.SetInputLimits(-20000,20000); pid4SpeedControl.SetOutputLimits(-255,255); pid4SpeedControl.SetSampleTime(DUREE_CYCLE); pid4SpeedControl.SetMode(AUTO); initDone = true; } /* Gestion de l'arret d'urgence */ if(current_goal.isCanceled){ initDone = false; current_goal.isReached = true; current_goal.isCanceled = false; /* et juste pour etre sur */ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } /* Gestion de la pause */ if(current_goal.isPaused){ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } if(current_goal.phase == PHASE_1){ //phase d'acceleration consigne = current_goal.speed; currentSpeed = robot_state.speed; if(abs(consigne-currentSpeed) < 1000){ /*si l'erreur est inferieur a 1, on concidere la consigne atteinte*/ current_goal.phase = PHASE_2; start_time = millis(); } } else if(current_goal.phase == PHASE_2){ //phase de regime permanent consigne = current_goal.speed; currentSpeed = robot_state.speed; if(millis()-start_time > current_goal.period){ /* fin de regime permanent */ current_goal.phase = PHASE_3; } } else if(current_goal.phase == PHASE_3){ //phase de decceleration consigne = 0; currentSpeed = robot_state.speed; if(abs(robot_state.speed)<1000){ current_goal.phase = PHASE_4; } } pid4SpeedControl.Compute(); if(current_goal.phase == PHASE_4){ (*value_pwm_right) = 0; (*value_pwm_left) = 0; current_goal.isReached = true; initDone = false; }else{ (*value_pwm_right) = pwm; (*value_pwm_left) = pwm; } }
/* Calcule les pwm a appliquer pour un asservissement en position * <> value_pwm_left : la pwm a appliquer sur la roue gauche [-255,255] * <> value_pwm_right : la pwm a appliquer sur la roue droite [-255,255] * */ void positionControl(int* value_pwm_left, int* value_pwm_right){ static bool initDone = false; if(!initDone){ output4Delta = 0; output4Alpha = 0; currentDelta = .0; currentAlpha = .0; consigneDelta = .0; consigneAlpha = .0; pid4DeltaControl.Reset(); pid4DeltaControl.SetInputLimits(-TABLE_DISTANCE_MAX_MM/ENC_TICKS_TO_MM,TABLE_DISTANCE_MAX_MM/ENC_TICKS_TO_MM); pid4DeltaControl.SetSampleTime(DUREE_CYCLE); pid4DeltaControl.SetOutputLimits(-current_goal.speed,current_goal.speed); /*composante liee a la vitesse lineaire*/ pid4DeltaControl.SetMode(AUTO); pid4AlphaControl.Reset(); pid4AlphaControl.SetSampleTime(DUREE_CYCLE); pid4AlphaControl.SetInputLimits(-M_PI,M_PI); pid4AlphaControl.SetOutputLimits(-255,255); /*composante lie a la vitesse de rotation*/ pid4AlphaControl.SetMode(AUTO); initDone = true; } /* Gestion de l'arret d'urgence */ if(current_goal.isCanceled){ initDone = false; current_goal.isReached = true; current_goal.isCanceled = false; /* et juste pour etre sur */ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } /* Gestion de la pause */ if(current_goal.isPaused){ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } /*calcul de l'angle alpha a combler avant d'etre aligne avec le point cible * borne = [-PI PI] */ double angularCoeff = atan2(current_goal.y-robot_state.y,current_goal.x-robot_state.x); /*arctan(y/x) -> [-PI,PI]*/ currentAlpha = moduloPI(angularCoeff - robot_state.angle); /* il faut un modulo ici, c'est sur ! /* En fait, le sens est donne par l'ecart entre le coeff angulaire et l'angle courant du robot. * Si cet angle est inferieur a PI/2 en valeur absolue, le robot avance en marche avant (il avance quoi) * Si cet angle est superieur a PI/2 en valeur absolue, le robot recule en marche arriere (= il recule) */ int sens = 1; if(abs(currentAlpha) > M_PI/2){/* c'est a dire qu'on a meilleur temps de partir en marche arriere */ sens = -1; currentAlpha = moduloPI(M_PI + angularCoeff - robot_state.angle); } currentAlpha = -currentAlpha; double dx = current_goal.x-robot_state.x; double dy = current_goal.y-robot_state.y; currentDelta = -sens * sqrt(dx*dx+dy*dy); // - parce que l'ecart doit etre negatif pour partir en avant /* Serial.print("coeff:"); Serial.print(angularCoeff); Serial.print(" angle:"); Serial.print(robot_state.angle); Serial.print(" alpha:"); Serial.print(currentAlpha); Serial.print(" delta:"); Serial.print(currentDelta); Serial.print(" x:"); Serial.print(current_goal.x); Serial.print(" y:"); Serial.println(current_goal.y); */ /* on limite la vitesse lineaire quand on s'approche du but */ if (abs(currentDelta)<250){ pid4DeltaControl.SetOutputLimits(-min(50,current_goal.speed),min(50,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<500){ pid4DeltaControl.SetOutputLimits(-min(60,current_goal.speed),min(60,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<750){ pid4DeltaControl.SetOutputLimits(-min(80,current_goal.speed),min(80,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<1000){ pid4DeltaControl.SetOutputLimits(-min(100,current_goal.speed),min(100,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<1250){ pid4DeltaControl.SetOutputLimits(-min(150,current_goal.speed),min(150,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<1500){ pid4DeltaControl.SetOutputLimits(-min(200,current_goal.speed),min(200,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } if(abs(currentDelta) < 5*ENC_MM_TO_TICKS) /*si l'ecart n'est plus que de 6 mm, on considere la consigne comme atteinte*/ current_goal.phase = PHASE_2; else current_goal.phase = PHASE_1; pid4AlphaControl.Compute(); pid4DeltaControl.Compute(); if(current_goal.phase == PHASE_2){ (*value_pwm_right) = 0; (*value_pwm_left) = 0; } else{ double pwm4Delta = 0.0; //FIXME probleme de debordemment //alpha 200 delta 255 / delta+alpha = 455 / delta-alpha = 55 / => alpha 200 delta 55 //alpha 200 delta -255 / delta+alpha = -55 / delta-alpha = -455 / => alpha 200 delta -55 //alpha -200 delta 255 / delta+alpha = 55 / delta-alpha = 455 / => alpha -200 delta 55 //alpha -200 delta -255 / delta+alpha = -455 / delta-alpha = -55 / => alpha -200 delta -55 /* Correction by thomas if(output4Delta+output4Alpha>255 || output4Delta-output4Alpha>255) pwm4Delta = 255-output4Alpha; else if(output4Delta+output4Alpha<-255 || output4Delta-output4Alpha<-255) pwm4Delta = -255+output4Alpha; else pwm4Delta = output4Delta;*/ (*value_pwm_right) = output4Delta+output4Alpha; (*value_pwm_left) = output4Delta-output4Alpha; // Correction by thomas if ((*value_pwm_right) > 255) (*value_pwm_right) = 255; else if ((*value_pwm_right) < -255) (*value_pwm_right) = -255; if ((*value_pwm_left) > 255) (*value_pwm_left) = 255; else if ((*value_pwm_left) < -255) (*value_pwm_left) = -255; } if(current_goal.phase == PHASE_2){ if(current_goal.id != -1 && !current_goal.isMessageSent){ //le message d'arrivee n'a pas encore ete envoye a l'intelligence //envoi du message sendMessage(current_goal.id,2); current_goal.isMessageSent = true; } /*condition d'arret = si on a atteint le but et qu'un nouveau but attends dans la fifo*/ if(!fifoIsEmpty()){ //on passe a la tache suivante current_goal.isReached = true; initDone = false; } } }
/* Calcule les pwm a appliquer pour un asservissement en angle * <> value_pwm_left : la pwm a appliquer sur la roue gauche [-255,255] * <> value_pwm_right : la pwm a appliquer sur la roue droite [-255,255] * */ void angleControl(int* value_pwm_left, int* value_pwm_right){ static bool initDone = false; if(!initDone){ pwm = 0; currentEcart = .0; consigne = .0; pid4AngleControl.Reset(); pid4AngleControl.SetInputLimits(-M_PI,M_PI); pid4AngleControl.SetOutputLimits(-current_goal.speed,current_goal.speed); pid4AngleControl.SetSampleTime(DUREE_CYCLE); pid4AngleControl.SetMode(AUTO); initDone = true; } /* Gestion de l'arret d'urgence */ if(current_goal.isCanceled){ initDone = false; current_goal.isReached = true; current_goal.isCanceled = false; /* et juste pour etre sur */ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } /* Gestion de la pause */ if(current_goal.isPaused){ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } /*l'angle consigne doit etre comprise entre ]-PI, PI] En fait pour simplifier, l'entree du PID sera l'ecart entre le l'angle courant et l'angle cible (consigne - angle courant) la consigne (SetPoint) du PID sera 0 la sortie du PID sera le double pwm */ currentEcart = -moduloPI(current_goal.angle - robot_state.angle); /* Serial.print("goal: "); Serial.print(current_goal.angle); Serial.print(" current: "); Serial.print(robot_state.angle); Serial.print(" ecart: "); Serial.println(currentEcart); */ if(abs(currentEcart) < 3.0f*M_PI/360.0f) /*si l'erreur est inferieur a 3deg, on concidere la consigne atteinte*/ current_goal.phase = PHASE_2; else current_goal.phase = PHASE_1; pid4AngleControl.Compute(); if(current_goal.phase == PHASE_2){ (*value_pwm_right) = 0; (*value_pwm_left) = 0; } else{ (*value_pwm_right) = pwm; (*value_pwm_left) = -pwm; } if(current_goal.phase == PHASE_2){ if(current_goal.id != -1 && !current_goal.isMessageSent){ //le message d'arrivee n'a pas encore ete envoye a l'intelligence //envoi du message sendMessage(current_goal.id,2); current_goal.isMessageSent = true; } if(!fifoIsEmpty()){ //on passe a la tache suivante /*condition d'arret = si on a atteint le but et qu'un nouveau but attends dans la fifo*/ current_goal.isReached = true; initDone = false; } } }
/* Calcule les pwm a appliquer pour un asservissement en position * <> value_pwm_left : la pwm a appliquer sur la roue gauche [-255,255] * <> value_pwm_right : la pwm a appliquer sur la roue droite [-255,255] * */ void positionControl(int* value_pwm_left, int* value_pwm_right){ static bool initDone = false; if(!initDone){ output4Delta = 0; output4Alpha = 0; currentDelta = .0; currentAlpha = .0; consigneDelta = .0; consigneAlpha = .0; pid4DeltaControl.Reset(); pid4DeltaControl.SetInputLimits(-TABLE_DISTANCE_MAX_MM/ENC_TICKS_TO_MM,TABLE_DISTANCE_MAX_MM/ENC_TICKS_TO_MM); pid4DeltaControl.SetSampleTime(DUREE_CYCLE); pid4DeltaControl.SetOutputLimits(-current_goal.speed,current_goal.speed); /*composante liee a la vitesse lineaire*/ pid4DeltaControl.SetMode(AUTO); pid4AlphaControl.Reset(); pid4AlphaControl.SetSampleTime(DUREE_CYCLE); pid4AlphaControl.SetInputLimits(-M_PI,M_PI); pid4AlphaControl.SetOutputLimits(-255,255); /*composante lie a la vitesse de rotation*/ pid4AlphaControl.SetMode(AUTO); initDone = true; } /* Gestion de l'arret d'urgence */ if(current_goal.isCanceled){ initDone = false; current_goal.isReached = true; current_goal.isCanceled = false; /* et juste pour etre sur */ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } /* Gestion de la pause */ if(current_goal.isPaused){ (*value_pwm_right) = 0; (*value_pwm_left) = 0; return; } /*calcul de l'angle alpha a combler avant d'etre aligne avec le point cible * borne = [-PI PI] */ double angularCoeff = atan2(current_goal.y-robot_state.y,current_goal.x-robot_state.x); /*arctan(y/x) -> [-PI,PI]*/ currentAlpha = moduloPI(angularCoeff - robot_state.angle); /* il faut un modulo ici, c'est sur ! /* En fait, le sens est donne par l'ecart entre le coeff angulaire et l'angle courant du robot. * Si cet angle est inferieur a PI/2 en valeur absolue, le robot avance en marche avant (il avance quoi) * Si cet angle est superieur a PI/2 en valeur absolue, le robot recule en marche arriere (= il recule) */ int sens = 1; if(current_goal.phase != PHASE_1 and abs(currentAlpha) > M_PI/2){/* c'est a dire qu'on a meilleur temps de partir en marche arriere */ sens = -1; currentAlpha = moduloPI(M_PI + angularCoeff - robot_state.angle); } currentAlpha = -currentAlpha; double dx = current_goal.x-robot_state.x; double dy = current_goal.y-robot_state.y; currentDelta = -sens * sqrt(dx*dx+dy*dy); // - parce que l'ecart doit etre negatif pour partir en avant switch(current_goal.phase) { case PHASE_1: if(abs(currentDelta)<1500) /*si l'ecart n'est plus que de 6 mm, on considere la consigne comme atteinte*/ { current_goal.phase = PHASE_DECEL; } break; case PHASE_DECEL: if (fifoIsEmpty()) { /* on limite la vitesse lineaire quand on s'approche du but */ if (abs(currentDelta)<250){ pid4DeltaControl.SetOutputLimits(-min(50,current_goal.speed),min(50,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<500){ pid4DeltaControl.SetOutputLimits(-min(60,current_goal.speed),min(60,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<750){ pid4DeltaControl.SetOutputLimits(-min(80,current_goal.speed),min(80,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<1000){ pid4DeltaControl.SetOutputLimits(-min(100,current_goal.speed),min(100,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else if (abs(currentDelta)<1250){ pid4DeltaControl.SetOutputLimits(-min(150,current_goal.speed),min(150,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } else { pid4DeltaControl.SetOutputLimits(-min(200,current_goal.speed),min(200,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation } } if(abs(currentDelta) < 5*ENC_MM_TO_TICKS) /*si l'ecart n'est plus que de 6 mm, on considere la consigne comme atteinte*/ { //envoi du message sendMessage(current_goal.id,2); current_goal.isMessageSent = true; current_goal.phase = PHASE_ARRET; } break; case PHASE_ARRET: if (abs(currentDelta) > 5*ENC_MM_TO_TICKS) { current_goal.phase = PHASE_CORRECTION; } break; case PHASE_CORRECTION: pid4DeltaControl.SetOutputLimits(-min(50,current_goal.speed),min(50,current_goal.speed)); // composante liee a la vitesse lineaire pid4AlphaControl.SetOutputLimits(-150,150); // composante liee a la vitesse de rotation if (abs(currentDelta) < 5*ENC_MM_TO_TICKS) { current_goal.phase = PHASE_ARRET; } default: break; } if (!fifoIsEmpty() and (current_goal.phase == PHASE_ARRET or current_goal.phase == PHASE_CORRECTION)) { //on passe a la tache suivante si la fifo n'est pas vide current_goal.isReached = true; initDone = false; } pid4AlphaControl.Compute(); pid4DeltaControl.Compute(); if (current_goal.phase == PHASE_ARRET) { (*value_pwm_right) = 0; (*value_pwm_left) = 0; } else { (*value_pwm_right) = output4Delta+output4Alpha; (*value_pwm_left) = output4Delta-output4Alpha; // Débordement if ((*value_pwm_right) > 255) (*value_pwm_right) = 255; else if ((*value_pwm_right) < -255) (*value_pwm_right) = -255; if ((*value_pwm_left) > 255) (*value_pwm_left) = 255; else if ((*value_pwm_left) < -255) (*value_pwm_left) = -255; } }
void initIMU(void) { float selfTest9250[6]; /* Initialize motors */ Motor_Init(); trace_printf("Motor initialized.\n"); /* Initialize related variables */ GyroMeasError = _PI * (60.0f / 180.0f); // gyroscope measurement error in rads/s (start at 60 deg/s), then reduce after ~10 s to 3 beta = sqrt(3.0f / 4.0f) * GyroMeasError; // compute beta GyroMeasDrift = _PI * (1.0f / 180.0f); // gyroscope measurement drift in rad/s/s (start at 0.0 deg/s/s) zeta = sqrt(3.0f / 4.0f) * GyroMeasDrift; // compute zeta, the other free parameter in the Madgwick scheme usually set to a small or zero value /* Initialize balancing */ bal_pitch = 0; bal_roll = 0; bal_yaw = 0; /* Initialize PID */ pitchReg.SetMode(AUTOMATIC); pitchReg.SetOutputLimits(-PID_PITCH_INFLUENCE, PID_PITCH_INFLUENCE); rollReg.SetMode(AUTOMATIC); rollReg.SetOutputLimits(-PID_ROLL_INFLUENCE, PID_ROLL_INFLUENCE); yawReg.SetMode(AUTOMATIC); yawReg.SetOutputLimits(-PID_YAW_INFLUENCE, PID_YAW_INFLUENCE); trace_printf("PID initialized.\n"); /* Detect whether MPU9250 is online */ MPU9250_I2C_Init(); resetMPU9250(); if(MPU9250_I2C_ByteRead(MPU9250_ADDRESS, WHO_AM_I_MPU9250) != 0x71) { trace_printf("Could not find MPU9250!\n"); } trace_printf("MPU9250 is online.\n"); timer_sleep(100); /* MPU9250 self test and calibrate */ MPU9250SelfTest(selfTest9250); trace_printf("x-axis self test: acceleration trim within : %6f %% of factory value\n", selfTest9250[0]); trace_printf("y-axis self test: acceleration trim within : %f %% of factory value\n", selfTest9250[1]); trace_printf("z-axis self test: acceleration trim within : %f %% of factory value\n", selfTest9250[2]); trace_printf("x-axis self test: gyration trim within : %f %% of factory value\n", selfTest9250[3]); trace_printf("y-axis self test: gyration trim within : %f %% of factory value\n", selfTest9250[4]); trace_printf("z-axis self test: gyration trim within : %f %% of factory value\n", selfTest9250[5]); timer_sleep(100); calibrateMPU9250(gyroBias, accelBias); // Calibrate gyro and accelerometers, load biases in bias registers trace_printf("x gyro bias = %f\n", gyroBias[0]); trace_printf("y gyro bias = %f\n", gyroBias[1]); trace_printf("z gyro bias = %f\n", gyroBias[2]); trace_printf("x accel bias = %f\n", accelBias[0]); trace_printf("y accel bias = %f\n", accelBias[1]); trace_printf("z accel bias = %f\n", accelBias[2]); timer_sleep(100); /* Initialize MPU9250 and AK8963 */ initMPU9250(); trace_printf("MPU9250 initialized for active data mode....\n"); // Initialize device for active mode read of acclerometer, gyroscope, and temperature timer_sleep(500); initAK8963(magCalibration); trace_printf("AK8963 initialized for active data mode....\n"); // Initialize device for active mode read of magnetometer trace_printf("Accelerometer full-scale range = %f g\n", 2.0f*(float)(1<<Ascale)); trace_printf("Gyroscope full-scale range = %f deg/s\n", 250.0f*(float)(1<<Gscale)); if(Mscale == 0) trace_printf("Magnetometer resolution = 14 bits\n"); if(Mscale == 1) trace_printf("Magnetometer resolution = 16 bits\n"); if(Mmode == 2) trace_printf("Magnetometer ODR = 8 Hz\n"); if(Mmode == 6) trace_printf("Magnetometer ODR = 100 Hz\n"); timer_sleep(100); getAres(); // Get accelerometer sensitivity getGres(); // Get gyro sensitivity getMres(); // Get magnetometer sensitivity trace_printf("Accelerometer sensitivity is %f LSB/g \n", 1.0f/aRes); trace_printf("Gyroscope sensitivity is %f LSB/deg/s \n", 1.0f/gRes); trace_printf("Magnetometer sensitivity is %f LSB/G \n", 1.0f/mRes); magbias[0] = +470.; // User environmental x-axis correction in milliGauss, should be automatically calculated magbias[1] = +120.; // User environmental x-axis correction in milliGauss magbias[2] = +125.; // User environmental x-axis correction in milliGauss }
int main(int argc, char **argv) { START_EASYLOGGINGPP(argc, argv); // Load configuration from file el::Configurations conf("/home/debian/hackerboat/embedded_software/unified/setup/log.conf"); // Actually reconfigure all loggers instead el::Loggers::reconfigureAllLoggers(conf); BoatState *me = new BoatState(); me->rudder = new Servo(); me->throttle = new Throttle(); me->orient = new OrientationInput(SensorOrientation::SENSOR_AXIS_Z_UP); double targetHeading = 0; double in = 0, out = 0, setpoint = 0; Pin enable(Conf::get()->servoEnbPort(), Conf::get()->servoEnbPin(), true, true); PID *helm = new PID(&in, &out, &setpoint, 0, 0, 0, 0); helm->SetMode(AUTOMATIC); helm->SetControllerDirection(Conf::get()->rudderDir()); helm->SetSampleTime(Conf::get()->rudderPeriod()); helm->SetOutputLimits(Conf::get()->rudderMin(), Conf::get()->rudderMax()); helm->SetTunings(10,0,0); if (!me->rudder->attach(Conf::get()->rudderPort(), Conf::get()->rudderPin())) { std::cout << "Rudder failed to attach 1" << std::endl; return -1; } if (!me->rudder->isAttached()) { std::cout << "Rudder failed to attach 2" << std::endl; return -1; } if (me->orient->begin() && me->orient->isValid()) { cout << "Initialization successful" << endl; cout << "Oriented with Z axis up" << endl; } else { cout << "Initialization failed; exiting" << endl; return -1; } for (int i = 0; i < 100; i++) { double currentheading = me->orient->getOrientation()->makeTrue().heading; if (isfinite(currentheading)) targetHeading += currentheading; cout << "."; std::this_thread::sleep_for(100ms); } cout << endl; targetHeading = targetHeading/100; cout << "Target heading is " << to_string(targetHeading) << " degrees true " << endl; int count = 0; for (;;) { in = me->orient->getOrientation()->makeTrue().headingError(targetHeading); count++; LOG_EVERY_N(10, DEBUG) << "True Heading: " << me->orient->getOrientation()->makeTrue() << ", Target Course: " << targetHeading; helm->Compute(); me->rudder->write(out); LOG_EVERY_N(10, DEBUG) << "Rudder command: " << to_string(out); std::this_thread::sleep_for(100ms); if (count > 9) { count = 0; cout << "True Heading: " << me->orient->getOrientation()->makeTrue().heading << "\tTarget Course: " << targetHeading << "\tRudder command: " << to_string(out) << endl; } } return 0; }
virtual void run() { int16_t accData[3]; int16_t gyrData[3]; CTimer tm(TIMER0); tm.second(DT); tm.enable(); myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(-100.0, 100.0); myPID.SetSampleTime(PID_SAMPLE_RATE); m_roll = 0.0f; m_pitch = 0.0f; double output; #if USE_AUTO_TUNING double sp_input, sp_output, sp_setpoint, lastRoll; PID speedPID(&sp_input, &sp_output, &sp_setpoint, 35, 1, 2, DIRECT); speedPID.SetMode(AUTOMATIC); speedPID.SetOutputLimits(-config.roll_offset, config.roll_offset); speedPID.SetSampleTime(PID_SAMPLE_RATE); sp_input = 0; sp_setpoint = 0; lastRoll = 0; #endif // // loop // while (isAlive()) { // // wait timer interrupt (DT) // if (tm.wait()) { // // read sensors // m_mxMPU.lock(); m_mpu->getMotion6(&accData[0], &accData[1], &accData[2], &gyrData[0], &gyrData[1], &gyrData[2]); m_mxMPU.unlock(); // // filter // ComplementaryFilter(accData, gyrData, &m_pitch, &m_roll); #if USE_AUTO_TUNING sp_input = (lastRoll - m_roll) / PID_SAMPLE_RATE; // roll speed lastRoll = m_roll; speedPID.Compute(); m_setpoint = -sp_output; // tune output angle #else m_roll -= config.roll_offset; #endif m_input = m_roll; myPID.Compute(); if ( m_output > config.skip_interval ) { LEDs[1] = LED_ON; LEDs[2] = LED_OFF; output = map(m_output, config.skip_interval, 100, config.pwm_min, config.pwm_max); m_left->direct(DIR_FORWARD); m_right->direct(DIR_FORWARD); } else if ( m_output<-config.skip_interval ) { LEDs[1] = LED_OFF; LEDs[2] = LED_ON; output = map(m_output, -config.skip_interval, -100, config.pwm_min, config.pwm_max); m_left->direct(DIR_REVERSE); m_right->direct(DIR_REVERSE); } else { LEDs[1] = LED_OFF; LEDs[2] = LED_OFF; output = 0; m_left->direct(DIR_STOP); m_right->direct(DIR_STOP); } // // auto power off when fell. // if ( abs(m_roll)>65 ) { output = 0; } // // output // m_left->dutyCycle(output * config.left_power); m_right->dutyCycle(output * config.right_power); } }