Angle sensor evaluation kit issues

I have purchased this TMR, angle sensor evaluation kit. I want to understand how it works:

I have used example codes from NVE's YouTube and GitHub and I am having issues.

I have got a replacement unit, and it is still behaving in the exact same way. I have switched Arduinos and still, the exact same.

Exact issues:

  • At -90 degrees on the evaluation board, the sensor reads 80 degrees.
  • At +90 degrees on the eval board, the sensor reads 100 degrees.
  • 0 degrees and 180 degrees on the eval board are correct

Please see my code and serial monitor output below.

I am trying to understand the atan2 function and how it is even working at 0 degrees. Surely for 0.72 degrees, the sin value and cos value in the atan function need to result in 0? I.e. 600/600?

Once In understand the application at 0 degrees, I then plan to apply that to the 90 degree position and see where it is going wrong. I have added the serial monitor output at 90 degrees at the bottom as well.

Code:

int sinInput = 0;
int cosInput = 1;
int sinValue;
int cosValue;
int sinValueOff;
int cosValueOff;
int sinValueMin = 1023;
int cosValueMin = 1023;
int sinValueMax = 0;
int cosValueMax = 0;
int sinOffset;
int cosOffset;
float positionAngleRad;
float positionAngleDeg;
int i;

void setup() {
  Serial.begin(9600);
  Serial.println("Initialized");
  pinMode(sinInput, INPUT);
  pinMode(cosInput, INPUT);

  for(i=1; i <=30000; i++) {
    sinValue = analogRead(sinInput);
    cosValue = analogRead(cosInput);
    if (cosValue<cosValueMin) {
      cosValueMin = cosValue;
    }
    if (cosValue>cosValueMax) {
      cosValueMax = cosValue;
    }
    if (sinValue<sinValueMin) {
      sinValueMin = sinValue;
    }
    if (sinValue>sinValueMax) {
      sinValueMax = sinValue;
    }
  }
  sinOffset = (sinValueMax + sinValueMin)/2;
  cosOffset = (cosValueMax + cosValueMin)/2;
}

void loop() {
  sinValue = analogRead(sinInput);
  cosValue = analogRead(cosInput);
  sinValueOff = sinValue - sinOffset;
  cosValueOff = cosValue - cosOffset;

  positionAngleRad = atan2f(float(cosValueOff),float(sinValueOff));
  positionAngleDeg = (positionAngleRad * 180) / 3.141592654;

  Serial.print ("Degrees: ");
  Serial.print (positionAngleDeg);
  Serial.print ("     ");
  Serial.print ("Radians: ");
  Serial.print (positionAngleRad);
  Serial.print ("     ");
  Serial.print ("Sin Value: ");
  Serial.print (sinValue);
  Serial.print ("     ");
  Serial.print ("Sin w/Offset: ");
  Serial.print (sinValueOff);
  Serial.print ("     ");
  Serial.print ("sinValueMin: ");
  Serial.print (sinValueMin);
  Serial.print ("     ");
  Serial.print ("sinValueMax: ");
  Serial.print (sinValueMax);
  Serial.print ("     ");
  Serial.print ("Cos Value: ");
  Serial.print (cosValue);
  Serial.print ("     ");
  Serial.print ("Cos w/Offset: ");
  Serial.print (cosValueOff);
  Serial.print ("     ");
  Serial.print ("cosValueMin: ");
  Serial.print (cosValueMin);
  Serial.print ("     ");
  Serial.print ("cosValueMax: ");
  Serial.println (cosValueMax);
}

Serial Monitor Output at 0 degrees (Single Line):

Degrees: 0.72     Radians: 0.01     Sin Value: 597     Sin w/Offset: 80     sinValueMin: 430     sinValueMax: 604     Cos Value: 511     Cos w/Offset: 1     cosValueMin: 419     cosValueMax: 602

Serial Monitor Output at +90 degrees (Single Line):

