0

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.

2 Answers 2

1

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);
}
4
  • 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, 2016 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, 2016 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?
    – eWizardII
    Jul 13, 2016 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, 2016 at 7:02
1

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 :)

1
  • 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.
    – eWizardII
    Jul 15, 2016 at 1:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.