ACC_getADC()
getEstimatedAttitude()
Gyro_getADC()
annexCode()
Gyro_getADC() and getting average of both gyro measurements
doOptionalSmoothing()
MPU_getAllValuesInOneI2CCall()
doOptionalSmoothing()
getEstimatedAttitude()
annexCode()
Plüschi wrote:Explanation:
If the calib sum will be 1020, the division will make 1020 / 512 = 1 out of it. But (1020 + 256) / 512 = 2 which is more accurate.
Same applies to acc calibraton. This is an accuracy improvement which wont break anything else. I have even tested it for neg numbers: -1025 / 512 = -3, but (-1025 + 256) / 512 = -2;
Another idea is to run the calibration at a higher resolution than the measurement, so we get a statistical accuracy improvement.
With both mods, adding 256 and statistically upping the resolution, i have seen a drift of 2 deg / minute on a 20$ nanowii.
Sebbi wrote:Just a quick addition:
MultiWii is called MultiWii because of the use of the sensors from a Wii remote. Those gyros and accelerometers were fine 5 years ago, but the 6050 and currently the 9050 from Invensense run circles around them in terms of accurary, cross-axis error, temperature drift, etc ... and basically EVERY IMU out there uses them instead of the old Wii sensors. While I don't think MultiWii should be renamed MultiMPU it should recognize its popularity and focus on this particular sensor in terms of accuracy.
[*]the 6050's gyro is configured to for full scale +-2000 °/s which corresponds to 16.4 LSB per °/s ... and ultimately just 4.1 LSB per °/s because of division by 4 in Gyro_getADC(). This could be improved to 32.8 or 65.5 LSB per °/s and use the full 16 bit range depending on how MultiWii behaves when the gyro saturates (if noise and vibration is an issue, user can activate averaging or LPF on the sensor itself)
[*]same for the accelerometer ... it is configured for a full scale range of +-8 g and values get divided by 8 ... resulting in 512 LSB per g (when 0|0|512 means no tilt then 1|0|511 means tilted 0,11 degrees). Using a range of +-2 g would make far more sense, since ACC values are only used for calculations between +- 1.423 g in IMU.cpp. This would result in 2048 LSB per g (smallest detectable tilt 0,028 degrees) and could be improved further by not dividing by 8 ... noise is a big problem here, but the MPU6050 is pretty noise free ... countering vibrations needs filtering/averaging, not cutting away bits)
[*]The structure of computeIMU() can also be improved for MPU6050 usage. Instead of splitting up the measurements into
- Code: Select all
ACC_getADC()
getEstimatedAttitude()
Gyro_getADC()
annexCode()
Gyro_getADC() and getting average of both gyro measurements
doOptionalSmoothing()
#elif defined(MPU6050)
Gyro_getADC();
getEstimatedAttitude();
annexCode();
for (axis = 0; axis < 3; axis++) {
imu.gyroData[axis] = imu.gyroADC[axis] / 16;
}
void computeIMU ()
{
uint8_t axis;
mpu6050_getADC();
getEstimatedAttitude();
annexCode();
for(axis=0;axis<3;axis++)
gyroData[axis] = gyroADC[axis];
}
Crashpilot1000 wrote:blablablablabla
Maybe he would be better off looking at your github and seeing the gems you placed there .
picstart wrote:Now the magnetic field isn't affected by acceleration
picstart wrote:a 1% per sec drift is too bad. In fact these GYROS are remarkable
picstart wrote:All GYROs will drift it is just a matter of how much. The GYRO is the principal sensor mostly because it is a first order derivative and the second order derivatve ACC is comingled with the gravitational acceleration. OK so we have angular rate of change where as it would be better to have just the euler angles. So the rate change of the Gyro gets integrated and brings in an unkown constant as all integration does. Now the magnetic field isn't affected by acceleration so a yaw pitch roll correction ( correlation test) is possible . Next in level flight with small accelerations the constant gravitational field can be used to correlate ( adjust for the angular GYRO drift). It is not that more accurate rate change GYROS aren't useful it is just that the integration must introduce a constant drift that needs a correlation correction. I don't see why a 1% per sec drift is too bad. In fact these GYROS are remarkable.
An aside
Knowing your speed with extreme accuracy doesn't give you your absolute distance from an arbitrary point unless you also know a correlation point with equal precision (an example correlation point could be the position of your starting point aka as the integration constant above). The GYRO de-correlates (drifts) from its starting position with time and temperature ( electrical noise or whatever) limit the accuracy of the angular velocity measurement. The error always accumulates so a correlation correction is always needed so the last bit from the GYRO is only meaningful if we have similar bit precision with respect to correlation.
case MSP_RAW_IMU:
headSerialReply(18);
for(uint8_t i=0;i<3;i++) serialize16(accSmooth[i]>>3);
for(uint8_t i=0;i<3;i++) serialize16(gyroData[i]>>2);
for(uint8_t i=0;i<3;i++) serialize16(magADC[i]);
break;
for(uint8_t i=0;i<3;i++) serialize16(accSmooth[i]>>3);
timecop wrote:for(uint8_t i=0;i<3;i++) serialize16(accSmooth[i]>>3);
for loops on one line, for FASTER EXECUTION.
You heard it here first.
Sebbi wrote:MultiWii is using a struct imu ... no accSmooth/gyroData/etc ...
Sebbi wrote:MultiWii is using a struct imu ... no accSmooth/gyroData/etc ...
Anyway, you have to adapt ALL changes from the Github branch. Not just some of them. The repo itself is based on trunk, so this should work right away ...
Plüschi wrote:Barney,
You have to set acc_1G to the new value (4096).
If you use undivided acc or gyro values you have to scale them down in serial.c where they are sent to the GUI.
This way:
- Code: Select all
case MSP_RAW_IMU:
headSerialReply(18);
for(uint8_t i=0;i<3;i++) serialize16(accSmooth[i]>>3);
for(uint8_t i=0;i<3;i++) serialize16(gyroData[i]>>2);
for(uint8_t i=0;i<3;i++) serialize16(magADC[i]);
break;
Crashpilot1000 wrote:using unaveraged and uncrippled gyro data ... with altered main pid controller
tmp0flt = (float)cycleTime;
MwiiTimescale = tmp0flt * 3.3333333e-4f;
dT = tmp0flt * 0.000001f; // pt1 element http://www.multiwii.com/forum/viewtopic.php?f=23&t=2624
prop = (float)max(abs(rcCommand[PITCH]), abs(rcCommand[ROLL])); // range [0;500] Crashpilot: prop is float now
switch (cfg.mainpidctrl)
{
case 1: // 1 = OriginalMwiiPid pimped by me
for (axis = 0; axis < 3; axis++)
{
if ((f.ANGLE_MODE || f.HORIZON_MODE) && axis < 2) // MODE relying on ACC 50 degrees max inclination
{
errorAngle = constrain(2.0f * (float)rcCommand[axis] + GPS_angle[axis], -500.0f, +500.0f) - angle[axis] + (float)cfg.angleTrim[axis];
PTermACC = errorAngle * (float)cfg.P8[PIDLEVEL] * 0.01f;
tmp0flt = (float)cfg.D8[PIDLEVEL] * 5.0f;
PTermACC = constrain(PTermACC, -tmp0flt, +tmp0flt);
errorAngle *= MwiiTimescale;
errorAngleI[axis] = constrain(errorAngleI[axis] + errorAngle, -10000.0f, +10000.0f); // WindUp
ITermACC = (errorAngleI[axis] * (float)cfg.I8[PIDLEVEL]) / 4096.0f;
}
if (!f.ANGLE_MODE || f.HORIZON_MODE || axis == 2) // MODE relying on GYRO or YAW axis
{
error = (float)rcCommand[axis] * 320.0f / (float)cfg.P8[axis];
error -= gyroData[axis];
PTermGYRO = (float)rcCommand[axis];
error *= MwiiTimescale;
errorGyroI[axis] = constrain(errorGyroI[axis] + error, -64000.0f, +64000.0f);
if (abs(gyroData[axis]) > 2560) errorGyroI[axis] = 0;
ITermGYRO = errorGyroI[axis] * (float)cfg.I8[axis] * 0.00003125f;
}
if (f.HORIZON_MODE && axis < 2)
{
PTerm = (PTermACC * (500.0f - prop) + PTermGYRO * prop) * 0.002f;
ITerm = (ITermACC * (500.0f - prop) + ITermGYRO * prop) * 0.002f;
}
else
{
if (f.ANGLE_MODE && axis < 2)
{
PTerm = PTermACC;
ITerm = ITermACC;
}
else
{
PTerm = PTermGYRO;
ITerm = ITermGYRO;
}
}
PTerm -= (gyroData[axis] * (float)dynP8[axis] * 0.003125f);
delta = (float)(gyroData[axis] - lastGyro[axis]) / (MwiiTimescale * 4);
lastGyro[axis] = gyroData[axis];
deltaSum = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
if (cfg.mainpt1cut != 0) // pt1 element http://www.multiwii.com/forum/viewtopic.php?f=23&t=2624
{
deltaSum = lastDTerm[axis] + (dT / (MainDpt1Cut + dT)) * (deltaSum - lastDTerm[axis]);
lastDTerm[axis] = deltaSum;
}
DTerm = (float)deltaSum * (float)dynD8[axis] * 0.03125f;
axisPID[axis] = PTerm + ITerm - DTerm;
}
break;
case 2:
....
Calculation of MainDpt1Cut:
MainDpt1Cut = 1.0f / (2.0f * M_PI * (float)cfg.mainpt1cut);
The default is:
cfg.mainpt1cut = 15
global_conf.accZero[ROLL] = (a[ROLL]+256)>>9;
global_conf.accZero[PITCH] = (a[PITCH]+256)>>9;
global_conf.accZero[YAW] = ((a[YAW]+256)>>9)-ACC_1G; // for nunchuk 200=1G
global_conf.accZero[ROLL] = (a[ROLL]+ACC_1G)>>9;
global_conf.accZero[PITCH] = (a[PITCH]+ACC_1G)>>9;
global_conf.accZero[YAW] = ((a[YAW]+ACC_1G)>>9)-ACC_1G; // for nunchuk 200=1G
Users browsing this forum: Google Adsense [Bot] and 1 guest