Look up table returns the wrong data for hydraulic hammer positioning

I have built a device that calculates the distance from the tip of an articulating hydraulic hammer’s chisel point to the base surface that the hammer is to reach, the purpose is to stop the hammer from striking the bottom, steel layer in a refractory/steel wall (hammer off all refractory but stop when reaching the underlying steel shell plate).
The device uses a basic potentiometer with a weighted pendulum to measure the angle of the hammer and a cheap ultrasonic transducer to measure the distance from the hammer to the surface to be hammered.
Two simple trigonometric calculations give the distance from the chisel point to the steel wall.
I have used two lookup tables to provide the secant and cosine of the hammer angle.

The problem I have is that the number returned from the lookup table is wrong, eg. when the angle is 45 degrees, it returns the secant for a 38-degree angle. It seems that the number returned from the lookup table has been shifted but unfortunately, the shift isn’t consistent. The numbers returned for the first few places in the lookup table are very close but this shift increases as it looks up the numbers further into the table. The same holds true for cosine lookup table and here, the shift amount matches that of the secant lookup table.

I have triple checked the lookup table data and all is good (only 91 entries for each table; o - 90 degrees).
I have attached the entire code, the code is full of commented out lines and certainly needs to be cleaned up.
No doubt I have overlooked something basic, I’m a mechanical engineer after all (stay off of any bridges near me), any help would be appreciated.

built_tes11_remarked_ultrasonic_mathwork.ino (8.41 KB)

OP’s code properly posted where everyone can see it now.

#include <avr/pgmspace.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(38, 42, 22, 26, 30, 34);
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);

  //if (adc_key_in > 1000) return btnNONE;
  //if (adc_key_in < 50)   return btnRIGHT
  //if (adc_key_in < 195)  return btnUP
  //if (adc_key_in < 380)  return btnDOWN
  //if (adc_key_in < 555)  return btnLEFT
  //if (adc_key_in < 790)  return btnSELECT
  //return btnNONE;
}


const int refrac = 15;
int groundPin = 5;
int groundState = 0;
int rly7 = 7; // LOW = hammer on
int toggle1Pin = 2; //this is override switch
int toggle1State = 0;
int toggle2Pin = 3; // this is bypass switch
int toggle2State = 0;
const int echoPin = 12;
const int trigPin = 13;
long duration;
int distance;
int potPin = 4;    // the input pin for the potentiometer
int val = 0;       // variable to store the value coming from the sensor divided for angle
float val1 = 0; // actual pot pin value
float val2 = 0;
float val3 = 0;
float val4 = 0;
float val5 = 0;
float hyp1 = 0;
double x = 0;
double y = 0;
double z = 0;

