Interpolation issues in array. float works, int doesn't

Hi guys,

I'm confused regarding interpolation.

Using an ESP32. Arduino IDE 1.8.6.

The main goal is to read the rpm of an engine and then control a servo depending on rpm.

I have an array of rpm / servo motor positioning.

I have a potentiometer that simulates rpm and also a servo motor. Reading both pots.

The goal is that the servo will control an exhaust valve. The array I have made is just a few lines, but it will have more rows eventually for better control.

The servo should be fully CCW at zero rpm. Then go fully CW at 2,000rpm and then return to fully CCW at 3,000rpm. This is to enable setting of the valve to the correct position by way of cable adjustment.

Then the servo stays fully CCW until 7,000rpm and at that point it starts to move CW until fully CW at 11,000rpm. Between these two rpm points I want the servo value to interpolate.

Then from 11,000rpm until 13,000rpm the servo stays fully CW.

The problem is that if I use an array of integers such as this:

int servoArray [row] [col] = {
  {0/*rpm*/, 700/*Servo Feedback*/},
  {1999/*rpm*/, 700/*Servo Feedback*/},
  {2000/*rpm*/, 3200/*Servo Feedback*/},
  {3000/*rpm*/, 3200/*Servo Feedback*/},
  {3001/*rpm*/, 700./*Servo Feedback*/},
  {7000/*rpm*/, 700/*Servo Feedback*/},
  {11000/*rpm*/, 3200./*Servo Feedback*/},
  {14000/*rpm*/, 3200/*Servo Feedback*/}
};

The servo does not interpolate between 7,000rpm and 11,000rpm. It says fully CCW until 11,000rpm and then goes fully CW.

However, if I change the array to floats such as:

float servoArray [row] [col] = {
  {0./*rpm*/, 700./*Servo Feedback*/},
  {1999.9/*rpm*/, 700./*Servo Feedback*/},
  {2000./*rpm*/, 3200./*Servo Feedback*/},
  {3000./*rpm*/, 3200./*Servo Feedback*/},
  {3000.1/*rpm*/, 700./*Servo Feedback*/},
  {7000./*rpm*/, 700./*Servo Feedback*/},
  {11000./*rpm*/, 3200./*Servo Feedback*/},
  {14000./*rpm*/, 3200./*Servo Feedback*/}
};

Then everything functions perfectly.

Here's a screenshot of the serial plotter with it working correctly using floats. Blue is rpm, red is the servo position. As you can see the servo operates smoothly between 7,000 and 1,000rpm:

And this is using int. The servo moves fully CCW fully CW:

So, my confusion is why is it doing this? If I do the interpolation equation on a calculator or in excel it works fine, but not so in the code.

As it is, I'm happy to just use it with floats, but I'll lose sleep as I don't know the issue and was hoping that maybe one of you guys can spot the issue.

Here's the full code:

/*   ESP32
     Maps servo position to rpm
     Uses TB6612FNG motor driver module
*/

#include "driver/adc.h" //  Necessary for using adc1_get_raw

/////////////////////
//  ADC INPUT pins //
/////////////////////

const byte servoIn = 39;  //  VN. Read Potentiometer on servo motor
const byte potIn = 32;    //  Read Potentiometer for simulating rpm

////////////////
//  Variables //
////////////////

int servoVal; //  Value of Servo Potentiometer
int potVal;   //  Value of Potentiometer for simulating rpm
int rpm;
int maxVal = 3200;
int minVal = 700;
int minRPM = 0;
int maxRPM = 13000;
int hysteresis = 30;  //  stops motor from vibrating about set point

int pwmA = 27;
int in1A = 25;
int in2A = 26;

///////////////
//  Printing //
///////////////

unsigned long lastTimePrinted = millis();

///////////////////////
//  RC Servo Timing  //
///////////////////////

const int row = 8;
const int col = 2;

