# Scale Magnometer to Servo

I'm trying to determine what is the best way to scale a magnometer to a servo, I am using the BNO055 from Bosch I get a heading say 50 degrees, and I want to be able to input 45 degrees and have the servo motor move accordingly. I am using a 180 degree motor. I would like to be able to input 45 degrees, and then the motor if 50 degrees was 95, would decrease in value step by step until the magnometer read 45; I'm having difficulty creating the logic to do this.

Bosch output is between 0 and 360; so I could end up with servo 0 is 120; and servo 180 is 300. Meaning the values are 300 - 360, 0 - 120 making the full 180, so I am not sure how I could use something like map in arduino to solve this issue.

Okay, lets say the output of your BNO055 is called `x` and the value for your servo is `y`. We need to translate `x` to `y` and you are correct to use the `map()` function. But what you are forgetting is that you do not need to map all the values of `x` to all the values of `y`. You can split it up.

In your example the values of the BNO055 relate to the servo as follows:

``````x   | y
0   | 0
120 | 0
300 | 180
360 | 180
``````

The servo only rotates from 0 degrees to 180 degrees between the BNO055 sensor values of 120 and 300. So you only need to map those values, while all values below should result in 0 and all values above should result in 180 degrees for the servo.

This translates into the following code:

``````//x is the output of BNO055 sensor
if(x < 120){
servo.write(0);
}
if(x > 300){
servo.write(180);
}
if(x > 120 && x < 300){
y = map(x, 120, 300, 0, 180);
servo.write(y);
}
``````

Another way of coding this is:

``````if(x < 120){
servo.write(0);
}
else if(x > 300){
servo.write(180);
}
else{
y = map(x, 120, 300, 0, 180);
servo.write(y);
}
``````
• It's hard to tell from the question, but I got the impression the OP wanted 300-360 to map to 0-60 and 0-120 to 60-180, which means wrapping the values first to be -60 to +120.
– Majenko
Jul 13 '16 at 14:28
• Now I'm confused, haha. Regardless what OP's desired data is, I hope this code shows him he is able to specify ranges of `map()` instead of just mapping everything.
– Len
Jul 13 '16 at 14:32
• @Len is correct to clarify the sensor reads 0 to 360; and for the example we have 300 to 360 and then 0 to 120 because the sensor wraps around - so my plan was to set the servo to 0 get the min reading which was 300 and 180 is 120 so then I need to map for those values so I'm guessing that means I would map like 0 to 60 for 300 to 360 and 60 to 180 for 0 to 120; does that make sense for map function? Jul 13 '16 at 15:20
• Yes, you can reverse map values. Say you need to map 0, 100 to 10,0 you just reverse the last two variables of `map()` as follows `map(x, 0, 100, 10, 0);` Also, about the servo. You don't need to manually change the position of the servo. Servo's are made to rotate to a specific location and know at what position they are, even if they just got power.
– Len
Jul 15 '16 at 7:02

You need to remember that you are working with a circle. You have degrees 0 to 360, but only if counting clockwise. If you work anticlockwise you also have degrees 0 to -360.

So your angles of interest are, clockwise from 0, 0-120, and anti-clockwise from 0, 0 to -60

To make things easier on you you need to create a range that is wrapped around so that anything in the "left" half of the circle is counted as anticlockwise from 0 and anything in the "right" half of the circle is counted clockwise from 0.

So values 0-180 are 0-180, but values of 180 to 360 are -128 to 0. Then your entire range spreads from -180 to +180 instead of 0-360 (if that makes sense).

It's simple enough:

``````if (angle > 180) angle = 0 - (360 - angle);
``````

So if `angle` is 300 you get:

``````0 - (360 - 300) = 0 - 60 = -60
``````

If `angle` is 330 you get:

``````0 - (360 - 330) = 0 - 30 = -30
``````

Now you can map the new values using the `map` function @Len has detailed above:

``````servo = map(angle, -60, 120, 0, 180);
``````

It is also possible to combine it all into one line should you wish, using the C "inline if" format:

``````servo = map((angle > 180 ? (0 - (360 - angle)) : angle), -60, 120, 0, 180);
``````

But that is kind of cryptic :)

• Excellent this solution I believe will solve it - unfortunately during the test of this solution I ended up burning out the servo motor itself :P So now I'll have to try again sometime next week, will keep this updated. Jul 15 '16 at 1:49