float outC[91] = {1, 0.99985, 0.99939, 0.99863, 0.99756, 0.99619, 0.99452, 0.99255, 0.99027, 0.98769, 0.98481, 0.98163, 0.97815, 0.97437, 0.97030, 0.96593, 0.96126, 0.95630, 0.95106, 0.94552, 0.93969, 0.93358, 0.92718, 0.92050, 0.91355, 0.90631, 0.89879, 0.89101, 0.88295, 0.87462, 0.86603, 0.85717, 0.84805, 0.83867, 0.82904, 0.81915, 0.80902, 0.79864, 0.78801, 0.77715, 0.76604, 0.75471, 0.74314, 0.73135, 0.71934, 0.70711, 0.69466, 0.68200, 0.66913, 0.65606, 0.64279, 0.62932, 0.61566, 0.60182, 0.58779, 0.57358, 0.55919, 0.54464, 0.52992, 0.51504, 0.5, 0.48481, 0.46947, 0.45399, 0.43837, 0.42262, 0.40674, 0.39073, 0.37461, 0.35837, 0.34202, 0.32557, 0.30902, 0.29237, 0.27564, 0.25882, 0.24192, 0.22495, 0.20791, 0.19081, 0.17365, 0.15643, 0.13917, 0.12187, 0.10453, 0.08716, 0.06976, 0.05234, 0.03490, 0.01745, 0.0};
//float outS[91] = {0, 0.01745, 0.03490, 0.05234, 0.06976, 0.08716, 0.10453, 0.12187, 0.13917, 0.15643, 0.17365, 0.19081, 0.20791, 0.22495, 0.24192, 0.25882, 0.27564, 0.29237, 0.30902, 0.32557, 0.34202, 0.35837, 0.37461, 0.39073, 0.40674, 0.42262, 0.43837, 0.45399, 0.46947, 0.48481, 0.5, 0.51504, 0.52992, 0.54464, 0.55919, 0.57358, 0.58779, 0.60182, 0.61566, 0.62932, 0.64279, 0.65606, 0.66913, 0.68200, 0.69466, 0.70711, 0.71934, 0.73135, 0.74314, 0.75471, 0.76604, 0.77715, 0.78801, 0.79864, 0.80902, 0.81915, 0.82904, 0.83867, 0.84805, 0.85717, 0.86603, 0.87462, 0.88295, 0.89101, 0.89879, 0.90631, 0.91355, 0.92050, 0.92718, 0.93358, 0.93969, 0.94552, 0.95106, 0.95630, 0.96126, 0.96593, 0.97030, 0.97437, 0.97815, 0.98163, 0.98481, 0.98769, 0.99027, 0.99255, 0.99452, 0.99619, 0.99756, 0.99863, 0.99939, 0.99985, 1};
float outSEC[] = {1, 1.000152, 1.000610, 1.001372, 1.002442, 1.003820, 1.005508, 1.007510, 1.009828, 1.012465, 1.015427, 1.018717, 1.022341, 1.026304, 1.030614, 1.035276, 1.040299, 1.045692, 1.051462, 1.057621, 1.064178, 1.071145, 1.078535, 1.086360, 1.094636, 1.103378, 1.112602, 1.122326, 1.132570, 1.143354, 1.154701, 1.166633, 1.179178, 1.192363, 1.206218, 1.220775, 1.236068, 1.252136, 1.269018, 1.286760, 1.305407, 1.325013, 1.345633, 1.367327, 1.390164, 1.414214, 1.439557, 1.466279, 1.494477, 1.524253, 1.555724, 1.589016, 1.624269, 1.661640, 1.701302, 1.743447, 1.788292, 1.836078, 1.887080, 1.941604, 2.000000, 2.062665, 2.130054, 2.202689, 2.281172, 2.366202, 2.458593, 2.559305, 2.669467, 2.790428, 2.923804, 3.071553, 3.236068, 3.420304, 3.627955, 3.863703, 4.133565, 4.445411, 4.809734, 5.240843, 5.758770, 6.392453, 7.185297, 8.205509, 9.566772, 11.4737, 14.3356, 19.1073, 28.6537, 57.2987, 75.0000};


