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
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– Majenko2016年07月13日 14:28:04 +00:00Commented 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– Len2016年07月13日 14:32:10 +00:00Commented 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– eWizardII2016年07月13日 15:20:28 +00:00Commented 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 followsmap(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– Len2016年07月15日 07:02:21 +00:00Commented Jul 15, 2016 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.eWizardII– eWizardII2016年07月15日 01:49:34 +00:00Commented Jul 15, 2016 at 1:49