Closed anmol1980 closed 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.
@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:
Z
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.
@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
@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
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.
@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);
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.
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
` 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
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.
I am following this conversation as an outsider. I am impressed at the patience and de devotion to help by @ZHomeSlice Respect ! :thumbsup:
Absolutely agree with you @intensite !!
@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.
thanks for your explanation Z! Thanks again for all your suggestions that helped me implement my stabilizer.
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