void setup() {
  pinMode(rly7, OUTPUT); // hammer on off
  pinMode(toggle1Pin, INPUT);// override
  pinMode(toggle2Pin, INPUT);// bypass
  pinMode(23, OUTPUT);// yellow LED override
  pinMode(25, OUTPUT);// red LED hammer off
  pinMode(27, OUTPUT);// green LED hammer on
  pinMode(29, OUTPUT);// blue LED bypass
  Serial.begin(9600);
  Serial.print(F("Start screen"));
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print(F("Start screen")); // print a simple message
  delay(1500); // allows startup text to remain on screen long enough to read
  pinMode(echoPin, INPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(toggle1Pin, INPUT);
  pinMode(toggle2Pin, INPUT);
  digitalWrite(rly7, LOW); // sets initial relay state to allow hammer to operate

}

void loop() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.035 / 2;
  val = analogRead(potPin) / 6.0;  // read the value from the sensor and divide to show degrees
  val1 = analogRead(potPin);
  val2 = x;
  val3 = y;
  val4 = analogRead(groundPin);
  val5 = z;
  // x = outC[val];
  //  y = outS[val];
  z = outSEC[val];
  toggle1State = digitalRead(toggle1Pin);
  toggle2State = digitalRead(toggle2Pin);
  groundState = analogRead(groundPin);
  if (toggle2State == HIGH ) // case 0 Override on
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(27, HIGH); // green led on
    digitalWrite(23, HIGH); // yellow led on
    digitalWrite(25, LOW); // red led off
    digitalWrite(29, LOW); // blue led off
  }
  else if (groundState < 1000 && toggle1State == HIGH) // no contact, bypass on
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(27, HIGH); // green led on
    digitalWrite(23, LOW); // yellow led on
    digitalWrite(25, LOW); // red led off
    digitalWrite(29, HIGH); // blue led on
  }
  else if (groundState < 1000 && toggle2State == LOW && toggle1State == LOW) // case 1 no contact with steel, override off, bypass off
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(27, HIGH); // green LED on
    digitalWrite(23, LOW); // yellow led off
    digitalWrite(29, LOW); // blue led off
    digitalWrite(25, LOW); // red led off
  }
  else if (groundState > 1000 && val5 < 50 && toggle1State == LOW && toggle2State == LOW) // case 2 contact with steel, too close, bypass off, override off
  {
    digitalWrite(7, HIGH); // hammer off
    digitalWrite(27, LOW); // green LED off
    digitalWrite(25, HIGH); // red LED on
    digitalWrite(23, LOW); // yellow led off
    digitalWrite(29, LOW); // blue led off
  }
  else if (groundState > 1000 && val5 < 50 && toggle2State == HIGH) // case 3 contact with steel, too close,override on
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(23, HIGH); // yellow LED on
    digitalWrite(27, HIGH); // green LED on
  }
  else if (groundState > 1000 && toggle1State == HIGH && toggle2State == LOW) // case 4 contact with steel, bypass on, override off (ignores distance)
  {
    digitalWrite(7, HIGH); // hammer off
    digitalWrite(25, HIGH); // red LED on
    digitalWrite(27, LOW); // green LED off
    digitalWrite(29, HIGH); // blue LED on
  }

  lcd.setCursor(9, 1);           // move cursor to second line "1" and 9 spaces over
  //val = analogRead(potPin) / 3.78;  // read the value from the sensor and divide to show degrees removed for real setup
   x = outC[val];
  //  y = outS[val];
  z = outSEC[val];
  val = analogRead(potPin) / 5.0;  // read the value from the sensor and divide by 5 to conver to degrees
  val1 = analogRead(potPin); // used this to see what the potentiometer was reading
  val2 = x;
  val3 = y;
  val4 = analogRead(groundPin);
  val5 = z; // gives the secant of the angle
  //val5 = ((((distance + refrac) * z ) - 16.5) * y); // this math may need correcting (16.5 is arbitrary length of hammer, // removed distancecentimeters replaced with distance
  //val5 = (distance + refrac)*z;
  hyp1 = ((distance + refrac) * val5); // calculates the first hypoteneuse by multiplying the secant of the angle by distance returned from ultrasound plus thickness of refrac
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.print("secant");
  lcd.setCursor(0, 1);
  //lcd.print(((distanceCentimeters / x) - 16.5) *y);
  lcd.print (val5);
  //Serial.print(f("Pot pin  "));
  //Serial.println(val1);
  Serial.print(F("Angle  "));
  Serial.println(val);
  Serial.print("secant  ");
  Serial.println(val5 * 1000);
  Serial.print("cosine  ");
  Serial.println(val2 * 1000);
 // Serial.print("US actual  ");
 // Serial.println(distance);
 // Serial.print("ADJ1  "); // replaced distance centimeters with distance
//  Serial.println(distance + refrac);
 // Serial.print("HYP1  ");
 // Serial.println(hyp1);
  delay(1000);
}

instead of val1, val2, val3, z, x... Why don't you give those variables some names that indicate what they hold so I don't have to keep going back up to look. It would certainly make this easier to debug.

