Hello Gursimran,
For the servo_set calculation of Snippet 1, since ypur constants are much less than 1, rather than multiplying by a very small value, you could divide by the reciprocal of your constants. For the values given, the reciprocals are very close to integer values. The servo_set value might possibly have an error of 1 because the result of each quotient has the fractional part truncated, and three quotients are added. Additional "rounding" could be applied to each quotient calculation, but would require a more complex calculation.
You could also apply the quasi fixed point method described below, but again requiring more execution cycles.
// SNIPPET 1int error, iterm, dterm, correction;int r_kp = 5; // 1/0.2int r_ki = 435; // 1/0.0023int r_kd = 30; // 1/0.033correction = (int)(error/r_kp + iterm/r_ki + dterm/r_kd);if (correction > 300) correction = 300;else if (correction < -300) correction = -300;servo_set = 1500 - correction; // Feed these values to servos
It would seem that, for fixed point calculations, there may be sufficient accuracy, using an 8-bit fractional part. This may be effectively achieved "on the fly" by making sure that each intermediate result is increased by 256 times, and the final integer result achieved by finally dividing by 256. Multiplying and dividing by 256 should result in fast operations for the compiler.
There also does seem to be some ambiguity with the com_ratio variable, whether it is a simple variable or a constant array. For the array version, 23.44 * 256 ~= 6001.
// SNIPPET 2/* black_val and white_val are sensor values when IR sensors are on black and white surfaces .. from ATD data register*/unsigned char black_val, white_val;int com_ratio;unsigned char i;//unsigned int com_ratio[7] = {6001, 6001, 6001 ... }; // ?? Name conflictcom_ratio = (int)(black_val - white_val); // /256; Leave as 8-bit integer
for (i = 0; i < 7; i++) { com_val = (unsigned char)(com_ratio * sen_val / 256); ... }//-------------------------------------------------------------------#define KP_DC 512L // 2.00 * 256#define KD_DC 827L // 3.23 * 256 int correction_dc, error_dc, perror_dc; // all are signed integers.. correction_dc = (int)((KP_DC*error_dc + KD_DC*(error_dc - perror_dc))/256);
For the last example, specifying KP_DC and KD_DC as long values will promote the intermediate calculations to long values, to prevent potential overflow.
Regards,
Mac