Servo Mapper

There was a lot of discution about the servo mapper this week-end and we did not seem to found a consensus how to fix the problem related the it's usage.

To have the servo service work properly, the user should be able to

  • map the range they are using to the position the servo should take
  • modify the limits a servo should have 
  • Set and get any parameters about the servo in the range they are using (input)

The problem with the current implementation of the mapper is that the limits (min/max) are set on the output wich lead to many confusion and logic problems

by example, if I have a map(0,90,90,180) 

If I want to limits the range from 0-90 to 10-90... I must use servo.setMin(100)!!!

and if the map is more complex, like (45,135,38,140) I have to make a manual computation to find how I must set the limits

It also make it hard to compare the position of the servo with it's min/max

So I really think the limits should be set using the Input value

But fixing that potentially break some backward compatibility.

Some path of solution have been proposed or my understanding of what proposed

  • Leave it that way: don't break any script, but will always make services that modify servo position hard to do and be solid in all situation
  • Remove the mapper and use gain/shift parameters: I'm not against the idea, but not convince it's easy to use in all the situation. By example how do I replicate what a map(45,135,38,140) do with the gain/shift parameters? I need to do manual computation to find the right parameters?
  • Keep it this way, but have getMin reverse map the setMin. That will help fixing the problem of comparing position to min/max, but can still be very confusing.


What I think is the best solutions is to remove the setMin/setMax and replace them with more explicit method like setMinInput, setMaxOutput etc. That will break scripts that can potentially have problem with the map setting, but better have the script not run than use bad parameters and burn servo or break part. The new setMin/max methods will also compute their counter part (Input/Output) by mapping or reversemapping the value. by example with a map(0,90,90,180), a setMinInput(10) will be the same as doing setMinOutput(100). That will also have the flexibility to apply the limits to the range we want (Input or Output), but I still beleive that using it on the Input value is much more better

Any though?



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Mats's picture

Servo mapping


When you talk about complexity, it's the complexity for the developers, not so much for the users of MRL. 

So given your 3 options, I vote for this solution that is very close to the third option that you suggest.

  • Keep it the way it is to avoid breaking scripts, but add two methods, getMinInput and getMaxInput in mapper and make them avaliable also in Servo. They should return the minOutput and maxOutput recalculated to the corresponding input values. The reason to have this calculated is because you can use something like in your example: map(0,90,90,180)  and then setMinMax(100,180) to override the output limits.
  • In this case the getMinInput would return 10 ( 0 input will still correspond to 90 output, and 90 input will correspond to 180 output, and 10 input will correspond to 100 output).
  • That makes it possible for services like Tracking or Jaw to internally use make calculations based in the values from getMinInput and getMaxInput. When using those values in moveTo, the servo/mapper will handle the correct calculations from the Input calues to the Output values.


calamity's picture

the complexity I want to

the complexity I want to avoid is to have the user need play with two different range of numbers to set the servo.

so your proposed solution do nothing to help in that way.

In your solution, user still have to do setMin(100) while what he want to do is to prevent an accidental moveTo(0) to happen. And that make no sense for me. It's certainly not user friendly for a beginner user who just want his slider to not go below 10 have to do a setMin(100). Then for another servo that use map(0,180,0,180) and setInverted(True), he need to use setMin(170) to have his slider not go below 10.

That's what I want to prevent. You should be able to set the limits on the same range that you use it for the moveTo()

the solution you propose help the developper, but not the regular user

Mats's picture

Servo mapping usage

Aha. Different assumptions.

I think we have a different view of how mappings are used. 

When people make their own scripts no mapping is needed at all, with the exception of perhaps the case where a servo needs to be reveresed.

All other mappings are used in the case where the user doesn't have control over the moveTo parameters, like when using Gael's gestures on a different InMoov build.

So to be able to use all the different Gestures that Gael created, there was a need to be able to move the same way. In this case the user doesn't have any control over the input, they are defined in the gestures and needs to be map:ed to get the expected output values to the servos.

The other case is similar. Lets say that the Tracking service was built to always send a moveTo value between 0 and 1. Then the mapping would then be map(0,1,0,180) for a full move, or map(0,1,70,110) to limit the movement i.e for example for an eye.

A third scenario may be that the servo is controlled by an potentiometer sending an analog value. That value could be between 0 and 1023 if it has 10-bit resolution. A map(0,1023,0,180) would make the servo move all the way.

So mapping is used in the cases where the user don't have control over the input values

Therefore it makes no sense to have the user calculate backwards to set the servo limits on the input values, and very natural to have the limits set on the Output values.


calamity's picture

Mats, our understanding on

Mats, our understanding on how the mapper is used is not different.

In almost all the script people use, the input range is different than in output range.

Most of the user use gael script as reference. Gael use map that way (0,180, MIN, MAX) so his gesture can be use by other user. 

In my script, I use angle of the part the servo is moving as input, and the output is the position the servo should take to have the choosen angle. For most case, the mapping is still (0,180,0,180) but in some case like with the bicep, if I want to elbow to bend at 60°, the servo have to move to position 80. The mapper can compute that for me.

So user use the mapper all the time.

The problem I see is that there is currently no way to set the limits with the reference people use. It most be done in another reference range (output)

I will continue with one of your example

you have your service that read the potentiometer and do servo.moveTo(potentiometer value).

the is (0,1023,0,180)

everything work fine on the software part.

You mount all your parts and test and find out that when the potentiometer value reach 999, problem may arise, servo could jam, or pieces may break, or it`s just going too far for what I want. The problem is that I could not set the limits with that value. It need to be converted in the output range and that`s where I beleive the confusion happen.

servo.setMinMax() is not explicit enough. so user may try to use it with their input value and that gives resuilt completely different than what expected. 

That's why I think using setMinMaxInput and setMinMaxOutput will improved things. this will allow to set the limits using either input or output value and are clear what the method are taking as parameter values. Both method should do exactly the same thing, so your example, setMinMaxInput(0,999) = setMinMaxOutput(0, 175.8)

pscartozzi's picture

If I may play the part of a

If I may play the part of a noob trying to implement this which isn't far off.



-I think the mapping functon is OK. It seems like a and b only need to 0, 90 or 0,180. I know where I want the servo to be based on whether it is a 90 or 180 deg servo. 

-c and d should define the values you want the servo to move. I use the sliders to figure those out. c and d should define the min and max positions that I want the servo to be limited to. I do not know why these have to be set in a different line with setlimit comands

- c and d should be reversible to account for servo reversing. There should be no need for the invert function.

- having the map function handle these removes two lines of script for each servo. You can define the servo in one line. This would be of help for us noobs.

- you should be able to set an intitial position for a servo before it connects so it does not rail the servo to 0 or 180 which rakes parts.

-if this brakes scripts that is OK, as long as how to correctly use it is shown on the servo help page


Noob thoughts



calamity's picture

I agree with most of what you

I agree with most of what you said Perry

The initial position for the servo before it connect have been taken into account with the revision of the servo service. It's now possible to do it. But the InMoov services have not been updated yet to use that new functionnality of the servo service. InMoov services are probably the next thing we should review.