Future Of Servo Speed Control

This will be the future !  Please be part of it .. thumbs up or thumbs down - if thumbs down state why.. WHOOHOO ! - this is what I have so far....

ServoControl comments range default
value
units
setSpeed(double speed)   0.0 - 1.0 1.0 relative - based on 
1.0 == full speed -  which is in this case "no" speed control
setVelocity(double velocity) gone ! - setSpeed is king - I method to rule them all !      
setAbsoluteSpeed(double speed)

There has to be a "convention" to follow to make absolute & relative speed work - I can't find anywhere on the Servo service page where this is specified.  I think calamity made some calculations - but I can't find them at the moment.  So until it become more clear I found these are the "specs" for HK15298.

0.13/ 60deg @ 6v, 0.11 / 60deg @ 7.4v

Which means what ?  0.13 secs to travel 60 degrees @ 6 volts ?

461.58 degrees/sec

    degrees per second
setLegacySpeedControl(boolean legacy)  to support all gestures currently using old speed control

Although I'm on the edge of setting the default to false, I believe most people who have an InMoov would disagree with that - so I'm willing to default it to true with a grace period of 1 release version, afterwhich it will be defaulted to false and/or removed completely

true/false true  

History Of Servo Speed Control

     
100000000 BC There was no speed control. Dinosaurs did not have much fun with servos. No wonder they were grumpy.
100000 BC GroG thinks, "Hey, controlling a servo's speed would be fun".   And makes Servo.setSpeed 
Its based on some modulus of an incrementing counter in Arduino's loop.  
The input interfaces is a range between 0.0 to 1.0 because he thinks that is the common output for many analog devices like joysticks.

The implementation is non-linear.

100 BC People start using the strange non-linear setSpeed. They make lots of scripts with this bizarre non-linear, changing scale. 
100 AD Calamity attempts to fix setSpeed.  The best part is he makes it based on "Time" which is pretty constant and universal, not the number of clicks a counter counts (which can vary alot between environments).
1000 AD Fixing the speed control breaks scripts.  There is much confusion and sadness.
2000 AD setSpeed setVelocity setMaxVelocity .. Breaking scripts.. Propegating bad interfaces .. GAH !   What do we do ?
2016 AD Much civil debate and proceedings continue..
Until..
Future .. The best interface and implementation was chosen.
It was simple and robust and the future was bright..

So I think we are in 2016 ..
and still debating .. which is good..

My opinion is there should be 
Servo.setSpeed(Double speed)
where the speed variable is 0.0 - to - 1.0  where 1.0 is full speed and 0.5 is a best attempt linear implementation of 1/2 speed

It "might" be useful to have a variable affect the speed as a constant offset.  Where the situation is you want two inmoovs to move in unison, yet they have different servos with different speed characteristics.

I would prefer to fix scripts so that they are onboard with Calamity's implementation.

If absolutely necessary, Kwatters had an iteresting idea of overloading setSpeed(Double speed, boolean oldStyle)

Where the old scripts could use non-default oldStyle speed control until they were converted.

hairygael

7 years 4 months ago

Nice post Grog!!

Although I'm still confused...

Servo.setSpeed in each Gesture will remain (0.0) -->(1.0) as far as I understand.

############################################

Start up script will:

Servo.setVelocity  will now be (-1)= full speed

Servo.setVelocity  will now be (0)= no speed

Servo.setVelocity  will now be (25)= 25degree/second

############################################

How does one beginner know how to set his Servo.setVelocity? There is no way they are going to measure each servo degree movement. I personnaly wouldn't even know how to start.

:)

gael, think of setVelocity the same way as a car cruise control

if you want to servo to go faster, you increase the value, slower you lower it. If you ask the servo to go too fast, the speed will cap cause the servo can't go faster.

the value can be measured and observed easily

by example, if you use the shoulder servo, setVelocity(18) and ask the servo to move from position 0 to 180 (before mapping), it should take 10 seconds to do the movement ( 10 second * 18 degree/second) 

The nice thing with setVelocity is that the parameter is defined in degrees / second.

So if you want for example the arm to move 90 degrees in 15 seconds, that can be achieved by using setVelocity(90/15) or setVelocity(6).

If you want the arm to move twice as fast, you change using setVelocity(12).

The nice thing here is that this will move the arm at the same speed independant of the max speed of the servo, as long as you keep the speed less than the maximum speed for the servo.

So if you have a gesture today, you cold measure or estimate the angle that it moves, and measure the time it takes to move. Then the calculation of the setVelocity parameter is simply ( "degrees" / "time in  seconds" ).

So it's not very difficult :) 

calamity

7 years 4 months ago

here my opinion so the civil debate continue lol

I would love have a setSpeed as you describe, but I see multiple problem with that

1- it will bring problem with backyard compatibility or can potentially bring confusion. I can imagine a neophyte wondering what setSpeed(0.5, true) mean and what is different than setSpeed(0.5, false)

2- a linear implementation where 0.5 value mean 1/2 the speed of a servo imply that we know the speed of the servo, wich we usually don't

3- with the same implementation, two inMoov using the same script will never move in unison unless we do as you said and add a constant offset, wich add to the complexity.

 

I understand that setVelocity can be a bad choice for the name, I couln't use setSpeed for backyard compatibility and that setVelocity is, while a speed control, very different than setSpeed.

with setVelocity, you give a value that can be observed and measured. 

so with setVelocity you told the servo to move in a way that it will turn his pot at the rate you describe.

That will result in two inmoov using different servo, and maybe different gearing, but using the same script will move in unison as long as the speed value is inside the servo capability. 

