ZHomeSlice / Simple_MPU6050

Going Live
MIT License
88 stars 24 forks source link

MPU6050 still gets stuck! #23

Closed anmol1980 closed 2 years ago

anmol1980 commented 2 years ago

Hi Z,

I used your library for implementing a PID loop based on MPU6050 readings. The code works for the most part. However, sometimes it gets frozen. I am using your library that I downloaded on Dec 20, 2021.

I am attaching my arduino code as well. Any help will be appreciated. I have been working on this problem for quite some time.

MPU6050_PID.ino.txt

Thanks

anmol1980 commented 2 years ago

There are 2 kind of problems I observe

1) Sometimes, the program just gets locked ie. the blinking stops and the servo doesn't move. I cannot read angles from mpu6050 anymore.

2) Another problem is that at times the 0 pitch angle is not horizontal anymore. My guess is that setWireTimeout is working in these cases, but somehow the 0 pitch angle changes.

I am using GIY-521 from amazon.

ZHomeSlice commented 2 years ago

@anmol1980 That's Excellent, I'm glad my library is helping you I defiantly would get the latest version I have just fixed a little glitch that could help.

I try to avoid using String data type example String strtokIndx; Strings and Arduino UNOs don't get along well.

The PID loop that everyone uses has a fatal flaw unless you are using it with temperature The integral and derivative calculations are incorrect when you can't put the PID loop in the loop() function. and still there are other issues.

Use my PID instead. It uses exact timing rather than a fixed interval. and it also resets the integral to eliminate windup at the start. Arduino_PID_Library_v3 it is a 1-1 swap just change your include to #include "PID_v3.h"

Proof of My PID in action.Balancing Bot hops off curb!!!

Also my tuning video for balancing (Speed Control and Temperature control use a different tuning method) How to Balance Robot PID tutorial in under 2 minutes!

"0 pitch angle is not horizontal anymore" could be because of temperature messing with the calibration. you can trigger a calibration at any time with the MPU6050 level and motionless.

mpu.CalibrateMPU(); as the last line of your setup(); function

check to be sure your defaults are accurate:

define OFFSETS 456, 733, 679, 151 , -40, -19

Z

anmol1980 commented 2 years ago

Dear Z,

Thanks for your email. I almost want to give up on MPU6050. If you have an alternative that is immune to noise (may be with SPI), please let me know.

Coming back to MPU6050, I have a few questions for you.

1) I ran into a compilation error when I added PID_v3.h to my arduino code. The error is "DPRINTSTIMER' was not declared in this scope"

2) I only get problems when I am running motors (servo) using signal from MPU6050. I cannot calibrate on the fly. My offsets are accurate and works for some time, but the code then seems to tilt the axis of reference. You mentioned something about temperature that I didn’t understand. Could you please tell me more.

3) Can you suggest an alternative to replace Strings in my code? I am not very good in programming.

Million thanks for your help, Anmol

Arduino: 1.8.19 (Linux), Board: "Arduino Uno"

In file included from /tmp/arduino_modified_sketch_110082/Simple_MPU6050_Example.ino:28:0: /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:47:8: warning: extra qualification 'PID::' on member 'BalanceBotDrive' [-fpermissive] PID & PID::BalanceBotDrive(float TurnOffset); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:99:4: warning: extra qualification 'PID::' on member 'map_Generic' [-fpermissive] X PID::map_Generic(X x, M in_min, N in_max, O out_min, Q out_max); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:93:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:94:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:95:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardB_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:96:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseB_CB = nothing; ^~~ In file included from /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:14:0: /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:47:8: warning: extra qualification 'PID::' on member 'BalanceBotDrive' [-fpermissive] PID & PID::BalanceBotDrive(float TurnOffset); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:99:4: warning: extra qualification 'PID::' on member 'map_Generic' [-fpermissive] X PID::map_Generic(X x, M in_min, N in_max, O out_min, Q out_max); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:93:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:94:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:95:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardB_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:96:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseB_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::Compute()': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:111:2: error: 'DPRINTSTIMER' was not declared in this scope DPRINTSTIMER(100){ ^~~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::BalanceBotDrive(float)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:155:2: error: 'DPRINTSTIMER' was not declared in this scope DPRINTSTIMER(100){ ^~~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetTunings(double, double, double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:244:28: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Kp<0 || Ki<0 || Kd<0) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetKp(double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:251:13: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Kp<0 ) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetKi(double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:256:13: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Ki<0 ) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetKd(double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:261:13: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Kd<0 ) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetOutputLimits(double, double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:287:17: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if(Min >= Max) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'void PID::Initialize()': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:320:10: warning: return-statement with a value, in function returning 'void' [-fpermissive] return *this; // return Pointer to this class ^~~~ Multiple libraries were found for "Simple_MPU6050.h" Used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050 Not used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050_archive Not used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050_archive2 Not used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050_2021 Multiple libraries were found for "Wire.h" Used: /home/pi/arduino-1.8.19/hardware/arduino/avr/libraries/Wire Not used: /home/pi/arduino-1.8.19/libraries/Wire_archive exit status 1 Error compiling for board Arduino Uno.