Why don't you also post some of your output that illustrates the problem.

Will do, thanks.

1023/3.78 = 270. There are only 91 (0-90) entries in outC.

1023/6 = 170. There are fewer than 170 entries in outSEC.

Either the divisor is wrong or you need to add code to perform bounds checking.

At the moment, I am ignoring angles greater than 89 degrees (the hammer will not exceed).

I am ignoring angles greater than 89 degrees

But you forgot to tell the Arduino about that.

Debug program lines will reveal the problem, as follows:

   if (val > 90) Serial.println("Array bound exceeded in outC");
   else x = outC[val];

I realize that will become an issue, one that I am not sure how to deal with yet. At the moment, my angle sensor is not exceeding 89 degrees so the arduino isn't looking for data beyond that.

Here is the cleaned up code (better labels) and also attached is a screenshot of the serial monitor…

//#include <avr/pgmspace.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(38, 42, 22, 26, 30, 34);
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0); 
}
const int refrac = 15;
int groundPin = 5;
int groundState = 0;
int rly7 = 7; // LOW = hammer on
int toggle1Pin = 2; //this is override switch
int toggle1State = 0;
int toggle2Pin = 3; // this is bypass switch
int toggle2State = 0;
const int echoPin = 12;
const int trigPin = 13;
long duration;
int distance;
int potPin = 4;    // the input pin for the potentiometer
int angle = 0;       // variable to store the value coming from the sensor divided for angle
float anglePot = 0; // actual pot pin value
float cosine = 0;
float sine = 0;
float steelContact = 0;
float secant = 0;
float hyp1 = 0;
double x = 0;
double y = 0;
double z = 0;
float hyp2 = 0;
float outC[91] = {1, 0.99985, 0.99939, 0.99863, 0.99756, 0.99619, 0.99452, 0.99255, 0.99027, 0.98769, 0.98481, 0.98163, 0.97815, 0.97437, 0.97030, 0.96593, 0.96126, 0.95630, 0.95106, 0.94552, 0.93969, 0.93358, 0.92718, 0.92050, 0.91355, 0.90631, 0.89879, 0.89101, 0.88295, 0.87462, 0.86603, 0.85717, 0.84805, 0.83867, 0.82904, 0.81915, 0.80902, 0.79864, 0.78801, 0.77715, 0.76604, 0.75471, 0.74314, 0.73135, 0.71934, 0.70711, 0.69466, 0.68200, 0.66913, 0.65606, 0.64279, 0.62932, 0.61566, 0.60182, 0.58779, 0.57358, 0.55919, 0.54464, 0.52992, 0.51504, 0.5, 0.48481, 0.46947, 0.45399, 0.43837, 0.42262, 0.40674, 0.39073, 0.37461, 0.35837, 0.34202, 0.32557, 0.30902, 0.29237, 0.27564, 0.25882, 0.24192, 0.22495, 0.20791, 0.19081, 0.17365, 0.15643, 0.13917, 0.12187, 0.10453, 0.08716, 0.06976, 0.05234, 0.03490, 0.01745, 0.0};
//float outS[91] = {0, 0.01745, 0.03490, 0.05234, 0.06976, 0.08716, 0.10453, 0.12187, 0.13917, 0.15643, 0.17365, 0.19081, 0.20791, 0.22495, 0.24192, 0.25882, 0.27564, 0.29237, 0.30902, 0.32557, 0.34202, 0.35837, 0.37461, 0.39073, 0.40674, 0.42262, 0.43837, 0.45399, 0.46947, 0.48481, 0.5, 0.51504, 0.52992, 0.54464, 0.55919, 0.57358, 0.58779, 0.60182, 0.61566, 0.62932, 0.64279, 0.65606, 0.66913, 0.68200, 0.69466, 0.70711, 0.71934, 0.73135, 0.74314, 0.75471, 0.76604, 0.77715, 0.78801, 0.79864, 0.80902, 0.81915, 0.82904, 0.83867, 0.84805, 0.85717, 0.86603, 0.87462, 0.88295, 0.89101, 0.89879, 0.90631, 0.91355, 0.92050, 0.92718, 0.93358, 0.93969, 0.94552, 0.95106, 0.95630, 0.96126, 0.96593, 0.97030, 0.97437, 0.97815, 0.98163, 0.98481, 0.98769, 0.99027, 0.99255, 0.99452, 0.99619, 0.99756, 0.99863, 0.99939, 0.99985, 1};
float outSEC[] = {1, 1.000152, 1.000610, 1.001372, 1.002442, 1.003820, 1.005508, 1.007510, 1.009828, 1.012465, 1.015427, 1.018717, 1.022341, 1.026304, 1.030614, 1.035276, 1.040299, 1.045692, 1.051462, 1.057621, 1.064178, 1.071145, 1.078535, 1.086360, 1.094636, 1.103378, 1.112602, 1.122326, 1.132570, 1.143354, 1.154701, 1.166633, 1.179178, 1.192363, 1.206218, 1.220775, 1.236068, 1.252136, 1.269018, 1.286760, 1.305407, 1.325013, 1.345633, 1.367327, 1.390164, 1.414214, 1.439557, 1.466279, 1.494477, 1.524253, 1.555724, 1.589016, 1.624269, 1.661640, 1.701302, 1.743447, 1.788292, 1.836078, 1.887080, 1.941604, 2.000000, 2.062665, 2.130054, 2.202689, 2.281172, 2.366202, 2.458593, 2.559305, 2.669467, 2.790428, 2.923804, 3.071553, 3.236068, 3.420304, 3.627955, 3.863703, 4.133565, 4.445411, 4.809734, 5.240843, 5.758770, 6.392453, 7.185297, 8.205509, 9.566772, 11.4737, 14.3356, 19.1073, 28.6537, 57.2987, 75.0000};


