2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
[![Arduino CI](https://github.com/RobTillaart/AverageAngle/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
2021-12-13 14:51:57 -05:00
|
|
|
[![Arduino-lint](https://github.com/RobTillaart/AverageAngle/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/AverageAngle/actions/workflows/arduino-lint.yml)
|
|
|
|
[![JSON check](https://github.com/RobTillaart/AverageAngle/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/AverageAngle/actions/workflows/jsoncheck.yml)
|
2021-01-29 06:31:58 -05:00
|
|
|
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AverageAngle/blob/master/LICENSE)
|
|
|
|
[![GitHub release](https://img.shields.io/github/release/RobTillaart/AverageAngle.svg?maxAge=3600)](https://github.com/RobTillaart/AverageAngle/releases)
|
|
|
|
|
2021-12-13 14:51:57 -05:00
|
|
|
|
2020-11-27 05:10:47 -05:00
|
|
|
# AverageAngle
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-12-13 14:51:57 -05:00
|
|
|
Arduino library to calculate correctly the average of multiple angles.
|
2020-11-27 05:10:47 -05:00
|
|
|
|
2021-10-18 15:44:20 -04:00
|
|
|
|
2020-11-27 05:10:47 -05:00
|
|
|
## Description
|
|
|
|
|
2022-10-29 07:59:29 -04:00
|
|
|
AverageAngle is a class to calculate the average of angles.
|
2020-11-27 05:10:47 -05:00
|
|
|
|
|
|
|
This is especially useful when angles are around 0 degrees,
|
|
|
|
e.g. from a compass sensor or the resultant of a track.
|
|
|
|
Example, the average angle of 359 and 1 is 0, not 179 (most of the time)
|
|
|
|
|
2021-12-13 14:51:57 -05:00
|
|
|
Furthermore the AverageAngle can also include the **length (weight)** of the angle as if it is a vector.
|
|
|
|
Default this length is set to 1 so all angles are by default of equal weight.
|
2020-11-27 05:10:47 -05:00
|
|
|
|
2021-12-13 14:51:57 -05:00
|
|
|
Example: The average angle of 359 (length = 2) and 1 (length = 1) is 359.something not zero.
|
2020-11-27 05:10:47 -05:00
|
|
|
|
2022-12-07 14:30:13 -05:00
|
|
|
The average angle is calculated by converting the added angle (in DEGREES, etc) to polar coordinates.
|
|
|
|
These (x,y) are added to a (sumX, sumY) and divided by the number of angles added so far.
|
|
|
|
|
|
|
|
|
|
|
|
#### Related to
|
|
|
|
- https://github.com/RobTillaart/Angle
|
|
|
|
- https://github.com/RobTillaart/AngleConvertor
|
|
|
|
- https://github.com/RobTillaart/runningAngle
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-10-18 15:44:20 -04:00
|
|
|
|
2022-10-29 07:59:29 -04:00
|
|
|
#### AngleType
|
|
|
|
|
2022-12-07 14:30:13 -05:00
|
|
|
- **enum AngleType { DEGREES, RADIANS, GRADIANS }** idem.
|
2022-10-29 07:59:29 -04:00
|
|
|
|
2022-12-07 14:30:13 -05:00
|
|
|
| value | name | range |
|
|
|
|
|:-------:|:-----------|:-----------|
|
|
|
|
| 0 | DEGREES | 0 .. 360 |
|
|
|
|
| 1 | RADIANS | 0 .. 2PI |
|
|
|
|
| 2 | GRADIANS | 0 .. 400 | 100 GRADIANS == 90 DEGREES.
|
2022-10-29 07:59:29 -04:00
|
|
|
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
## Interface
|
|
|
|
|
|
|
|
- **AverageAngle(AngleType type = DEGREES)** constructor defaults to degrees.
|
2022-12-07 14:30:13 -05:00
|
|
|
- **uint32_t add(float alpha, float length = 1.0)** add a new angle,
|
|
|
|
optional with length other than 1.
|
|
|
|
Returns the number of elements (count).
|
|
|
|
- **void reset()** clears internal counters.
|
2021-10-18 15:44:20 -04:00
|
|
|
- **uint32_t count()** the amount of angles added.
|
2022-12-07 14:30:13 -05:00
|
|
|
If count == 0, there is no average.
|
|
|
|
- **float getAverage()** returns the average, unless count == 0
|
|
|
|
or the internal sums == (0,0) in which case we have a singularity ==> NAN (not a number)
|
2022-10-29 07:59:29 -04:00
|
|
|
- **float getTotalLength()** the length of the resulting 'angle' when we see them as vectors.
|
2022-12-07 14:30:13 -05:00
|
|
|
If count == 0 ==> total length = 0.
|
2021-10-18 15:44:20 -04:00
|
|
|
- **float getAverageLength()** returns the average length of the angles added.
|
2022-12-07 14:30:13 -05:00
|
|
|
If count == 0 ==> average length = 0.
|
2022-10-29 07:59:29 -04:00
|
|
|
- **AngleType type()** returns DEGREES, RADIANS or GRADIANS.
|
2021-10-18 15:44:20 -04:00
|
|
|
- **void setType(AngleType type)** changes type DEGREES, RADIANS or GRADIANS.
|
2022-12-07 14:30:13 -05:00
|
|
|
Type can be changed run time and still continue to add.
|
2021-10-18 15:44:20 -04:00
|
|
|
|
|
|
|
|
|
|
|
## Gradians
|
|
|
|
|
2022-10-29 07:59:29 -04:00
|
|
|
Gradians a.k.a. **gon**, is a less often used unit for angles.
|
2021-12-13 14:51:57 -05:00
|
|
|
There are 100 gradians in a right angle. A full circle = 400 gradians.
|
2021-10-18 15:44:20 -04:00
|
|
|
|
|
|
|
https://en.wikipedia.org/wiki/Gradian
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2020-11-27 05:10:47 -05:00
|
|
|
|
|
|
|
## Operation
|
|
|
|
|
|
|
|
If you want to average 5 compass readings you can just add the angles and
|
|
|
|
do not use the length parameter.
|
2021-12-13 14:51:57 -05:00
|
|
|
```cpp
|
2020-11-27 05:10:47 -05:00
|
|
|
AA.reset();
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
AA.add(compass.readHeading());
|
2021-10-18 15:44:20 -04:00
|
|
|
delay(100); // e.g. compass read needs some time
|
2020-11-27 05:10:47 -05:00
|
|
|
}
|
|
|
|
Serial.println(AA.getAverage());
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2021-10-18 15:44:20 -04:00
|
|
|
If you want to average a track, e.g. 5 steps North, 3 steps west etc,
|
|
|
|
you need to include the length of each step.
|
2021-12-13 14:51:57 -05:00
|
|
|
```cpp
|
2020-11-27 05:10:47 -05:00
|
|
|
AA.reset();
|
2021-10-18 15:44:20 -04:00
|
|
|
AA.add(90, 5); // 5 steps north
|
|
|
|
AA.add(180, 3); // 3 steps west
|
2020-11-27 05:10:47 -05:00
|
|
|
Serial.println(AA.getAverage());
|
|
|
|
Serial.println(AA.getTotalLength());
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2022-12-07 14:30:13 -05:00
|
|
|
If you want to average an angle in DEGREES and an angle in RADIANS,
|
|
|
|
just change the type runtime.
|
|
|
|
```cpp
|
|
|
|
AA.reset();
|
|
|
|
AA.setType(DEGREES);
|
|
|
|
AA.add(90);
|
|
|
|
AA.setType(RADIANS);
|
|
|
|
AA.add(PI/3);
|
|
|
|
AA.setType(DEGREES);
|
|
|
|
Serial.println(AA.getAverage());
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Warning
|
|
|
|
|
|
|
|
As the internal representation has a limited resolution (float) it can occur that when
|
|
|
|
the internal values are large, one cannot add a very small angle any more.
|
|
|
|
Did not encounter it yet myself.
|
|
|
|
|
|
|
|
|
2021-10-18 15:44:20 -04:00
|
|
|
## Future
|
|
|
|
|
2022-12-07 14:30:13 -05:00
|
|
|
#### Must
|
|
|
|
|
|
|
|
#### Should
|
|
|
|
|
|
|
|
#### Could
|
|
|
|
- add a USER AngleType, in which the user can map 0..360 degrees to any range.
|
2022-10-29 07:59:29 -04:00
|
|
|
- float userFactor = 1.0; (default)
|
|
|
|
- can even be negative?
|
|
|
|
- use cases? e.g 0..4 quadrant?
|
2020-11-27 05:10:47 -05:00
|
|
|
|