This report would have more information with "Show verbose output during compilation" option enabled in File -> Preferences.

On Mar 15, 2022, at 12:17 AM, Homer Creutz @.***> wrote:

@anmol1980 https://github.com/anmol1980 That's Excellent, I'm glad my library is helping you I defiantly would get the latest version I have just fixed a little glitch that could help.

I try to avoid using String data type example String strtokIndx; Strings and Arduino UNOs don't get along well.

The PID loop that everyone uses has a fatal flaw unless you are using it with temperature The integral and derivative calculations are incorrect when you can't put the PID loop in the loop() function. and still there are other issues.

Use my PID instead. It uses exact timing rather than a fixed interval. and it also resets the integral to eliminate windup at the start. Arduino_PID_Library_v3 https://github.com/ZHomeSlice/Arduino_PID_Library_v3 it is a 1-1 swap just change your include to #include "PID_v3.h"

Proof of My PID in action.Balancing Bot hops off curb!!! https://youtu.be/JI7Pp7kWgmg Also my tuning video for balancing (Speed Control and Temperature control use a different tuning method) How to Balance Robot PID tutorial in under 2 minutes! https://youtu.be/uyHdyF0_BFo "0 pitch angle is not horizontal anymore" could be because of temperature messing with the calibration. you can trigger a calibration at any time with the MPU6050 level and motionless.

mpu.CalibrateMPU(); as the last line of your setup(); function

check to be sure your defaults are accurate:

define OFFSETS 456, 733, 679, 151 , -40, -19

Z

— Reply to this email directly, view it on GitHub https://github.com/ZHomeSlice/Simple_MPU6050/issues/23#issuecomment-1067546691, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEY2QC54TVVK7SCMEUQCIK3VAAFLZANCNFSM5QXL4VNA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.

ZHomeSlice commented 2 years ago

@anmol1980 "DPRINTSTIMER" I'll get this added It is a macro that I created to do a blink without delay #define DPRINTSTIMER(t) for (static uint32_t SpamTimer; (uint32_t)(millis() - SpamTimer) >= (t); SpamTimer = millis()) // (BLACK BOX) Ya, don't complain that I used "for(;;){}" instead of "if(){}" for my Blink Without Delay Timer macro. It works nicely!!!

I have the checking for "fpermissive" errors mute... but let's see if we can fix these now.

Just went through the code with your list and updated the master on Github :)

That should be the fix. Z

ZHomeSlice commented 2 years ago

@anmol1980 I need additional information on : " I only get problems when I am running motors (servo) using signal from MPU6050." The ServoBot library is likely the cause. so many programs are what we call blocking code and servo code is likely causing the problem when the servo takes over it can stop all other code including i2c communications thus corrupting the data. cab you get me the link to the file?

what does the servo do? for example, does it always stay vertical even with the base moving like a camera stabilizer?

Suggestion 1: Move myPID.Compute(); into the PrintValues function. The reason: you will only need to update your PID when you have new data to use. Proportional will not change The Integral Value will duplicate the error over and over again causing windup The derivative Value will work the first time then return to zero because nothing changed between the remaining checks. Output = P + I + D

Suggestion 2: increase your rate of data from the MPU6050 to 100hz mpu.Set_DMP_Output_Rate_Hz(100);

Suggestion 3: Note that a typical servo motor expects to be updated every 20 ms with a pulse between 1 ms and 2 ms Setting your MPU6050 to 10ms delay between readings meets the 20ms update time then you can pulse the servo with a pulse between 1ms and 2ms to set the position. With a 1.5 ms pulse, the servo motor will be at the natural 90° position. Example Code

// Callback function that only runs when data is captured from the MPU6050
int PrintValues(int32_t *quat,float *yawpitchroll, uint16_t SpamDelay = delayInterval) {
  Quaternion q;
  VectorFloat gravity;
  //float ypr[3] = { 0, 0, 0 };
  float xyz[3] = { 0, 0, 0 };
  spamtimer(SpamDelay) {// non blocking delay before printing again. This skips the following code when delay time (ms) hasn't been met
    mpu.GetQuaternion(&q, quat);
    mpu.GetGravity(&gravity, &q);
    mpu.GetYawPitchRoll(xyz, &q, &gravity);
    mpu.ConvertToDegrees(xyz,yawpitchroll);

Input = ypr[1]; // load the PID input
myPID.Compute(); // only ran once per MPU6050 update

// Becuse we don't need to get data from anything at this time letd hard code the servo  and send it a pulse
digitalWrite(Servo_Pin, HIGH);
micros(1000)
// 0 = 0° and 1000 = 180° 
micros(min(0, max(1000, Output));
digitalWrite(Servo_Pin, LOW);

The above code has a lot of assumptions surrounding its use. Z

anmol1980 commented 2 years ago

Hi Z,

1) The application is similar to camera stabilization mechanism. I have taken many steps to prevent MPU6050 noise. I have implemented by pass caps in servos, caps in power supply, pull up resistors at MPU6050, using cat 6 shielded cable, and even lowered I2C frequency. Because the program always works when the servo isn’t moving, I felt the mpu6050 freezing problem had to be related to the servo noise I may have despite my best efforts.

2) ServoBot is a simple library for managing servos. I am not sure why I wrote it. I will use your suggestions. The ServoBot library is attached

3) I have another question. What is the relationship between spamdelay of 100 ms and mpu.Set_DMP_Output_Rate_Hz(100). Shouldn’t they have identical time period. If I have 100 Hz, shouldn’t I be using 10 ms as spamdelay. I cannot understand this part of code.

I will take some time to implement your suggestions and get back in a day or two.

Thanks, anmol1980

On Mar 16, 2022, at 12:59 PM, Homer Creutz @.***> wrote:

@anmol1980 https://github.com/anmol1980 I need additional information on : " I only get problems when I am running motors (servo) using signal from MPU6050." The ServoBot library is likely the cause. so many programs are what we call blocking code and servo code is likely causing the problem when the servo takes over it can stop all other code including i2c communications thus corrupting the data. cab you get me the link to the file?

what does the servo do? for example, does it always stay vertical even with the base moving like a camera stabilizer?

Suggestion 1: Move myPID.Compute(); into the PrintValues function. The reason: you will only need to update your PID when you have new data to use. Proportional will not change The Integral Value will duplicate the error over and over again causing windup The derivative Value will work the first time then return to zero because nothing changed between the remaining checks. Output = P + I + D

Suggestion 2: increase your rate of data from the MPU6050 to 100hz mpu.Set_DMP_Output_Rate_Hz(100);

Suggestion 3: Note that a typical servo motor expects to be updated every 20 ms with a pulse between 1 ms and 2 ms Setting your MPU6050 to 10ms delay between readings meets the 20ms update time then you can pulse the servo with a pulse between 1ms and 2ms to set the position. With a 1.5 ms pulse, the servo motor will be at the natural 90° position. Example Code

// Callback function that only runs when data is captured from the MPU6050 int PrintValues(int32_t quat,float yawpitchroll, uint16_t SpamDelay = delayInterval) { Quaternion q; VectorFloat gravity; //float ypr[3] = { 0, 0, 0 }; float xyz[3] = { 0, 0, 0 }; spamtimer(SpamDelay) {// non blocking delay before printing again. This skips the following code when delay time (ms) hasn't been met mpu.GetQuaternion(&q, quat); mpu.GetGravity(&gravity, &q); mpu.GetYawPitchRoll(xyz, &q, &gravity); mpu.ConvertToDegrees(xyz,yawpitchroll);

Input = ypr[1]; // load the PID input myPID.Compute(); // only ran once per MPU6050 update

// Becuse we don't need to get data from anything at this time letd hard code the servo and send it a pulse digitalWrite(Servo_Pin, HIGH); micros(1000) // 0 = 0° and 1000 = 180° micros(min(0, max(1000, Output)); digitalWrite(Servo_Pin, LOW); The above code has a lot of assumptions surrounding its use. Z

— Reply to this email directly, view it on GitHub https://github.com/ZHomeSlice/Simple_MPU6050/issues/23#issuecomment-1069354901, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEY2QC6PZEX2BWJMPKTHD3LVAIHOJANCNFSM5QXL4VNA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.

ZHomeSlice commented 2 years ago

@anmol1980

3) I have another question. What is the relationship between spamdelay of 100 ms and mpu.Set_DMP_Output_Rate_Hz(100). Shouldn’t they have identical time period. If I have 100 Hz, shouldn’t I be using 10 ms as spamdelay. I cannot understand this part of code.

answer: spamdelay() is for printing to the serial port. spamming the serial port with that much text every 10ms will more than likely cause a crash. If it doesn't cause a crash it could cause other blocking delays. Serial communication is time-consuming and too much can rob other processes like i2c and PID calculations from performing correctly. You can run the PID loop every 10ms and print the current orientation to the serial output every 100ms and you will never know the difference visually.

to avoid using the dreaded delay(); you should always use:

The "official" way to wright a blink without delay timer:

  static unsigned long SpamTimer;
  if ((millis() - SpamTimer) >= (100)) {
    SpamTimer= millis();
// Place your delayed code here
    Serial.println("not Spam");
  }

My Macro which is another way it is confusing not so kosher way of coding this but it is on a single line of code :) #define spamtimer(t) for (static uint32_t SpamTimer; (uint32_t)(millis() - SpamTimer) >= (t); SpamTimer = millis())

Usage:

spamtimer(100){
// Place your delayed code here
   Serial.println("not Spam");
}

Or you could writhe it outside of the macro as

for (static uint32_t SpamTimer; (uint32_t)(millis() - SpamTimer) >= (100); SpamTimer = millis()){
// Place your delayed code here
   Serial.println("not Spam");
}

Another thing to consider Use the MPU's Interrupt pin to trigger the reading to get the most accurate calculation Change mpu.dmp_read_fifo();// Must be in loop to mpu.dmp_read_fifo(1);// Must be in loop and connect the interrupt pin to pin 2 on your arduino.


I'm Assuming you will be maintaining a specific orientation You will want your setpoint to be zero with a fixed offset added to your input to correct for physical error example

Setpoint = 0;
Input = ypr[1]+AdjustmentError; //The adjustment error is for when your platform isn't flat but your MPU thinks it's at zero.

I am assuming at the starting position you will want your servo to be at 90° or 50% actuated. have your output range from -500 to +500 (1000ms) just add 500 to the output before using the delayMicroseconds() function delayMicroseconds(min(1000,max(0,Output +500); When resetting the PID integral windup the default servo position will be at 90°


Note: My PID_v3 is based on 1 second. At 10ms readings the Error for Integral and Derivative is divided by 100 then calculated. This is done with more precision and it actually uses the exact time between readings (This is the main difference between PID_v1 that everybody else uses) but in a nutshell, it uses a portion of the error to allow it to accumulate over a 1 second period of time. this allows Ki and Kd will stay consistent even with different reading durations. Proportional is not influenced by time.

Integral will wind up if the Servo can't reach the setpoint. so be sure to stop the PID loop if this occurs

You will likely want to have a slower (smaller) integral multiplier until you are close to level then tighten it up to stay level.

Start with integral increasing it until It ocellated just a little but flattens out. Proportional and derivative are both Zeroes An Integral of 1 is equal to adding the "error" from the setpoint to the output every second in other words if your output is 0-1000 so an error of 90° every second 90 would be added to the output. An Integral of 2.5 is equal to adding the "error" from setpoint times 2.5 to the output every second so at 90° every second 225 would be added to the output. as your output changes, your error will change and the influence will decrease The less error from setpoint the less integral affects your output. Integral needs to be slow compared to Proportional and Derivative

Proportional is instantaneous and affects your output immediately. if your error from the setpoint is zero proportional influence is zero. don't give proportional too much control. add a little proportional control and then go back and further adjust integral when you have too much proportional influence you will oscillate out of control.

The derivative is based on the rate of change per second (PID_v3). Use Derivative last to further enhance rapid recovery from changes. The derivative has no influence when nothing changes. Noise is your biggest issue here. Derivative amplifies noise. Adding just enough derivative influence will help quickly land your setpoint.

Z

ps

 digitalWrite(Servo_Pin, HIGH);
 micros(1000)
 // 0 = 0° and 1000 = 180°
 micros(min(0, max(1000, Output));
 digitalWrite(Servo_Pin, LOW);

should have been

 digitalWrite(Servo_Pin, HIGH);
 delayMicroseconds(1000)
 // 0 = 0° and 1000 = 180°
delayMicroseconds(min(1000, max(0, Output)); //you want the max value of greater than zero and the min value less than 1000 as your delay
 digitalWrite(Servo_Pin, LOW);
anmol1980 commented 2 years ago

Hi Z,

I am getting following errors from PID_v3 when I compile my code after I include your suggestions. Please let me know what I am missing.

Thanks, anmol1980

Arduino: 1.8.19 (Linux), Board: "Arduino Uno"

/home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::Compute()': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:112:3: error: 'DPRINTSFN' was not declared in this scope DPRINTSFN(10,"Input",Input,6,2); ^~~~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::BalanceBotDrive(float)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:156:3: error: 'DPRINTSFN' was not declared in this scope DPRINTSFN(10,"YawInput",YawInput,6,2); ^~~~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:167:3: error: 'DPRINTLN' was not declared in this scope DPRINTLN(); ^~~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:167:3: note: suggested alternative: 'PCINT0' DPRINTLN(); ^~~~ PCINT0

exit status 1 Error compiling for board Arduino Uno.

This report would have more information with "Show verbose output during compilation" option enabled in File -> Preferences.

On Mar 16, 2022, at 12:11 AM, Anmol Agrawal @.***> wrote:

Dear Z,

Thanks for your email. I almost want to give up on MPU6050. If you have an alternative that is immune to noise (may be with SPI), please let me know.

Coming back to MPU6050, I have a few questions for you.

1) I ran into a compilation error when I added PID_v3.h to my arduino code. The error is "DPRINTSTIMER' was not declared in this scope"

2) I only get problems when I am running motors (servo) using signal from MPU6050. I cannot calibrate on the fly. My offsets are accurate and works for some time, but the code then seems to tilt the axis of reference. You mentioned something about temperature that I didn’t understand. Could you please tell me more.

3) Can you suggest an alternative to replace Strings in my code? I am not very good in programming.

Million thanks for your help, Anmol

Arduino: 1.8.19 (Linux), Board: "Arduino Uno"

In file included from /tmp/arduino_modified_sketch_110082/Simple_MPU6050_Example.ino:28:0: /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:47:8: warning: extra qualification 'PID::' on member 'BalanceBotDrive' [-fpermissive] PID & PID::BalanceBotDrive(float TurnOffset); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:99:4: warning: extra qualification 'PID::' on member 'map_Generic' [-fpermissive] X PID::map_Generic(X x, M in_min, N in_max, O out_min, Q out_max); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:93:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:94:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:95:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardB_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:96:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseB_CB = nothing; ^~~ In file included from /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:14:0: /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:47:8: warning: extra qualification 'PID::' on member 'BalanceBotDrive' [-fpermissive] PID & PID::BalanceBotDrive(float TurnOffset); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:99:4: warning: extra qualification 'PID::' on member 'map_Generic' [-fpermissive] X PID::map_Generic(X x, M in_min, N in_max, O out_min, Q out_max); ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:93:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:94:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseA_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:95:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ForwardB_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.h:96:29: warning: invalid conversion from 'void ()()' to 'PID::voidFuncPtrD {aka void ()(double)}' [-fpermissive] voidFuncPtrD ReverseB_CB = nothing; ^~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::Compute()': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:111:2: error: 'DPRINTSTIMER' was not declared in this scope DPRINTSTIMER(100){ ^~~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::BalanceBotDrive(float)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:155:2: error: 'DPRINTSTIMER' was not declared in this scope DPRINTSTIMER(100){ ^~~~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetTunings(double, double, double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:244:28: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Kp<0 || Ki<0 || Kd<0) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetKp(double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:251:13: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Kp<0 ) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetKi(double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:256:13: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Ki<0 ) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetKd(double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:261:13: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if (Kd<0 ) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'PID& PID::SetOutputLimits(double, double)': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:287:17: warning: return-statement with no value, in function returning 'PID&' [-fpermissive] if(Min >= Max) return; ^~ /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp: In member function 'void PID::Initialize()': /home/pi/arduino-1.8.19/libraries/PID_v3/PID_v3.cpp:320:10: warning: return-statement with a value, in function returning 'void' [-fpermissive] return *this; // return Pointer to this class ^~~~ Multiple libraries were found for "Simple_MPU6050.h" Used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050 Not used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050_archive Not used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050_archive2 Not used: /home/pi/arduino-1.8.19/libraries/Simple_MPU6050_2021 Multiple libraries were found for "Wire.h" Used: /home/pi/arduino-1.8.19/hardware/arduino/avr/libraries/Wire Not used: /home/pi/arduino-1.8.19/libraries/Wire_archive exit status 1 Error compiling for board Arduino Uno.

This report would have more information with "Show verbose output during compilation" option enabled in File -> Preferences.

On Mar 15, 2022, at 12:17 AM, Homer Creutz @. @.>> wrote:

@anmol1980 https://github.com/anmol1980 That's Excellent, I'm glad my library is helping you I defiantly would get the latest version I have just fixed a little glitch that could help.

I try to avoid using String data type example String strtokIndx; Strings and Arduino UNOs don't get along well.

The PID loop that everyone uses has a fatal flaw unless you are using it with temperature The integral and derivative calculations are incorrect when you can't put the PID loop in the loop() function. and still there are other issues.

Use my PID instead. It uses exact timing rather than a fixed interval. and it also resets the integral to eliminate windup at the start. Arduino_PID_Library_v3 https://github.com/ZHomeSlice/Arduino_PID_Library_v3 it is a 1-1 swap just change your include to #include "PID_v3.h"

Proof of My PID in action.Balancing Bot hops off curb!!! https://youtu.be/JI7Pp7kWgmg Also my tuning video for balancing (Speed Control and Temperature control use a different tuning method) How to Balance Robot PID tutorial in under 2 minutes! https://youtu.be/uyHdyF0_BFo "0 pitch angle is not horizontal anymore" could be because of temperature messing with the calibration. you can trigger a calibration at any time with the MPU6050 level and motionless.

mpu.CalibrateMPU(); as the last line of your setup(); function

check to be sure your defaults are accurate:

define OFFSETS 456, 733, 679, 151 , -40, -19

Z

— Reply to this email directly, view it on GitHub https://github.com/ZHomeSlice/Simple_MPU6050/issues/23#issuecomment-1067546691, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEY2QC54TVVK7SCMEUQCIK3VAAFLZANCNFSM5QXL4VNA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.

ZHomeSlice commented 2 years ago

Thanks for helping me clean PID_v3.cpp I forgot I left my Debugging macros in

I added the macro in into the GitHub archive `#define DPRINTSFN(StrSize,Name,Variable,Spaces,Precision) {char S[max((Spaces + Precision + 3), StrSize)];Serial.print(F(" "));Serial.print(F(Name));Serial.print(F(" ")); Serial.print(dtostrf((float)Variable,Spaces,Precision ,S));}//StringSize,Name,Variable,Spaces,Precision

define DPRINTLN(...) Serial.println(__VA_ARGS__)

` It's what was missing. The macros help me simplify all the extra work

Here are all my debug macros for you to try. To enable the output just add this before the macro definitions. #define DEBUG 1

#ifdef DEBUG
#define DPRINTSTIMER(t)    for (static uint32_t SpamTimer; (uint32_t)(millis() - SpamTimer) >= (t); SpamTimer = millis())
#define SERIALBEGIN(...)   Serial.begin(__VA_ARGS__)
#define DPRINT(...)        Serial.print(__VA_ARGS__)
#define DPRINTLN(...)      Serial.println(__VA_ARGS__)
#define DPRINTF(...)       Serial.print(F(__VA_ARGS__))   //Printing  fixed text using the F macro
#define DPRINTLNF(...)     Serial.println(F(__VA_ARGS__)) //Printing Fixed text using the F macro
#define DPRINTSFN(StrSize,Name,Variable,Spaces,Precision) {char S[max((Spaces + Precision + 3), StrSize)];Serial.print(F(" "));Serial.print(F(Name));Serial.print(F(" ")); Serial.print(dtostrf((float)Variable,Spaces,Precision ,S));}//StringSize,Name,Variable,Spaces,Precision
#define DPRINTSF(...)      {char S[30]; Serial.print(dtostrf((float)__VA_ARGS__ , S));}//Variable,Spaces,Precision
#define DPRINTLNSF(...)    {char S[30]; Serial.println(dtostrf((float)__VA_ARGS__ , S));}//Variable,Spaces,Precision
#define DPRINTSS(Str,Sp)     {int Spaces = max(strlen(Str),Sp) ; char S[Spaces+1]; strcpy(S,Str); for(int i = strlen(Str);i < Spaces;i++) S[i] = ' '; S[Spaces] = '\0';  Serial.print(S);}//Variable,Spaces Left Justified
#define DPRINTSSR(Str,Sp)    {int i, Spaces = max(strlen(Str),Sp) ; char S[Spaces+1]; for(i = 0;i < Spaces - strlen(Str);i++) S[i] = ' ';  strcpy(S+i,Str);  Serial.print(S);}//Variable,Spaces Right Justified
#define DPRINTSSC(Str,Sp)    {int Spaces = max(strlen(Str),Sp) ; char S[Spaces+1]; for(int i = 0;i < Spaces;i++) S[i] = ' '; int C = (Spaces - strlen(Str))*.5; memcpy(S + C,Str, strlen(Str));  Serial.print(S);}//Variable,Spaces Centered
#define PINMODE(...)       pinMode(__VA_ARGS__)
#define TOGGLEd13          PINB = 0x20                    //For the UNO only
#define DPRINTBL(Num,Digits) for (int i=0;i<Digits;i++) Serial.write(((Num >> i) & 1) == 1 ? '1' : '0'); // Prints a binary number with following Placeholder Zeros  (Digits)
#define DPRINTB16(Num) for (unsigned int t = 0x8000; t; t >>= 1) Serial.write(Num  & t ? '1' : '0'); // Prints a 16 bit binary number with leading zeros
#define DPRINTB(Num,Digits) for (uint32_t t = (1UL<<Digits-1); t; t >>= 1) Serial.write(Num  & t ? '1' : '0'); // Prints a binary number with leading zeros (Digits)
#define DPRINTBIN(Num) for (uint32_t t = (1UL<< (sizeof(Num)*8)-1); t; t >>= 1) Serial.write(Num  & t ? '1' : '0'); // Prints a binary number with leading zeros (Automatic Handling)
#define DPRINTBINL(Num) for (int i=0;i<(sizeof(Num)*8);i++) Serial.write(((Num >> i) & 1) == 1 ? '1' : '0'); // Prints a binary number with following Placeholder Zeros  (Automatic Handling)
#define DPRINTBX(S,Num,Digits,nl) Serial.print(F(S)); for (uint32_t t = (1UL<<Digits-1); t; t >>= 1) Serial.write(Num  & t ? '1' : '0'); if(nl)Serial.println();// Prints a binary number with leading zeros (Digits)
#define DPRINTBINX(S,Num,nl) Serial.print(F(S)); for (uint32_t t = (1UL<< (sizeof(Num)*8)-1); t; t >>= 1) Serial.write(Num  & t ? '1' : '0'); if(nl)Serial.println(); // Prints a binary number with leading zeros (Automatic Handling)
#define DPRINTBINLX(S,Num,nl) Serial.print(F(S)); for (int i=0;i<(sizeof(Num)*8);i++) Serial.write(((Num >> i) & 1) == 1 ? '1' : '0'); if(nl)Serial.println(); // Prints a binary number with following Placeholder Zeros  (Automatic Handling)
#define DPRINTHEX(Num) Serial.print(Num>>4,HEX);Serial.print(Num&0X0F,HEX);

#else
#define DPRINTSTIMER(t)    if(false)
#define SERIALBEGIN(...)   //blank line
#define DPRINT(...)        //blank line
#define DPRINTLN(...)      //blank line
#define DPRINTF(...)       //blank line
#define DPRINTLNF(...)     //blank line
#define DPRINTSFN(...)     //blank line
#define DPRINTSF(...)      //blank line
#define DPRINTLNSF(...)    //blank line
#define DPRINTSS(...)      //blank line
#define DPRINTSSR(...)     //blank line
#define DPRINTSSC(...)     //blank line
#define DELAY(...)         //blank line
#define PINMODE(...)       //blank line
#define TOGGLEd13          //blank line
#define DPRINTBL(...)      //blank line
#define DPRINTB16(...)     //blank line
#define DPRINTB(...)       //blank line
#define DPRINTBIN(...)     //blank line
#define DPRINTBINL(...)    //blank line
#define DPRINTBX(...)      //blank line
#define DPRINTBINX(...)    //blank line
#define DPRINTBINLX(...)   //blank line
#define DPRINTHEX(...)     //blank line

#endif

Z

anmol1980 commented 2 years ago

Hi Z,

My stabilizer works really well now. I was able to implement all your suggestions. Thanks for educating me to better control servos and use your library effectively. I also found some loose connections to MPU6050 that may have caused more problem.

Before we close this thread, I would like to ask one last question. Could you please elaborate about your following comment? I have incorporated your following suggestion without understanding it and would appreciate more context to help me understand it. Use the MPU's Interrupt pin to trigger the reading to get the most accurate calculation Change mpu.dmp_read_fifo();// Must be in loop to mpu.dmp_read_fifo(1);// Must be in loop and connect the interrupt pin to pin 2 on your arduino.

Thanks a lot for your help.

Best anmol1980

On Mar 18, 2022, at 10:53 PM, Homer Creutz @.***> wrote:

Thanks for helping me clean PID_v3.cpp I forgot I left my Debugging macros in

I added the macro in into the GitHub archive

define DPRINTSFN(StrSize,Name,Variable,Spaces,Precision) {char S[max((Spaces + Precision + 3), StrSize)];Serial.print(F(" "));Serial.print(F(Name));Serial.print(F(" ")); Serial.print(dtostrf((float)Variable,Spaces,Precision ,S));}//StringSize,Name,Variable,Spaces,Precision #define DPRINTLN(...) Serial.println(__VA_ARGS__)

Is what was missing The macros help me simplify all the extra work

Here are all my debug macros for you to try. To enable the output just add this before the macro definitions.

define DEBUG 1

ifdef DEBUG

define DPRINTSTIMER(t) for (static uint32_t SpamTimer; (uint32_t)(millis() - SpamTimer) >= (t); SpamTimer = millis())

define SERIALBEGIN(...) Serial.begin(__VA_ARGS__)

define DPRINT(...) Serial.print(__VA_ARGS__)

define DPRINTLN(...) Serial.println(__VA_ARGS__)

define DPRINTF(...) Serial.print(F(__VA_ARGS__)) //Printing fixed text using the F macro

define DPRINTLNF(...) Serial.println(F(__VA_ARGS__)) //Printing Fixed text using the F macro

define DPRINTSFN(StrSize,Name,Variable,Spaces,Precision) {char S[max((Spaces + Precision + 3), StrSize)];Serial.print(F(" "));Serial.print(F(Name));Serial.print(F(" ")); Serial.print(dtostrf((float)Variable,Spaces,Precision ,S));}//StringSize,Name,Variable,Spaces,Precision

define DPRINTSF(...) {char S[30]; Serial.print(dtostrf((float)__VA_ARGS__ , S));}//Variable,Spaces,Precision

define DPRINTLNSF(...) {char S[30]; Serial.println(dtostrf((float)__VA_ARGS__ , S));}//Variable,Spaces,Precision

define DPRINTSS(Str,Sp) {int Spaces = max(strlen(Str),Sp) ; char S[Spaces+1]; strcpy(S,Str); for(int i = strlen(Str);i < Spaces;i++) S[i] = ' '; S[Spaces] = '\0'; Serial.print(S);}//Variable,Spaces Left Justified

define DPRINTSSR(Str,Sp) {int i, Spaces = max(strlen(Str),Sp) ; char S[Spaces+1]; for(i = 0;i < Spaces - strlen(Str);i++) S[i] = ' '; strcpy(S+i,Str); Serial.print(S);}//Variable,Spaces Right Justified

define DPRINTSSC(Str,Sp) {int Spaces = max(strlen(Str),Sp) ; char S[Spaces+1]; for(int i = 0;i < Spaces;i++) S[i] = ' '; int C = (Spaces - strlen(Str))*.5; memcpy(S + C,Str, strlen(Str)); Serial.print(S);}//Variable,Spaces Centered

define PINMODE(...) pinMode(__VA_ARGS__)

define TOGGLEd13 PINB = 0x20 //For the UNO only

define DPRINTBL(Num,Digits) for (int i=0;i<Digits;i++) Serial.write(((Num >> i) & 1) == 1 ? '1' : '0'); // Prints a binary number with following Placeholder Zeros (Digits)

define DPRINTB16(Num) for (unsigned int t = 0x8000; t; t >>= 1) Serial.write(Num & t ? '1' : '0'); // Prints a 16 bit binary number with leading zeros

define DPRINTB(Num,Digits) for (uint32_t t = (1UL<<Digits-1); t; t >>= 1) Serial.write(Num & t ? '1' : '0'); // Prints a binary number with leading zeros (Digits)

define DPRINTBIN(Num) for (uint32_t t = (1UL<< (sizeof(Num)*8)-1); t; t >>= 1) Serial.write(Num & t ? '1' : '0'); // Prints a binary number with leading zeros (Automatic Handling)

define DPRINTBINL(Num) for (int i=0;i<(sizeof(Num)*8);i++) Serial.write(((Num >> i) & 1) == 1 ? '1' : '0'); // Prints a binary number with following Placeholder Zeros (Automatic Handling)

define DPRINTBX(S,Num,Digits,nl) Serial.print(F(S)); for (uint32_t t = (1UL<<Digits-1); t; t >>= 1) Serial.write(Num & t ? '1' : '0'); if(nl)Serial.println();// Prints a binary number with leading zeros (Digits)

define DPRINTBINX(S,Num,nl) Serial.print(F(S)); for (uint32_t t = (1UL<< (sizeof(Num)*8)-1); t; t >>= 1) Serial.write(Num & t ? '1' : '0'); if(nl)Serial.println(); // Prints a binary number with leading zeros (Automatic Handling)

define DPRINTBINLX(S,Num,nl) Serial.print(F(S)); for (int i=0;i<(sizeof(Num)*8);i++) Serial.write(((Num >> i) & 1) == 1 ? '1' : '0'); if(nl)Serial.println(); // Prints a binary number with following Placeholder Zeros (Automatic Handling)

define DPRINTHEX(Num) Serial.print(Num>>4,HEX);Serial.print(Num&0X0F,HEX);

else

define DPRINTSTIMER(t) if(false)

define SERIALBEGIN(...) //blank line

define DPRINT(...) //blank line

define DPRINTLN(...) //blank line

define DPRINTF(...) //blank line

define DPRINTLNF(...) //blank line

define DPRINTSFN(...) //blank line

define DPRINTSF(...) //blank line

define DPRINTLNSF(...) //blank line

define DPRINTSS(...) //blank line

define DPRINTSSR(...) //blank line

define DPRINTSSC(...) //blank line

define DELAY(...) //blank line

define PINMODE(...) //blank line

define TOGGLEd13 //blank line

define DPRINTBL(...) //blank line

define DPRINTB16(...) //blank line

define DPRINTB(...) //blank line

define DPRINTBIN(...) //blank line

define DPRINTBINL(...) //blank line

define DPRINTBX(...) //blank line

define DPRINTBINX(...) //blank line

define DPRINTBINLX(...) //blank line

define DPRINTHEX(...) //blank line

endif

Z

— Reply to this email directly, view it on GitHub https://github.com/ZHomeSlice/Simple_MPU6050/issues/23#issuecomment-1072925147, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEY2QC27COEHKUXUYQOSO43VAU6TRANCNFSM5QXL4VNA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.

intensite commented 2 years ago

I am following this conversation as an outsider. I am impressed at the patience and de devotion to help by @ZHomeSlice Respect ! :thumbsup:

anmol1980 commented 2 years ago

Absolutely agree with you @intensite !!

ZHomeSlice commented 2 years ago

@anmol1980 Using interrupt pin: Your current method spams the i2c bus looking at the FIFO buffet size. This is simpler for most who are just getting started with the MPU6050. When it changes from zero we retrieve the data from the FIFO buffer. mpu.dmp_read_fifo();

Alternatively, the int pin on your breakout board briefly flashes high every time data is added to the FIFO buffer.

When we use a one in this function mpu.dmp_read_fifo(1); An interrupt function is attached to pin 2 When pin 2 changes state the flag is set to true. attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);

I've automated this attachment process. Some details on how this works see: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

After pin 2 changes a flag is set true The next time mpu.dmp_read_fifo(1); Function executed a true flag allows the process to continue which then verifies the FIFO buffer has data and upon confirmation it retrieved the data.

The amount of processing time saved is impressive. As well as the data is always fresh.

Z

@intensite
Thank you. This has been a fun experience sharing this library.

anmol1980 commented 2 years ago

thanks for your explanation Z! Thanks again for all your suggestions that helped me implement my stabilizer.