void setup() {
  pinMode(rly7, OUTPUT); // hammer on off
  pinMode(toggle1Pin, INPUT);// override
  pinMode(toggle2Pin, INPUT);// bypass
  pinMode(23, OUTPUT);// yellow LED override
  pinMode(25, OUTPUT);// red LED hammer off
  pinMode(27, OUTPUT);// green LED hammer on
  pinMode(29, OUTPUT);// blue LED bypass
  Serial.begin(9600);
  Serial.print(F("Start screen"));
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print(F("Start screen")); // print a simple message
  delay(1500); // allows startup text to remain on screen long enough to read
  pinMode(echoPin, INPUT);
  pinMode(trigPin, OUTPUT);
  pinMode(toggle1Pin, INPUT);
  pinMode(toggle2Pin, INPUT);
  digitalWrite(rly7, LOW); // sets initial relay state to allow hammer to operate

}

void loop() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.035 / 2;
  angle = analogRead(potPin) / 6.0;  // read the value from the sensor and divide to show degrees
  anglePot = analogRead(potPin);
  cosine = x;
  sine = y;
  steelContact = analogRead(groundPin);
  secant = z;
   
  // x = outC[val];
  //  y = outS[val];
  z = outSEC[angle];
  toggle1State = digitalRead(toggle1Pin);
  toggle2State = digitalRead(toggle2Pin);
  groundState = analogRead(groundPin);
  if (toggle2State == HIGH ) // case 0 Override on
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(27, HIGH); // green led on
    digitalWrite(23, HIGH); // yellow led on
    digitalWrite(25, LOW); // red led off
    digitalWrite(29, LOW); // blue led off
  }
  else if (groundState < 1000 && toggle1State == HIGH) // no contact, bypass on
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(27, HIGH); // green led on
    digitalWrite(23, LOW); // yellow led on
    digitalWrite(25, LOW); // red led off
    digitalWrite(29, HIGH); // blue led on
  }
  else if (groundState < 1000 && toggle2State == LOW && toggle1State == LOW) // case 1 no contact with steel, override off, bypass off
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(27, HIGH); // green LED on
    digitalWrite(23, LOW); // yellow led off
    digitalWrite(29, LOW); // blue led off
    digitalWrite(25, LOW); // red led off
  }
  else if (groundState > 1000 && hyp2 < 50 && toggle1State == LOW && toggle2State == LOW) // case 2 contact with steel, too close, bypass off, override off
  {
    digitalWrite(7, HIGH); // hammer off
    digitalWrite(27, LOW); // green LED off
    digitalWrite(25, HIGH); // red LED on
    digitalWrite(23, LOW); // yellow led off
    digitalWrite(29, LOW); // blue led off
  }
  else if (groundState > 1000 && hyp2 < 50 && toggle2State == HIGH) // case 3 contact with steel, too close,override on
  {
    digitalWrite(7, LOW); // hammer on
    digitalWrite(23, HIGH); // yellow LED on
    digitalWrite(27, HIGH); // green LED on
  }
  else if (groundState > 1000 && toggle1State == HIGH && toggle2State == LOW) // case 4 contact with steel, bypass on, override off (ignores distance)
  {
    digitalWrite(7, HIGH); // hammer off
    digitalWrite(25, HIGH); // red LED on
    digitalWrite(27, LOW); // green LED off
    digitalWrite(29, HIGH); // blue LED on
  }

  lcd.setCursor(9, 1);           // move cursor to second line "1" and 9 spaces over
  //val = analogRead(potPin) / 3.78;  // read the value from the sensor and divide to show degrees removed for real setup
   x = outC[angle];
  //  y = outS[val];
  z = outSEC[angle];
  angle = analogRead(potPin) / 5.0;  // read the value from the sensor and divide by 5 to conver to degrees
  anglePot = analogRead(potPin); // used this to see what the potentiometer was reading
  cosine = x;
  sine = y;
  steelContact = analogRead(groundPin);
  secant = z; // gives the secant of the angle
  //val5 = ((((distance + refrac) * z ) - 16.5) * y); // this math may need correcting (16.5 is arbitrary length of hammer, // removed distancecentimeters replaced with distance
  //val5 = (distance + refrac)*z;
  hyp1 = ((distance + refrac) * secant); // calculates the first hypoteneuse by multiplying the secant of the angle by distance returned from ultrasound plus thickness of refrac
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.print("secant");
  lcd.setCursor(0, 1);
  //lcd.print(((distanceCentimeters / x) - 16.5) *y);
  lcd.print (secant);
  //Serial.print(f("Pot pin  "));
  //Serial.println(val1);
  Serial.print(F("Angle  "));
  Serial.println(angle);
  Serial.print("secant  ");
  Serial.println(secant * 1000);
  Serial.print("cosine  ");
  Serial.println(cosine * 1000);
 // Serial.print("US actual  ");
 // Serial.println(distance);
 // Serial.print("ADJ1  "); // replaced distance centimeters with distance