Degrees: 100.58     Radians: 1.76     Sin Value: 500     Sin w/Offset: -17     sinValueMin: 430     sinValueMax: 604     Cos Value: 601     Cos w/Offset: 91     cosValueMin: 419     cosValueMax: 602

The for statement in the setup is there to "calibrate the sensor".

I rotate the magnet around and the code calculates the max and min readings for the sensor outputs. These are then used to calculate the offsets, which can then be used to normalise the reading later on.

I understand atan2 gives the angle in radians, hence in the inclusion of degrees and radians in the serial monitor and my conversion.

I understand atan2f produces the output as a float instead of a double.

Looks like the calibration is not done correctly. The sin term should be zero if the angle truly is zero degrees, and the cos term should be 1 (after normalization).

With the atan2 function, normalization of the X and Y terms are not required, but you should make sure that the offset-corrected minimum and maximum values of each are the same as you go around the compass rose. If they aren't, a relative scale factor is also required.

This is basically the same as calibrating a magnetometer, but in 2D. See this excellent overview and comprehensive tutorial on that topic.

Thanks for your help.

This has woke me up to realise what I should be expecting from the sin and cos outputs.

I will assess the outputs and their offsets again.

I have read the link you have sent. Quite complex. I appreciate it is related, but I think my issue might but a lack of understanding of the atan2 function and the requirements from my sensor. Like I said, following your advise, I will look at the sin output at 0 degrees.

atan2() is just the inverse tangent function, but rather than taking a single value of Y/X as input, they are kept separate to allow the angle quadrant to be distinguished.

Where MAX V is the maximum output of the sensor, MIN V is the minimum output, and 0V is the 0V offset:

Sensor outputs SHOULD be:
@ 0 degrees: Sin = 0V, Cos = MAX V
@ 90 deg: Sin = MAX V, Cos = 0V
@180 deg: Sin = 0V, Cos = MIN V
@270 deg: Sin = MIN V, Cos = 0V
@360 deg: Sin = 0V, Cos = MAX V

Therefore, given the following, I believe I am using atan2 the wrong way around with my X and Y. But I do not understand how NVE have got their demos to work with this evaluation board. I am using their code, with the serial monitor additions to the code, and I have changed the pins used. I cannot see I have made any mistakes with the pins.

I believe this because of the readings I am getting on the serial monitor:

Sin:
Max = 604, Min = 430. Middle (0V offset) = 517.
E.g. 0 deg should be 517. (However, I get 597)

Cos:
Max = 602, Min - 419. Middle (0V offset) = 510.5.
E.g. 0 deg should be 602. (However, I get 511)

It does appear that you have the X and Y input terms reversed.

See this atan2 reference

Where MAX V is the maximum output of the sensor, MIN V is the minimum output

The actual values of MAX V and MIN V should be the same (positive and negative after offset correction).

Sorry if this is a stupid question, but how am I supposed to determine whether the sin or the cos equates to the X or the Y please?

In the demo code, they have it set up in the configuration I have used in the code given. I know that they could have it wrong also. I am just trying to understand sorry.

Y is usually the sine term, X is cosine.

angle in radians = atan2(Y, X)

Capture

1 Like

There are some variations due to the electrical differences in the sensor. This is stipulated in some of the demos, and the MAX and MIN V for Sin and Cos is calculated as a result.

Of course there are sensor to sensor variations. Proper calibration should correct those, to the best of your ability.

After correcting the atan2, X and Y assignments, I now have 0 degrees as we discussed that I should have.

Degrees: 0.00     Radians: 0.00     Sin Value: 509     Sin w/Offset: 0     sinValueMin: 425     sinValueMax: 593     Cos Value: 595     Cos w/Offset: 90     cosValueMin: 414     cosValueMax: 596

However, the +/- 90 degree issue persists:

+90 deg:

Degrees: 101.31     Radians: 1.77     Sin Value: 599     Sin w/Offset: 90     sinValueMin: 425     sinValueMax: 593     Cos Value: 487     Cos w/Offset: -18     cosValueMin: 414     cosValueMax: 596

-90 deg:

Degrees: -79.92     Radians: -1.39     Sin Value: 419     Sin w/Offset: -90     sinValueMin: 425     sinValueMax: 593     Cos Value: 521     Cos w/Offset: 16     cosValueMin: 414     cosValueMax: 596

I thought I would slowly change the angle and examine the output. Weird results:

Going from 30 degrees to 50 degrees, produces a 30 to 60 degree change.

So in the 30 to 50 degree arc, I am gaining another 10 degrees.

Going from -30 to -60, produces a -30 to -50 degree change.

So in the -30 to -50 degree arc, I am loosing 10 degrees.

Plot the corrected X, Y values as you go around the compass circle. In the ideal case, they form a circle, centered on the origin. If not, either the calibration results are wrong, or they were incorrectly applied.

Example of perfect calibration:

See this page for other examples: Learn more about magnetometer models and HSI calibration ยท VectorNav

1 Like

That plot shows a soft iron distortion, which can be corrected using this math-heavy approach (the Matlab code runs on Gnu Octave).

https://forum.sparkfun.com/viewtopic.php?t=36399

Unfortunately the Sparkfun forum lost the image files.

You might look for current carrying wires, or magnetic materials near the sensor, as either can induce that rotation.

This was achieved using another version of the OEM demo code:

angle = atan2(float(AATsin)/(AATsinmax-AATsinmin),float(AATcos)/(AATcosmax-AATcosmin)); //Calculate angle

I would like to say again, thank you so much for your help.

In regard to this issue, in your experience, would this issue be present on all batches of these sensors?

NVE sell these eval kits and the sensors using their demos which I will link below. In absolutely none of their materials do they demonstrate any of the issues I am having/what you are helping me with.

I have no idea, but do look carefully at your setup for possible problems with current carrying wires or magnetic materials near the sensor, like the Neopixel strip surrounding the sensor in the video link above.

If you post a set of X,Y values, I will run it through the correction procedure described in the Sparkfun link, and see how it goes. Copy/paste into code tags.

Do you have MATLAB, to carry out the instructions I am guessing?

XY Values from the spreadsheet of the second XY Plot:

-3	98
-3	98
-3	98
-3	98
-2	98
-2	98
-2	98
-2	98
-2	98
0	98
0	98
0	98
0	98
0	98
1	98
2	98
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
2	97
3	98
3	98
3	98
2	98
2	97
2	98
2	98
2	98
2	98
2	97
2	98
2	98
2	98
0	98
0	98
0	98
0	98
0	98
0	98
0	98
2	98
5	97
10	96
18	95
30	91
43	84
57	74
67	62
72	54
75	51
77	48
79	45
82	41
85	36
88	31
91	24
93	19
95	13
96	9
97	4
97	0
98	-5
98	-10
98	-14
97	-19
97	-23
97	-26
96	-28
96	-30
95	-32
94	-35
94	-38
93	-40
92	-42
91	-45
90	-50
88	-54
86	-57
85	-59
83	-62
81	-65
78	-69
75	-73
71	-76
68	-79
65	-82
60	-85
56	-88
51	-90
45	-93
36	-96
26	-98
18	-99
12	-99
6	-99
0	-98
-7	-97
-13	-96
-16	-95
-20	-93
-24	-92
-28	-91
-33	-88
-38	-86
-43	-83
-49	-80
-55	-76
-59	-72
-64	-68
-68	-63
-70	-59
-71	-57
-73	-54
-75	-51
-77	-47
-79	-44
-81	-41
-83	-37
-85	-33
-88	-29
-89	-25
-91	-22
-92	-18
-93	-15
-94	-11
-95	-7
-96	-4
-96	-1
-97	3
-97	8
-97	12
-97	16
-97	21
-96	26
-95	30
-95	32
-95	33
-94	33
-94	35
-94	36
-94	36
-94	36
-94	37
-94	37
-94	37
-93	38
-93	40
-92	42
-91	44
-90	48
-87	52
-86	55
-85	57
-83	59
-81	63
-77	68
-75	71
-73	73
-71	75
-69	76
-67	78
-64	80
-62	82
-60	83
-58	85
-56	86
-54	87
-51	89
-48	90
-45	92
-42	92
-40	94
-36	95
-32	96
-29	96
-26	97
-23	97
-19	98
-15	98
-12	98
-9	98
-6	98
-4	98
-1	98
2	98
6	97
9	96
13	96
16	95
19	94
22	93
24	93
28	91
37	87
53	78
63	68
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	61
67	62
68	61
68	61
68	61
69	59
70	57
72	55
73	53
75	51
76	49
80	45
85	36
89	29
92	22
94	16
95	11
96	8
97	4
97	1
97	-1
98	-6
98	-10
98	-15
98	-18
97	-21
97	-25
96	-29
95	-33
94	-36
93	-40
92	-44
90	-48
89	-51
88	-54
87	-56
86	-57
85	-59
83	-61
82	-64
80	-67
78	-69
76	-72
73	-75
69	-78
65	-82
61	-85
56	-88
50	-91
43	-94
34	-96
27	-98
25	-98
19	-99
11	-99
2	-98
-8	-97
-16	-95
-22	-93
-31	-89
-39	-85
-48	-80
-58	-73
-64	-69
-67	-66
-68	-63
-70	-60
-71	-56
-72	-54
-75	-50
-76	-48
-78	-44
-81	-39
-85	-34
-89	-26
-90	-22
-91	-20
-92	-18
-93	-15
-94	-10
-95	-6
-96	-1
-97	2
-97	7
-97	13
-97	17
-97	20
-96	23
-96	27
-95	30
-94	34
-94	36
-93	37
-93	39
-93	40
-92	40
-92	41
-92	43
-91	45
-90	46
-89	48
-88	51
-86	55
-83	60
-81	63
-78	67
-75	71
-70	76
-64	81
-58	85
-52	88
-48	90
-45	92
-40	94
-32	96
-25	97
-17	98
-10	98
-3	98
4	97
11	96
14	96
17	95
19	94
20	94
24	93
29	91
33	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
34	89
35	88
35	88
36	88
41	85
49	81
55	77
59	73
65	64
71	56
79	45
85	38
88	30
92	21
95	11
97	0
98	-10
97	-20
96	-31
93	-42
88	-53
83	-62
76	-71
70	-78
63	-84
54	-89
45	-93
35	-96
25	-98
14	-99
2	-98
-11	-96
-25	-92
-33	-88
-42	-84
-52	-78
-62	-71
-68	-63
-71	-59
-73	-54
-77	-47
-82	-38
-87	-30
-90	-24
-91	-21
-92	-18
-93	-13
-95	-6
-97	1
-97	6
-97	11
-97	16
-97	22
-95	29
-94	34
-93	38
-92	42
-89	48
-85	57
-80	64
-77	68
-75	71
-70	75
-65	80
-60	83
-56	86
-52	88
-47	91
-40	94
-33	96
-29	96
-27	97
-25	97
-22	98
-19	98
-16	98
-13	98
-10	98
-4	98
0	98
2	97
3	97
3	97
8	97
11	96
12	96
12	96
16	95
18	94
20	93
21	93
20	93
21	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
21	93
20	93
21	93
21	93
20	93
21	93
20	93
20	93
21	93
21	93
20	93
21	93
20	93
21	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
21	93
20	93
21	93
20	93
21	93
20	93
21	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
20	93
21	93
20	93
20	93
20	93
21	93
20	93
21	93
20	93
20	93
20	93
20	93