///////////////////////////////
//  array using float works  //
///////////////////////////////

float servoArray [row] [col] = {
  {0./*rpm*/, 700./*Servo Feedback*/},
  {1999.9/*rpm*/, 700./*Servo Feedback*/},
  {2000./*rpm*/, 3200./*Servo Feedback*/},
  {3000./*rpm*/, 3200./*Servo Feedback*/},
  {3000.1/*rpm*/, 700./*Servo Feedback*/},
  {7000./*rpm*/, 700./*Servo Feedback*/},
  {11000./*rpm*/, 3200./*Servo Feedback*/},
  {14000./*rpm*/, 3200./*Servo Feedback*/}
};

/////////////////////////////////////
//  array using int does not work  //
/////////////////////////////////////

//int servoArray [row] [col] = {
//  {0/*rpm*/, 700/*Servo Feedback*/},
//  {1999/*rpm*/, 700/*Servo Feedback*/},
//  {2000/*rpm*/, 3200/*Servo Feedback*/},
//  {3000/*rpm*/, 3200/*Servo Feedback*/},
//  {3001/*rpm*/, 700./*Servo Feedback*/},
//  {7000/*rpm*/, 700/*Servo Feedback*/},
//  {11000/*rpm*/, 3200./*Servo Feedback*/},
//  {14000/*rpm*/, 3200/*Servo Feedback*/}
//};

void setup() {

  Serial.begin(9600);

  ////////////////
  //  Setup ADC //
  ////////////////

  analogReadResolution(12);
  analogSetPinAttenuation(servoIn, ADC_11db);
  analogSetPinAttenuation(potIn, ADC_11db);
  adcAttachPin(servoIn);
  adcAttachPin(potIn);

  ///////////////////////////////////////
  //  Setup PWM to control motor speed //
  ///////////////////////////////////////

  ledcSetup(15, 2000, 12);
  ledcAttachPin(pwmA, 15);

  digitalWrite(in1A, LOW);
  digitalWrite(in2A, LOW);

  pinMode(pwmA, OUTPUT);
  pinMode(in1A, OUTPUT);
  pinMode(in2A, OUTPUT);

}

void loop() {

  servoVal = adc1_get_raw(ADC1_CHANNEL_3);
  potVal = map(adc1_get_raw(ADC1_CHANNEL_4), 0, 4095, minVal, maxVal);
  rpm = map(potVal, minVal, maxVal, minRPM, maxRPM);

  for (int i = 6; i >= 0; i--) {
    if (rpm >= servoArray[i][0]) {
      potVal = servoArray[i][1] + ((servoArray[i + 1][1] - servoArray[i][1]) / (servoArray[i + 1][0] - servoArray[i][0])) * (rpm - servoArray[i][0]);
      break;
    }
  }

  if (servoVal > potVal + hysteresis) {
    digitalWrite(in1A, LOW);
    digitalWrite(in2A, HIGH);
    ledcWrite(15, 4000); //  ledcWrite(ledChannel, dutyCycle)
  }
  else if (servoVal < potVal - hysteresis) {
    digitalWrite(in1A, HIGH);
    digitalWrite(in2A, LOW);
    ledcWrite(15, 4000); //  ledcWrite(ledChannel, dutyCycle)
  }
  else {
    digitalWrite(in1A, HIGH);
    digitalWrite(in2A, HIGH);
  }

  if (millis() - lastTimePrinted >= 100) {
    Serial.printf("%d,", rpm);
    Serial.printf("%d\n", servoVal);
    lastTimePrinted = millis();
  }
}

If you have any questions then I'll try my best to answer.

Cheers,

Matt

The difference between integer division and floating point division is vast.

The result of dividing 4 by 5 is zero in the first case. Mind the parentheses.

@jremington

Thanks. You've hit on a very good point there.

I'll have to fiddle around with it a little. A job for tomorrow. Time for bed!

Cheers

Matt​

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.