//  Serial.println(distance + refrac);
 // Serial.print("HYP1  ");
 // Serial.println(hyp1);
  delay(1000);
}

Hi, Can you post a diagram of your system please, so we can see the angles and distances.

Thanks.. Tom... :)

Attached is a diagram, measurements given are arbitrary (for the purpose of the diagram).
Inclinometer and ultrasonic transducer are both attached at the hammer pivot point, the inclinometer is rigidly attached so pendulum rotates the potentiometer and the ultrasonic transducer is mounted in a bearing with a counterweight to keep it pointed at 0 degrees to the wall surface.

Hi, What model Arduino are you using? Mega? What analog input are you using ? A0 , A1 A2? Change this

int potPin = 4;    // the input pin for the potentiometer

to

int potPin = A0;    // the input pin for the potentiometer

Or what ever your analog input is. The compiler will let you do it. Tom... :)

In response to JRemington's advice, I did add some code to prevent reading angles greater than 89 degrees. This prevents out of range issues but has not solved my primary problem... the lookup tables aren't matching up with the input angle.

You have two different readings for angle with different denominators.

angle = analogRead(potPin) / 6.0; 
angle = analogRead(potPin) / 5.0;

Serial.println(angle) is taken from the reading with 5 as the denominator, and I think that the secant = z value is taken from the reading with 6 as the denominator.