Another reason why I implement setVelocity like this is that, in conjonction with the IK service i'm working on, it allow to estimate fairly precisely the position of the inMoov part in time, so it make it possible collision with other part or defined object, even if with hobby servo, we don't have feedback about the actual position. That wouln't have been possible with the arbitrary value used by setSpeed.

Finally, after many modifications, (thanks to gael for his patience and feedback on this) the new implementation of the speed control keep the backyard compatibility with old scripts by convertion the setSpeed value to a setVelocity value. 

 

GroG

7 years 4 months ago

There are still days left in 2016 !!!  Plenty of time for more debate !  :D

I want to start with maybe some obvious clean-up.

The method setMaxVelocity sets the Java-Land maxVelocity and sends a message to MrlServo to set the maxVelocity.

The one in MrlServo.cpp does absolutely nothing.

If there is no point to it there, it should be removed and so should the message definition..

 

What say Ye ?

(figure we do the easy ones first :)

setMaxVelocity was used in the first version of the speed control, but yes, it's currently unused and can be removed.

lazyness and possibility to reuse it have me keep it, But at the current state it's not need in MrlServo.cpp

But it's still used in Servo.java

Good .. that was easy ...
 
Now next thing :
Imagine we did not have to deal with backward compatibility..
 
What would the method name(s) be ? and What would be the best interfaces ?
 
not setVelocity - since there is no vector / direction component ... everything we have been dealing with is a scalar
 
so ..  setSpeed I think is the right method name, but what input values ?  And is this the only method ?
 
There are other possibilities, but the 2 major contenders I see is
  • 0.0 to 1.0 (relative)
  • degree per second (absolute)
Relative is nice because you don't need to remember values.  0.5 is half as fast whichever motor or servo you are using. And
1.0 is always full speed.  So, it allows easy mapping from on system to another.
 
Degrees per second is nice because it can be verified. Someone could actually test and see if some movement went 10 degrees in a second.
 
Names are very important - if you choose a bad name, you'll be constantly explaining to others what it means.  It limits development, causes confusion, causes lots of problems.
 
setSpeed(double speed)  // 0.0 to 1.0
setSpeed(int speed) // 0.0 to infinity
setSpeedPercent(double speed)  // 0.0 to 1.0  
setUnitSpeed(int degreesPerSec) // 0.0 to infinity
 
So first question is :
for setSpeed ... the most common method what should it do the 0.0 to 1.0 range or the 0.0 to infinity degrees per second ?

I don't really care about the name of setVelocity. I was looking for a different name than setSpeed for the reason giving in a previous post.

I choose setVelocity as name because it's a synonym of speed (you can verify in any synonym dictionnary) and that it refer to angular velocity.

While the setVelocity method only define the scalar or magnitude of the velocity, the vector or directional component is implecitly define when you do a a moveTo. We ask the servo to move do a movement of a certain magnitude toward a point, and that is the definition of velocity.

in the history of MRL, setSpeed have define the relative speed of a servo where 1.0 been full speed and 0.0 been stopped. I'm fine with that definition and would like to keep it that way.

setVelocity don't fit in that definition and I want to be clear that it's another way of regulating the movement. I think calling it also setSpeed can bring confusion.

and to finally answer you question, in my mind, it is much more easier to use absolute value than relative value to a maximum speed that most of the time is not defined.

I agree on all points. 

I'm glad you find it acceptable to have setSpeed(double percent) - with range 0.0 to 1.0

I agree the method name should "be something different"

I don't think it should be setVelocity, I was trying to think of possibilities

setUnitSpeed(int degreesPerSecond) ... is imho the most favoriable (at the moment) .. there is also
setAbsoluteSpeed(int degreesPerSecond)
 
setSpeedDegreesPerSecond(int speed)    seems a little to long, although to have the actual units expressed would be nice..  Also, you have it at int, but is there any reason not to have a double for fractional degrees ?  

Great .. so far we have the following changes

moveTo(double pos)
setSpeed(double percent) /* 0.0 to 1.0 */
setAngularSpeed(double degreesPerSecond) /* 0.0 to ??? */

also, if the implementation did not use Arduino's servo.write but used instead write.writeMicroseconds the increased resolution of the input would be more meaningful, as writeMicroseconds can potentially do sub-degrees

I was also thinking to compensate in the future for differences at least a constant is needed.|
We currently compensate for position with a mapper.  Perhaps mappers should be utilized for speed as well in the same way they are currently being used with position.

so that the following could be possible if needed
servo01.mapSpeed(0.0, 1.0, 0.0, 2.0)

which would for a script increase the speed proportionally for any input values.  I'm not sure if this would be the best way to handle differences - but its a way which we did it in position, and it seemed to work ok ..
Given that this is pattern perhaps if we expose acceleration as a scalar - the same "pattern" of mapping would be apropos.

servo01.mapAcceleration(0.0, 1.0, 0.0, 2.0)

I'm stopping arguing about the name change

what I don't understand is that i have begin to use setVelocity like 6 months ago and I never seen any comment that was a bad name. Now that people begin to use it, you want a change that break script and forcing people to update. I found this unproductive and pointless as it don't even bring something news. So enough of this.

 

With the use of absolute speed, like in degree/s, we don't need mapSpeed(). With an absolute speed, by definition, the speed are normalized and two different robot, even if use different servo will move at the same speed. 

I'm trying find an advantage of using relative speed over absolute speed other than for the backward compatibility and history reason. 

writeMicrosecond is still only superficially implemented. you can use it, but there is no min/max/map etc related to it

 

the acceleration stuff is only at initial implementation and probably won't stay as it is right now. 

we can use as unit "degree/s/s" or "time to reach the set speed"

do we use it as acceleration/deceleration? pass a parameter to define if it's do acceleration only, deceleration only or both.

Do we pass an initial speed? 

it still have a lot of question to answer about it, but the initial implementation make the acceleration effect working.

