Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not getting default SampleTime after multiple compilations #3

Open
paynterf opened this issue Jun 9, 2021 · 2 comments
Open

Not getting default SampleTime after multiple compilations #3

paynterf opened this issue Jun 9, 2021 · 2 comments

Comments

@paynterf
Copy link

paynterf commented Jun 9, 2021

I'm using PID_v2 in an Arduino application, and I get the following output:

MPU6050 connection successful
Initializing DMP...
Enabling DMP...
DMP ready! Waiting for MPU6050 drift rate to settle...
MPU6050 Ready at 0.52 Sec
TurnRatePID started with Kp/Ki/Kd = 5.0,0.8,3.0, kp/ki/kd =  = 5.00,0.080,30.00, SampleTime = 30
End of test - Stopping!

From this code:

//05/31/21 latest & greatest PID values
double TurnRate_Kp = 5.0;
double TurnRate_Ki = 0.8;
double TurnRate_Kd = 3;
double TurnRatePIDSetPointDPS, TurnRatePIDOutput;
double TurnRatePIDInput = 15.f;
PID TurnRatePID(&TurnRatePIDInput, &TurnRatePIDOutput, &TurnRatePIDSetPointDPS, TurnRate_Kp, TurnRate_Ki, TurnRate_Kd, DIRECT);

void setup()
{
	Serial.begin(115200);

#pragma region MPU6050
	mySerial.printf("\nChecking for MPU6050 IMU at I2C Addr 0x%x\n", MPU6050_I2C_ADDR);
	mpu.initialize();

	// verify connection
	Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

	float StartSec = 0; //used to time MPU6050 init
	Serial.println(F("Initializing DMP..."));
	devStatus = mpu.dmpInitialize();

	// make sure it worked (returns 0 if successful)
	if (devStatus == 0)
	{
		// turn on the DMP, now that it's ready
		Serial.println(F("Enabling DMP..."));
		mpu.setDMPEnabled(true);

		// set our DMP Ready flag so the main loop() function knows it's okay to use it
		Serial.println(F("DMP ready! Waiting for MPU6050 drift rate to settle..."));
		dmpReady = true;

		// get expected DMP packet size for later comparison
		packetSize = mpu.dmpGetFIFOPacketSize();
		bMPU6050Ready = true;
		StartSec = millis() / 1000.f;
		mySerial.printf("MPU6050 Ready at %2.2f Sec\n", StartSec);
	}
	else
	{
		// ERROR!
		// 1 = initial memory load failed
		// 2 = DMP configuration updates failed
		// (if it's going to break, usually the code will be 1)
		Serial.print(F("DMP Initialization failed (code "));
		Serial.print(devStatus);
		Serial.println(F(")"));

		bMPU6050Ready = false;
	}
#pragma endregion MPU6050

	mySerial.printf("TurnRatePID started with Kp/Ki/Kd = %2.1f,%2.1f,%,%2.1f, kp/ki/kd =  = %2.2f,%2.3f,%,%2.2f, SampleTime = %d\n",
		TurnRatePID.GetKp(), TurnRatePID.GetKi(), TurnRatePID.GetKd(), TurnRatePID.Getkp(), TurnRatePID.Getki(), TurnRatePID.Getkd(), TURN_RATE_UPDATE_INTERVAL_MSEC);

#pragma region TIMER_INTERRUPT
	//09/18/20 can't use Timer1 cuz doing so conflicts with PWM on pins 10-12
	cli();//stop interrupts
	TCCR5A = 0;// set entire TCCR5A register to 0
	TCCR5B = 0;// same for TCCR5B
	TCNT5 = 0;//initialize counter value to 0

	// set compare match register for 5hz increments
	//10/11/20 chg timer interval to 10Hz vs 5
	//OCR5A = 3124;// = (16*10^6) / (5*1024) - 1 (must be <65536)
	OCR5A = 1562;// = (16*10^6) / (10*1024) - 1 (must be <65536)
	TCCR5B |= (1 << WGM52);// turn on CTC mode
	TCCR5B |= (1 << CS52) | (1 << CS50);// Set CS10 and CS12 bits for 1024 prescaler
	TIMSK5 |= (1 << OCIE5A);// enable timer compare interrupt
	sei();//allow interrupts
	pinMode(TIMER_INT_OUTPUT_PIN, OUTPUT);
#pragma endregion TIMER_INTERRUPT


	mySerial.printf("End of test - Stopping!\n");
	while (true)
	{
		CheckForUserInput();
	}
}

I expected the SampleTime to be 100 after the default PID constructor, but it isn't - it's still the same value I set later in the code. I have tried a full 'Clean' build, but get the same (unexpected) result.

What gives?

Frank

@paynterf
Copy link
Author