Hi,
Why are you reading the angle pot in two different parts of the code?

Read the pot ONCE at the START of the loop.
Calculate ALL your COS, SIN and SECANT IMMEDIATELY after that.

Then use those figures for the rest of the code.

I ran your code with extra serial prints and got the offset you had, until I commented out the second set of pot inputs.

Do all your cals in one at the start.

  anglePot = analogRead(potPin);
  angle = anglePot / 6.0;
  x = outC[angle];
  y = outS[angle];
  z = outSEC[angle];
  cosine = x;
  sine = y;
  secant = z;
  steelContact = analogRead(groundPin);

Hope it helps… Tom… :slight_smile:

In reply to TomGeorge, I am using a Mega2560. I also changed the code for the potentiometer pin from "4" to "A4", no change...

In response to Cattledog and Tom George, that solved it, thanks.

This should teach me a valuable lesson in cleaning up my code as I add or change things.

Thanks again to all who responded, this is the first time I asked for help with Arduino code and the response surprised me.

At a guess, you are not correctly turning the reading from your analog input into an angle.

For more accuracy and less hassle, initialise your lookup table in your setup() using the math functions that come with the arduino. This does mean that some program memory will be consumed by the math functions, but meh. If memory is really tight, then yes you will want to precompute this and put it in progmem instead.

Index your array not by a value in degrees, but by what the reading from your analogIn will be. If you don’t want your array to be 2k long (1024 * sizeof(float)), then index your array by what your analog input will be divided by 4, or 8, or some other power of 2. Using a power of 2 means there is less integer division aliasing going on.

Here’s a sample sketch. I put a pot on pin A0 to test - seems to work. Or to something reasonable, at least.

// we divide the reading on the pot pin by 8 to get an index into this table
float potPin2Cos[128];
float potPin2Sec[128];

void setup() {
  Serial.begin(9600);
  while(!Serial);

  Serial.println("i\tanalog\tdeg\tcos\tsec\t");
  
  for(int i=0; i<128;i++) {
    // we divide the reading by 8 to pack the gear into our array. 
    // So I add 4 to get an angle in the middle of the range
    int reading = i * 8 + 4;

    // in the original code, 
    // angle = analogRead(potPin) / 6.0
    // to give an angle in degrees. I will convert this to radians.
    
    float angle = reading / 6.0 / 90.0 * PI/2;
    potPin2Cos[i] = cos(angle);
    potPin2Sec[i] = 1/potPin2Cos[i];

    if(fabs(potPin2Sec[i]) > 75) potPin2Sec[i] = 75;

    Serial.print(i);
    Serial.print('\t');
    Serial.print(reading);
    Serial.print('\t');
    Serial.print(angle / 2 / PI * 360); // convert to degrees for display purposes
    Serial.print('\t');
    Serial.print(potPin2Cos[i]); 
    Serial.print('\t');
    Serial.print(potPin2Sec[i]); 
    Serial.println();
  }
  Serial.println();
}

uint32_t ms;

void loop() {
  if(millis() - ms > 1000) {
    int reading = analogRead(A0);
    Serial.print('\t');
    Serial.print(reading);
    Serial.print('\t');
    Serial.print(reading/6.0); // convert to degrees for display purposes
    Serial.print('\t');
    Serial.print(potPin2Cos[reading / 8]); 
    Serial.print('\t');
    Serial.print(potPin2Sec[reading / 8]); 
    Serial.println();
    ms = millis();
  }
}

– EDIT –

I could have use the map() function to turn the “reading divided by 8” into “angle measured in radians”. Also, for better accuracy you can do a linear interpolation. But, presumably you want speed.

int read_LCD_buttons()
{
  adc_key_in = analogRead(0);
}

Liar. You told the compiler that you’d return a value. You don’t.