and more importantly, is setAcceleration a good name?

I didn't know this was an argument.  Surprise to me.  I didn't know how to use setVelocity, and I have not begun to use it yet.  Method names are like documentation, I put it out as a question, "What is the best name"   It was a question, I did not state "I know a better name"

There is no indication with the names currently why I should use one vs the other, nor what input values one would expect vs the other.  I thought this could be improved.  And just because I didn't say it 6 months ago, doesn't negate the fact I thought it might be improved.  When is the cut-off when I should hold my tongue ?  3 days?

Just because something doesn't bring "new functionality" doesn't mean its not important or worthwhile.  MRL is a product of both New Functionality and Refactoring.  Both are important.

1. The biggest change was between counting clicks, and time based speed control.  You changed it to time base and I think that was an improvement.
2. Input ranges - this has been 0.0 - 1.0 then degreesPerSecond.  -  For the most part I don't really care.  It started one way, and the new function has different input range of degrees per second.  It doesn't really matter - either can easily be transformed into the other.
3. Backward compatibility vs Baggage - setSpeed is the most generic universal name, but its currently the one "not to use"  going forward - so I see a problem there - and hence why I originally brought it up..

Your right about mapping.  I think setVelocity & absolute units should be used going forward .. I don't really like the name, I don't like the fact that the poorer implementation has a better name, and I don't like the fact we still don't have much of a plan going forward besides have 2 method which try to do the same thing, with different outcomes.  Its a bit messy...  So that's why I keep bringing it up..  And I don't think its pointless 

You don't understand what I was suggesting about writeMicrosecond ...

there would be a single place where it would be replaced
https://github.com/MyRobotLab/myrobotlab/blob/develop/src/resource/Ardu…;
Precision is lost when casting to int .. the translation from degrees to micro seconds I believe is something like this:
servo->writeMicrosecond (2400 /*max*/ - 544 /*min*/ + (10 /*ms per degree*/ * currentPos))

Is your last question a sarcastic one ?
 

sorry, I did not mean to be harsh, sometimes bad days slip where it should not

while I agree that setSpeed will have been a better name, I still fail to see why setVelocity is so bad. I still not see why the proposed changes are better, more clear and less prone to confusion.

Maybe it's because I use setVelocity for a long time, or because my french speaking, but personally, in my mind I think that setVelocity is clear enough to know that we are dealing with how fast a servo will go.

I'm not against refactoring, quite the contrary. but my lazy nature make me as a big WHY when I don't see any improvement at the end of the line. But maybe I'm just not seeing it.

It's unfortunate that the first implementation have a better name than the recent one. But you can't rename your first born because it's name will suit better your newborn unless the firstborn die. You won't kill your firstboarn don't you?

 

 

now I understand your comment about writeMicroseconds. will certainly gives a better resolution (about 1800 step vs 180). The difference will probably be only seen when using very low speed setting. I the see the casting to int as a lost of precision. it's mostly do we round or truncate the number. in either case, it will need 10 1/10 of position to change value. the imprecision will always been much bigger on how the pot is fixed (slack in the pot position or the gearing)

 

 

 

 

:)

The lifetime of software is extremely short. There's good and bad to it.  The good is that as it dies, new software replaces it and it evolves into a better design.  The bad thing is that this quick lifecycle can generate its own chaos and confusion.

With this new stronger function, there is no exit plan to remove the old appendage.  So we have a five legged horse.

Are 5 legs better at running ?  No .. but we'll still need to clean all 5, buy 5 horse shoes, etc..
The "develop" branch needs to be a place where we can remove legs, if we think the horse will run faster.  Who knows, maybe 2 legs are faster.

"Develop" should be a place were we can try to build the best and fastest horse.
But there are all the farmers which depend on horses.  How will the saddles fit?  Cowboy "A" has a rodeo coming up, and Farmer "B" needs to start plowing the fields. Yeah, so that's why were suppose to have "master" branch.  So we can mitigate the evolution, make sure bridels and saddles fit, or how they can be easily modified to still work.

That said, I'm done with suggesting anymore changes in this area.  I want the webgui fixed so I'll fix it (working on horseshoes) ..  but for this topic I'm done.

Sleep helping, I re-read the full conversation again and I think misunderstood what you want to do.

I have in mind that you did not like setVelocity and want to change it, and I still beleive that is not a good reason.

But now I realize that you want to rework the different method so the shapes fit better together. And with that goal, yes there is place for improvement.

So i'm sorry to have exposed my stupidity like this and wish to go on and hope you will still put your valuable input in this.

 

what about

setSpeed(0.0-1.0) -> old behavior keep for backward compatibility

setRelativeSpeed(0.0-1.0) -> new linear speed control where 1.0 is the maximum speed of a servo. I think this will be hard to use with hobby servo because it's hard to know the exact value of full speed. but with DIYServo, that will be more easy to determined the full speed that it will go. So it can be useful to have

setAbsoluteSpeed(0.0-infinity) -> the renaming of setVelocity, use degree/sec as unit.

it will also need

setMaxSpeed(degree/sec) -> rename of setMaxVelocity, but it will also need for setRelativeSpeed to set what is the "full speed" (1.0 value). It can also be use to set a speed limit on the servo. In some case, going too fast can damage the part the servo is moving, So I think having a control that say never go over that speed is a good thing.

While at it, I will also want to discuss how to implement acceleration, where the servo start slowly, accelerate to a speed then can also decelerate before reaching the target. There is multiple way to implement this.

so here some suggestion I can think of

setAcceleration(deg/s/s)

setAcceleration(deg/s/s, initialSpeed)

setAccelerationTime(time to reach speed)

setAccelerationTime(time to reach speed, initial speed)

setAccelerationInitialSpeed()

useAcceleration(boolean)

useDeceleration(boolean)

and I can think of many more setting way for acceleration. Any though?

 

 

No worries Calamity,  I always appreciate your input even when we don't agree.
Sometimes ideas are not complete, and take while to flush out successfully. 

I think the crux of the issue is you made a better speed control, but its not backward compatible.
setSpeed is the most intuitive method, unfortunately the old, bad, non-linear speed control uses it.

So - there needs to be a plan of migrating the scripts off, or requiring script to re-name their speed control if they want to use the old, bad speed control.

Converting the scripts would be rather trivial - e.g. to set them to setDumbSpeedControl( ....) if they were all checked in.  When InMoov 'official' script & gesture are checked into InMoov repo - we could easily convert them.

I like setAbsoluteSpeed, but setSpeed in my opinion should be linear relative ...
Or setSpeed should be (0 - infinity degreesPerSecond) - linear and interfacing will require mapping..

In regards to setAcceleration what I think you are beginning to define is "ramping" - which is the curve or slope of acceleration before velocity is reached.

I'm not sure the best way to control or represent this.  Slope of acceleration or deceleration (as in y = mx + k) or absolute value - e.g. degrees per sec per sec.


I've done a push which contains several updates.
"attach" is a method which is mostly abount service attaching services.  I've made a webgui directive which makes it very easy to create a type-ahead for a list of services which has a desired interface.

Servo the directive this way :

<attach ng-model="possibleController" ng-disabled="controllerName != null" interface="org.myrobotlab.service.interfaces.ServoController"/>

attach of a pin is just a method call - changing pins should not require destroying the MrlServo and related data.

I changed the speed input to use velocity, but I would be fine to change it back to speed, if we can go forward with a plan to use linear speed control vs "old legacy"  way

 

If you really want to have setSpeed for a linear relative speed control, then script will have to be modified.Not everyone have script check in so we probablywill have  a lot of 'why setSpeed is not working anymore like before'. But yes is relatively easy the replace the method name with something else.

 

If we implement a linear relative speed control, we will have to define relative to what. ''full speed'' is not a value that we can use in the calculation. So we need a way to set what is max speed (value 100%) like setMaxSpeed(degree/s). so setSpeed will be relative to setMaxSpeed, and setMaxSpeed could also been a limit to setAbsoluteSpeed().

So we potentially have 

setMaxSpeed(degree/s) -> define the maximum speed of a servo, we probably need to find a default value.

setSpeed(0.0-1.0)    new linear relative speed control

setAbsoluteSpeed(0.0-maxSpeed) in degree/s -> same as the current setVelocity()

setSpeedOldBehaviour(0.0-1.0) as the old setSpeed base on v119

useSpeedControl(boolean) to activate or desactivate the speed control, false mean standard servo.write(targetPos) will be use

On another note, i'm in the way to change the servo.moveTo to be able to change so it use the writeMicroseconds value. 

I just find out that the arduino servo.write can use the range 0-180 or the range 544us-2400us. In fact, internal to the arduino servo library, the range 0-180 is map to the 544-2400 range then writeMicrosecond is called. and I plan to allow the same behaviour in the MRL servo service so we can all the functionnality we have with servo.moveTo also work with writeMicroseconds

Yay !  I think we are starting to see the same thing.
I saw your latest check-in & that is exactly what I was thinking with

->  servoWrite/deviceId/b16 target

In retrospect, we should have always tried to use an implementation which supports the highest possible resolution.

In regards to write / writeMicroseconds - writeMicroseconds should always be used for "implementations".  It supports the highest resolution.   As does micros() vs millis().

If this was the case it would allow for subdegree input from moveTo(Double)

Additionally, if micros are used instead of millis - potentially the movements will be smoother.

I checked the code in MrlServo.cpp to see how it works, because I want to implement it also in Adafruit16CServoDriver. 

But i got a bit confused..... 

I guess that setAcceleration is intended so that the acceleration can be specified as degrees / s^2

But the implementations in MrlServo.cpp seems to implement degrees /s^3.

It takes the deltaTime into account 3 times, not 2 as I would expect. First by using it ^2 when calculating the new _velocity and then one more time calculating the step = _velocity * deltaTime

I connected two servos, one using the Arduino, and one using Adafruit16CServoDriver to be able to test that the logic is the same in both. They now move in sync when using setVelocity, but not when using setAcceleration.  

Your question about deceleration is interesting. A bit more difficult to implement, because the algorithm for deceleraion needs to precalculate at what position / time to start decreasing the speed. And it probably needs to be adjusted again a few times during the deceleration  

Just like when driving a car. It's easy to start with full throttle, but much harder to know when to step on the brakes to stop at a specific point.

Perhaps a bit overkill, but today it's only acceleration, and the servo stops when no new position are sent.

 

Hi All,

I think for the most movements with the InMoov, are absolute.

The way how Mats it explained is a good one.
This makes it easier to calculate the correct timing for each movement.

If the Acceleration part is full functional, it makes it more smooth and even faster in some movements.
Now we need to calm down, because if we use a speed what is to high, it can break some parts or even kill the servo during the start or at the end !

I hope the Acceleration can do the job in both way's, so the movement will also slowdown nicely :)
For this, we need to now the real position and the new position...
If the real position is comming closer to his new position, there must be a point where we need to slowdown again.
This will help to safe mechanical parts, like all servo's by the shoulder, because of the total weight from the arms.

I've tested the Acceleration which is included in MRL1851, and works nice already.
(Thanks to Calamity)

Regards,
Marten

BTW, here my simple test script for testing the Acceleration:


# Starting the Servo Service
# Tested in MRL 1851, where Calamity has added a Acceleration option

arduino = Runtime.createAndStart("arduino","Arduino")
arduino.setBoardMega()
arduino.connect("/dev/tty.usbmodem411") # OSX USB connection
# arduino.connect("COM4") # Windows USB connection

servo = Runtime.createAndStart("servo","Servo")
servo.attach(arduino,3)
sleep(1) #attaching procedure take a bit more time to do, wait a little before using it

# Setting the Velocity and the first Acceleration
servo.setVelocity(400)

servo.setAcceleration(4)
servo.moveTo(0)

sleep(4)
servo.setAcceleration(10)
servo.moveTo(180)

sleep(4)
servo.setAcceleration(20)
servo.moveTo(0)

sleep(4)
servo.setAcceleration(40)
servo.moveTo(180)

sleep(2)
servo.detach()

 

If you don't know full speed, there is no way you can know half speed. So relative can never work on it's own.

If you want to use relative, we need something like:

setSpeed(relativeSpeed,maxSpeed)

where relativeSpeed would be 0.0 - 1.0

and maxSpeed a positive value defining the max speed in degrees that you measure the potentiometer to move. The maxSpeed value will vary a lot depending on how fast movement you can expect. For example the eyes servos would use a much higher maxSpeed value than an arm.

And we need to define some value to say that the servo should  move at max speed.

 

calamity

7 years 4 months ago

After reading the update post, I still feel there is many point to be clear out.

I will try to explain again how I end up designing setVelocity to avoid all the pitfall that setSpeed (either the old behaviour or the new change you propose to it) have

When you pick a servo, it may have a speed value describe in the documentation, but many thing will influence that ''full speed''

  • Load on the servo: The speed value describe is a no load, as soon as it have to carry a load, it`s speed will slow down. More the load is heavy, more it will slow down until it stall and do magic smoke. 
  • The voltage supply: the speed is influenced by the voltage. Using battery, it`s quite possible that the voltage will vary in the usage, going for 6.2V at full charge to 5.8 as the battery charge deplete and modifying the ''full speed'' a servo can go
  • The location of the pot: on stock servo, the pot is physically linked to the horn of the servo, but it's quite common that we modify servo to extract the pot so we don't measure anymore the position of the horn, but the position of a part.  If there is a gear box in the way, the speed that the pot turn will differ greatly from the ''full speed'' provide in the servo documentation

So a setSpeed based on a ''full speed'' will always be hard to use. What may work fine under certain condition will not work under other condition.

So without a way to be able to calibrate the full speed under the conditions that influence the servo, It will always be hard to have it work alway the same way.

 

So when I begin to work on setVelocity, I want to avoid those factors. Those factors will always influence the upper limits it's possible to set with setVelocity, but as long the value are set within the limit of the servo, 5 degree/sec will always be 5 degree/sec, whatever the servo model use, the load on the servo, the voltage of the servo or the location of the pot. 

I think that`s define the difference between setSpeed and setVelocity, why I name it defferently and why i'm reluctant to have setVelocity use a similar name than setSpeed.

I think that setSpeed based on the full speed of a servo is a bad design choice that bring a lot of ''normalization'' problem.

Now, if you want to have a setSpeed that take value between 0.0-1.0 and that is linear, we should base it on a defined value that set the maximum speed that servo can go (instead of full speed that can vary). It will work if the maxSpeed is keep inside the servo limits and will make setSpeed work on the same base as setVelocity. Otherwise, setSpeed will always working in a faulty way and I really think setVelocity should remain something different than setSpeed

in the following video https://youtu.be/oA81rw7pr6Q

I have 3 different servo (TS-80, BMS-L530MG and corona DS929HV) that can go at different speed. The first movement is without speed control, you can see that the corona is very fast. then I ask them to move the same range with a velocity set at 20. You can see how well they syncronize each other. Not sure if it`s possible to do that with the way you suggest implementing setSpeed

 

 

Hi

This is how I hope the "Future Of Servo Speed Control" will be.

setSpeed(double speed) -> This is the poorly defined method that is currently in use by many scripts. The only two defined values are 0.0 ( no speed ) and 1.0 ( full speed). Anything else is undefined since full speed varies from servo to servo and there is no way to set the speed of a servo to something like "half speed". It should be removed as soon as possible. Perhaps a warning in the log, so that people can convert to the new methods. We should not encourage the usage of ranges 0-1 if there isn't a real upper limit. 

setVelocity(double velocity) is the new method that allows for setting the servo speed at a well defined angular speed. It's independant of the size ot the servo. In the implementation will send new servo positions to the servo so that it can move at the desired speed. ( If the servo cant keep up with the change in servo positions it will move at max speed ). The GUI should be updated to use this method.

setAbsoluteSpeed(double speed): The comments are confusing, but seems to be that same as setVelocity. I don't see any reason to have two methods doing the same thing. The name indicates that it's to be used to set the speed for a linear servo, not a rotational servo. 

setLegacySpeedControl(boolean legacy). I don't see any use for this method. Leave the setSpeed as it is for a few versions and then remove it.

/Mats

setSpeed(double speed) -> This is the poorly defined method that is currently in use by many scripts. The only two defined values are 0.0 ( no speed ) and 1.0 ( full speed). Anything else is undefined since full speed varies from servo to servo and there is no way to set the speed of a servo to something like "half speed". It should be removed as soon as possible. Perhaps a warning in the log, so that people can convert to the new methods. We should not encourage the usage of ranges 0-1 if there isn't a real upper limit. 

Yes it was a poor implementation, I think the method name can still be used with a boolean which flips it from the poor implementation to the linear one rather than creating new methods.  For example, from what you suggest - we will have Servo.setVelocity and Motor.setSpeed.  A "default" speed is necessary, until calibrated.

setVelocity(double velocity) is the new method that allows for setting the servo speed at a well defined angular speed. It's independant of the size ot the servo. In the implementation will send new servo positions to the servo so that it can move at the desired speed. ( If the servo cant keep up with the change in servo positions it will move at max speed ). The GUI should be updated to use this method.

setAbsoluteSpeed(double speed): The comments are confusing, but seems to be that same as setVelocity. I don't see any reason to have two methods doing the same thing. The name indicates that it's to be used to set the speed for a linear servo, not a rotational servo. 

It is the same as setVelocity. It uses absolute units.
The difference between setSpeed & setAbsoluteSpeed is one uses 0.0 to 1.0 range and the other would be 0.0 to ??? range.
Since ??? is not well defined - we will define it as a "default" 461.58 degrees/sec until the user calibrates it.
0.5 is well defined too - its 230.76 degrees/sec until the user calibrates it.
0.25 is 115.39 degrees/sec until the user calibrates it

If the user sets setAbsoluteSpeed(600)
then 0.5 is 300 .. etc..

Hi GroG

You are walking the same path as calamity did months ago. Then he realized that using two parameters to set a single value was just confusing.

That's why setMaxVelocity ( or as you call it setAbsoluteSpeed ) was created, and later abandoned.

The nice thing with setVelocity is that it doesn't have to be calibrated. It results in the same speed independant of servo type.

From your explanation:

setVelocity = setAbsoulteSpeed() * setSpeed()

/Mats

Hi GroG

I have a feeling that there is an underlying assumption, where we have different understandings of how things work. That happended for example with the Arduino, where you were assuming that the Arduino would not reset at connect but in reallity it does.

I have a feeling that there is a similar case here, since you started to talk about motor.setSpeed. 

setSpeed for a motor is also a bad choise of name, unless you have a motor with feedback and a pid loop for the speed control.

 A better name would be setPower. The power of a motor can be regulated to make it run at for example .6 of full power. That can be done in two major ways. One way is to decrease the voltage. The other way is to use PWM so that it has full power 60% of the time and no power at 40% of the time. In MRL the second method is used. That method results in the motor runnnig with full torque when it's on. The result is that the motor will run at 60% speed, becasue of his relation:

power = torque * angular speed.

So when the power is 60% of full power, the torque will be the same, so the speed will decrease to 60%.

---

Servos behave different. When we talk about PWM for a servo, it's not true PWM, so the explanation above is not relevant for servos. For a servo we send a pulse between 1-2ms ( or a bit shorter / longer ) as been discussed earlier. Then there is a pause so that pulses are sent at about 20ms intervals. The length of the pulse tells the servo what final position it should move to, and has no releation to the speed of the movement.

---

Does the idea of 0.0 - 1.0 as a good value for servo.setSpeed originate from the motor.setSpeed ?

Imho a value 0.0 to 1.0 for servo.setSpeed is a bad idea and should be abandoned, and we should have just one method to set the real speed in degrees / second ( i.e how setVelocity is implemented today ).

The only reason I can see for having a value of 0.0 - 1.0 is to have a predefined range that in theory should make it easy to connect services together. But I still think we would have to map values between services, so it's probably not true that it would make connecting services together easier.

/Mats

 

 

 

 

Yes, no two servos move at the same speed, for many reasons.

Yes, you need to know how fast your servo 'really' goes in order for any accurate controll of say 1/2 speed.

Most people initially, will not know how fast their servo really goes.

We should supply a "best guess" default,  what is the alternative ?  I don't believe their is one.  The real range of the servo speed is not known until calibrated - so one must be supplied.  If you want to be accurate - then you need to find out what the 'real' max speed is.

So if you find out what your 'real' max speed is you callibrate it by setAbsoluteSpeed.

setSpeed( 0.0 - 1.0) is just a fractional multiplier to whatever was set in setAbsoluteSpeed .. or to the value which is defaulted (461.53 degrees/sec)

and to give legacy scripts a grace-period before breaking them kwatter's slope calculation will be applied with setLegacySpeedControl

 

Grog, you just stating the reason why I think setSpeed based on the full speed is not a good design.

I have explore this way when I start trying to rework the speed control, I give up on this way because it's impossible to have it constant and reproductible. 

full speed value will change depending on the servo model and environment you use it.

You build a device that use a servo. You calculate the maxSpeed and find that setSpeed(0.5) is the right speed. Another person build the same device, but his joint are harder to move or he use a different servo. He also need to calibrate his maxSpeed and get an different value than you. So for him setSpeed(0.5) is probably not the right speed and have to ajust it. That user modify is device so now it weight more. He need to recalibrate again the maxSpeed, and change the setSpeed so he have a similar speed than before.

But in the first place, if you use setVelocity, you will not need to calibrate the maxSpeed, you just need to find the right velocity (let say 10 degree/second). The other person can use your script, whatever his joints are harder or the servo he use or the weight of his device, your script will work for him too and he will have the same speed (10 degree/s)

The speed should be base on something constant, the maxSpeed is not constant. but 10 degree/s will always be  10 degree/s

I can give you many example of situation where setSpeed base on maxSpeed will fail. 

on a inMoov shoulder, at full speed, it take much more time to raise the arm (because the servo is working against gravity) than to lower the arm. How do you determine the maxSpeed of that servo?

with setVelocity(10.0) the arm will be raise or lower at the same speed (10 degree/second)

Another real life example. You are driving your car and find out that 50% of maxSpeed it can go is the right speed. If you go downhill, then 50% of the max speed becomes probably too fast, or too slow if you are going uphill. But you will be always fine if you drive at 50mph

So that`s why I really beleive that setXXXX(degree/s) is the way to go. and have setXXXX(percent) as a secondary alternate way usefull in some case (but still have not think of good case for it)

 

GroG

7 years 4 months ago

Dum dum dummmmmmmmmmmmm !

Finally, comes the light ...  I think I was working on the Arduino message generation when Calamity & others were working through speed.

@Mats - ya totally agree - it's my wanting to find patterns when I suggested Motor.setSpeed - but its not valid, in fact I looked at the interface and changed it years ago to setPowerOutput because I realized back then there is no way to determine without feedback what actual speed is.

@Calamity, ya makes sense - to summarize my current understanding of setVelocity, when you move at sub max speed (whatever that may be) .. you move at degrees per second .. period.  And the "second" is your interval.

Thats why the heart of the calculation in MrlServo is simply :

      float step = _velocity * deltaTime;
      step /= 1000; //for deg/ms;
      currentPos += step;
      servo->write((int)currentPos);
 
You've set up a grid of seconds - it counts the seconds and divides its position across the seconds grid - and moves the required degrees within that second at 'full speed'
 
I think I am convinced fractional input (0.0 - 1.0) is not good..

Sorry it took so long to explain it to me..
I think you all can breath a sigh of relief, finally, I'm not running around with deterimentally crazy ideas anymore..
 
@Calamity,
The code above was from a pull this morning - are you testing 
servo->microSeconds((int)currentPos); ?
Because the "grid" doesn't need to be on a second interval - it could be a smoother sub-second interval.
 
@Calamity - can you please update the service page http://myrobotlab.org/service/Servo to guide noobies to use the right methods, and what they want as input.

@Mats - I wish I didn't use setSpeed in the past... but I didn't know there was going to be a better implementation...  I'm fine with your 'upgrade' path, where setSpeed will at some point be removed and setVelocity will the the only remaining method.  Given all the complexity and work in the area, I'm willing to give up the better name, as long as there is easy to find documentation of doing it the "right" way...
 
Thanks Guys for walking me through that ... I know it wasn't easy :)

 

@Grog, it was not a crazy idea, I have try that path first and did not like where it lead.

I will update the service page, was mostly waiting for that discussion to end and want to complete the use of microseconds as output to servo and some other demainds I told I will look into.

the ''grid'' as you said is in milliseconds and the number of step it take is in function of the time since the last move and the velocity. 

using servo->writeMicroseconds() is not need, servo->write() can distinguish when we are using value in degree (0-180) or in microseconds(544-2400). If the value is in degree, it map it to the microseconds range and call writeMicroseconds.

In the pull you have seen, the data output to the servo can be in degree or in microseconds, But now i'm working to have all the output the to servo to be in microseconds value and the conversion happen behind the scene so user won't have to deal with the microseconds value

 

 

Okay .. that sounds like a good plan..   I agree with kwatters - units from Java-land servo should be degree per second, or sub-degrees .e.g 34.53 never microSecond input values....
except in the Servo.microSecond method in Java land...

I think the discussion will completely end - when the ServoControl interface is updated .. or called "good" ..  
The attach method's I've changed from Object Integer to primitive double, but I'd like to wait until you & Mats and perhaps kwatters if he has any input say its "good"

I'm ready to fix up the webgui - but am waiting on the blessing of the interface from you three to proceed. From the interface all things will follow.. feel free to add comments to it too ;)

The way the servo service is currently implemented, the input for the moveTo method is not limited to a value in degree. the map method default it as a value in degree, but you can map any input range to a valid output to send to the servo. 

By example Gael use setting like this

map(0,180, minPos, maxPos) so his range of 0-180 do not represent a value in degree, but a scale where 0 is the minPos and 180 is the maxPos.

He could use a scale from 0-100 or 34-87 and everything will work the same, it just change what moveTo expect as value.

But whatever, with the change I'm currently doing, user won't have to deal with microseconds value or even know it exist, the conversion of the output range 0-180 will happen just before sending the value to the servo

 

I really enjoy discussing, because I think that the end result will be better when there is a common view of how a problem should be solved. It can sometimes be frustrating process, but at the end I think it's the only way to move forward. If we agree on how things should work, everyone will support that descision and be able to explain why a specific solution was selected. 

GroG

7 years 4 months ago

@Calamity,

I'm curious why you chose to change the Javaland (and MrlServo-land) mapping values ?

Isn't all of this unnecessary if the core of MrlServo changes to this :

line 83 :

double pos = currentPos * 10.31 + 544;
servo->writeMicroseconds(pos);

 

It could have be done there, I choose to do it in javaland because I can use the int to transfer the data (544-2400), otherwise, we need to convert the double to an int value and reconvert it once in MrlComm-land.

Feel easier that way for me, but I think it just a mather where the conversion from degree to microsecond happen 

juerg

7 years 3 months ago

puhhh, long thread, is there now a final status reached and where can I find the agreed on methods to control my servos?

About Gael gestures and others integration into the base script, I'm thinking about the best way to implemented them and minimize the rewrite. I want to validate with you the cleanest possible solution.

 

  • Limits
MAP(min,max,USER_MIN,USER_MAX)
 
  • Invert

servo.setInverted(1)

  • Speed
I have a queston, I initiate the servo with a default maxvelocity like exemple setmaxVelocity(100) . setVelocity is very usefull , exemple to use autoAttach functionality and many others.
But into Gael files there is

i01.fullspeed  , i01.setArmSpeed("left", 0.1, 0.1, 0.2, 0.2) ...

How setspeed coexist with setvelocity ?
If I set servo.setSpeed(0.5) > velocity is now 50 ?

If now I set setVelocity(100) instead of setMaxVelocity(100)
servo.setSpeed(0.5) stile 50 ?

  • Attachement / Detachment
I will remove every vocal commands "ATTACH X SERVO" because now ( or later ) the attach is automatic .  we just need a parameter to disable the autodetachment. So into some gestures we can decide if Inmoov detach or not servos after the moveTo(). Everytime servos are autoAttached(1) of course.

 

 

Gael use mapping that look like map(0,180,MIN,MAX)

This is working good under the condition that the range of movement (MAX - MIN) is similar. If for some reason a build can't have the same range of movement, ALL the gesture will be off from what is wanted.

I think at some point it will be good to change the gesture to use real angle instead of 0-180 value. But I know it's a big job to change all the gestures and it will need some kind of calibration process to have it work the right way.

setSpeed is beed keep for backward compatibility to emulate the same speed output as it was with v119. But setSpeed is not linear (setSpeed(0,5) <> half the speed of setSpeed(0.99))

Under the hood setSpeed will make a setVelocity call with the corresponding value (setSpeed(0.5) = setVelocity(11))

so when you use setSpeed, you are in using setVelocity, but on a different scale.

when you do setSpeed(1.0) it do a setVelocity(maxVelocity) call. maxVelocity is by default = -1 (mean it don't use the speed control). But you can use setMaxVelocity() to set what velocity setSpeed(1.0) will go.

setSpeed non-linearity make it hard to determined wich speed setting is the right value other than by trial/error or experience. So I really think new gesture should only use setVelocity value. SetSpeed() have been made Deprecated and intend to disapear at some point in the future.

 

 

 

 

juerg

7 years 3 months ago

as I like the idea of autodetach in my InMoov the omoplate and shoulder servos may not autodetach when the arm is raised. even more delicate for the bicep as it depends on the current shoulder and arm rotation values.

So we would need to know the force applied to the servo with the current geometry and settings. In addition the servo's self resistance to turn. IK might provide a rough idea of the force but as far as I know the weight distribution of the links is not in place at the moment. Also the self resistance of the servo is currently unknown and would need to be given for the servo in place including the gear ratio - a long way to go?

My head up/down may never be detached as InMoov will return to stare at the floor

An exclusion list for auto-detach might be easiest? And a function that adds a servo to the no-autodetach list?

And - is autodetach immediate or has it a timeout?

calamity

7 years 3 months ago

In reply to by juerg

The way I want to implement auto-detach is on a servo base and turn off by default. So you can activate auto-detach on the servo you want.

My first implementation of auto-detach work in conjonction with setVelocity. When the speed control is enable (velocity > 0), auto-detach compute the time it take to move to the position, then detach it. When the speed control is disable (velocity = -1) it use a timeout.

But to work properly, the velocity setting must be keep with value the servo can actually reach. If you setVelocity to a value the servo can't reach, the computation will be off and the servo will detach too soon.

2 questions about detach timeout if velocity=-1 :

exemple if timeout = 10 second

And at 5 second after the initial action,  I do an other servo action. Is the timeout restart ?

---

Is it possible to use velocity!=-1 AND timeout ? ( exemple if there is an exesive load on a servo and don't want to use autodetach by velocity calculation but with a timeoutdetach )

I will need to complete this... too many cool stuff to work on

currently look like autodetach is not worky when velocity is -1

my plan is having the autodetach reset the timer when the servo is ask to move again

Hi !!

Time to convert gestures to use setvelocity :)
I have taken all your default max velocity ( from pinochio ) to put in default config files.
And set all servo ( except jaw and eyes ) to use a maxvelocity.

Is it a good idea ? Or maybe it better to set MAX_VELOCITY=-1

EDIT after test , it was bad idea lol
I set MAX_VELOCITY=-1 waiting some reflexion about how to calculate a maximum velocity

 

 

 

MAX_VELOCITY will affect 2 things

if you use setSpeed(1.0) -> it will set velocity to it's MAX_VELOCITY value;

if you use setVelocity() -> it will cap the velocity value to MAX_VELOCITY if MAX_VELOCITY >= 0

 

MAX_VELOCITY represent a speed limits. it can be use for 2 reason

1- don't go faster than the set value or part can break

2- for precision in the velocity value... the velocity is an absolute unit, but if you keep increasing the value, at some point, the servo won't go faster. so you can use max_velocity to keep inside the value your servo can go.

 

so the max_velocity can differ greatly between builds, what work for me may not work for you

the best way to calculate max velocity is to use a timer and calculate how much time it take for your servo to go from 0 to 180 (or move on any range). Hard to measure with very fast servo like the eyes, but fairly easy with servo use for shoulder or other slow moving part.

Many thing can affect how fast your robot part can go

  • load on the servo
  • gearing
  • how hard it is to move the part
  • the voltage use/power of the battery
  • the model of servo use.
  • etc

 

 

in your comment you state

"the best way to calculate max velocity is to use a timer and calculate how much time it take for your servo to go from 0 to 180 (or move on any range)."

1) I think we only visually measure a duration for a move and do no calculations?

2) more precise we do not measure the servo's rotation time but the joint rotation? Like it takes 4 seconds to raise the arm by 40 degrees with max speed? This can then be defined by using

MAX_VELOCITY=10 [degrees/second]?

and then to slow down the movement to take 6 seconds I will use

setSpeed(0.75)?

Mats

7 years 2 months ago

In reply to by juerg

I think it's better to avoid setSpeed and only use setVelocity.

In your example, I would just use setVelocity(6) and no other parameters.

Then the movement will be made at the same speed independant of what servo you use and gerstures defined this way will move the same way on all InMoov builds.

 

 

thanks Mats, so whenever I want a move to be slower I will simply lower the degrees/second using setVelocity?

Just to make sure, setVelocity(6) will set - whatever joint I apply it to - to 6 degrees/second? So the joint knows what gear ratio between servo rotation and joint move exists (e.g. for the omoplate)? Or do I actually only control the servo rotation speed and the joint movement depends on the gear elements?