paynterf commented Jun 9, 2021

Made another run trying to figure this out. I instrumented PID_v2.cpp to report the actual value of the private SampleTime member as follows:

/* SetSampleTime(...) *********************************************************
 * sets the period, in Milliseconds, at which the calculation is performed
 ******************************************************************************/
void PID::SetSampleTime(int NewSampleTime) {
  if (NewSampleTime > 0) {
    PIDSerial.printf("In SetSampleTime, SampleTime now %2.1f, Changing to %2.1f\n",
      (double)NewSampleTime, (double)SampleTime);
    double ratio = (double)NewSampleTime / (double)SampleTime;
    ki *= ratio;
    kd /= ratio;
    SampleTime = (unsigned long)NewSampleTime;
  }
}

using this Arduino code:

void setup()
{
	Serial.begin(115200);

#pragma region MPU6050
	mySerial.printf("\nChecking for MPU6050 IMU at I2C Addr 0x%x\n", MPU6050_I2C_ADDR);
	mpu.initialize();

	// verify connection
	Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

	float StartSec = 0; //used to time MPU6050 init
	Serial.println(F("Initializing DMP..."));
	devStatus = mpu.dmpInitialize();

	// make sure it worked (returns 0 if successful)
	if (devStatus == 0)
	{
		// turn on the DMP, now that it's ready
		Serial.println(F("Enabling DMP..."));
		mpu.setDMPEnabled(true);

		// set our DMP Ready flag so the main loop() function knows it's okay to use it
		Serial.println(F("DMP ready! Waiting for MPU6050 drift rate to settle..."));
		dmpReady = true;

		// get expected DMP packet size for later comparison
		packetSize = mpu.dmpGetFIFOPacketSize();
		bMPU6050Ready = true;
		StartSec = millis() / 1000.f;
		mySerial.printf("MPU6050 Ready at %2.2f Sec\n", StartSec);
	}
	else
	{
		// ERROR!
		// 1 = initial memory load failed
		// 2 = DMP configuration updates failed
		// (if it's going to break, usually the code will be 1)
		Serial.print(F("DMP Initialization failed (code "));
		Serial.print(devStatus);
		Serial.println(F(")"));

		bMPU6050Ready = false;
	}
#pragma endregion MPU6050

	TurnRatePID.SetSampleTime(100);
	mySerial.printf("TurnRatePID started with Kp/Ki/Kd = %2.1f,%2.1f,%2.1f, kp/ki/kd =  = %2.2f,%2.3f,%2.2f, SampleTime = %lu\n",
		TurnRatePID.GetKp(), TurnRatePID.GetKi(), TurnRatePID.GetKd(), TurnRatePID.Getkp(), TurnRatePID.Getki(), TurnRatePID.Getkd(), TurnRatePID.GetSampleTime());

And I got this output:

I received: 63
ENTERING COMMAND MODE:
0 = 180 deg CCW Turn
1 = 180 deg CW Turn
A = Back to Auto Mode
S = Stop
F = Forward
R = Reverse

       Faster
	8
Left 4	5  6 Right
	2
       Slower
Got D
Got A
Got 31
CW 180 deg Turn
In SpinTurn(CW, 180.00, 45.00)
TurnRatePID started with Kp/Ki/Kd = 5.0,0.8,3.0, kp/ki/kd =  = 5.00,0.080,30.00, SampleTime = 30
Init hdg = 142.35 deg, Turn = 180.00  deg, tgt = -37.65 deg, timeout = 8.00 sec
TurnRatePID started with Kp/Ki/Kd = 5.0,0.8,3.0, kp/ki/kd =  = 5.00,0.080,30.00, SampleTime = 30
In SetSampleTime, SampleTime now 30.0, Changing to 100.0
TurnRatePID started with Kp/Ki/Kd = 5.0,0.8,3.0, kp/ki/kd =  = 5.00,0.024,100.00, SampleTime = 30

Looking at the output, it seems clear from the value of private member variable kd (I added access functions), it is getting scaled initially as if the SampleTime is the correct (100 mSec) value, even though the reported value is 30, not 100. However, after SetSampleTime() executes, it appears that the internal kd value gets divided by 0.1 (i.e. SampleTimeInSec) again - and this is very unexpected behavior. In addition, I cannot for the life of me figure out how the internal private member can be one number, but the retrieved value is something else.

TIA,

Frank

@imax9000
Copy link
Owner

Yeah, it's definitely weird. However I've noticed that in your initial post you're printing out TURN_RATE_UPDATE_INTERVAL_MSEC as SampleTime.

In the followup though you're using controller's method GetSampleTime() which is not present in the committed version of the library, so it's hard to say exactly what's going on, sorry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants