Discontinuous Motion Changes with Lynxmotion Servo

Hello,

I wrote some simple Arduino test code for the LSS (pseudo code below):

during Setup:
  myLSS.setAngularStiffness(0);     //The following block was obtained from another forum post
  myLSS.setAngularHoldingStiffness(0);
  myLSS.setMaxSpeed(180); //isn't the maximum supposed to be 72 RPM for the HS1?
  myLSS.setAngularAcceleration(1000); //maximum is actually 100 but behaviour is the same
  myLSS.setAngularDeceleration(1000);
  myLSS.setMotionControlEnabled(false); //increase acceleration and disable motion control

  myLSS.move(0); //move to 0 position 

during Loop:
  if (myLSS.getPosition() < 10) myLSS.move(1800);
  else if (myLSS.getPosition() > 1790) myLSS.move(0);

The intent of this test is to have the servo horn moving back and forth. However, the servo halts briefly at each extreme before changing direction. The equivalent RC servos under PWM change direction virtually instantly and I want to replicate this. Is there any way to prevent the pausing? I tried a similar attempt using myLSS.wheelRPM(72), but the pausing persists (and for whatever reason, sometimes some pauses are longer than others). Power supply is 12V.

1 Like

Hello @Cucumber_Harvester!

“setMaxSpeed” sets the maximum speed in deg/sec if you want to set it in RPM you have to use “setMaxSpeedRPM”

I think the reason the movement is not smooth is because of the condition you are using in the code, maybe 1 degree is a very “demanding” condition. You could try 2 degrees, that is:

(myLSS.getPosition() < 20) and (myLSS.getPosition() > 1780)

But that is only a suggestion. It may be better to simply calculate the time it will take to reach the requested position, then send the command to move, wait for the time it will take to do so, and send the other command.

2 Likes

Hi @geraldinebc15:

Thanks for clarifying the maxSpeed issue - I’ll correct it in my code and try the 2 degrees tolerance. One interesting thing I observed is that I can send an overwriting command like “go to 0 degrees” while the servo is on its way to 180 degrees and it’ll change direction instantly. But if it arrives at 180 first then it undergoes a slight delay.

1 Like

I can send an overwriting command like “go to 0 degrees” while the servo is on its way to 180 degrees and it’ll change direction instantly

Yeah, that is the behavior you should expect

But if it arrives at 180 first then it undergoes a slight delay.

With the same code? Or the code you posted with the conditions?

2 Likes

with different code. Something like:
“Start at 0 degrees”
“Command to 180 degrees”
(while servo is on its way to 180)
“Command to 0 degrees”
–> servo changes direction instantly

1 Like

Yes, the servo should change the direction instantly when you send a new move command.

On another note, I see you disabled Motion Control “myLSS.setMotionControlEnabled(false)”

In that mode, the servo will move at full speed for D/MD action commands. Angular acceleration (AA) and angular deceleration (AD) won’t have an effect on motion and modifiers SD/S (speed) or T (time) cannot be used.

So if you choose EM0 some of the previous settings in your code are pretty much ignored.

EM0 was specifically created to replicate RC mode where the servo would be effectively spammed by a bunch of position commands and move to each position as quickly as possible. It takes the new position and enters “holding mode”, so travels to that new position as quickly as possible.

EM1 filtering (ON by default) smoothes the RC motion given this “bus spamming” approach and uses a moving weighted average of the positions helping considerably with smoothness.

3 Likes

Hi @geraldinebc15
is that an electronic or mechanic reason?
I’m almost sure you can ask the servo to move 1 degree ‘in the same direction’ as before. But when it turns over, mechanical slack and potmeter ‘dead time’ come into count.
It’s just an academic question, who needs 1 degree moves in real live? :wink:

2 Likes

Hello!

It is more related to electronic reasons

Certainly, you can ask the servo to move 1 degree in any direction at any time. The problem, in my opinion, is that the code he shared asks if a certain position was reached with a tolerance of 1 degree, that is:
Move to 0 degrees and then asks if it is in a position of less than 1 degree?

In fact, it was a suggestion from experience because for a certain project I needed to do something similar and using a tolerance of 1 degree I din’t get the results I wanted so I chose to put a tolerance of ±2 and I got better results.

2 Likes

Hi everyone:

Thank you very much for contributing to my forum inquiry. I have some new information:
It turns out that the brief pause is actually due to the myLSS.getPosition() command! I was refreshing my position at every cycle of the loop.
Here is some code that I used to find out that querying position causes delay:

for(int i=10; i<3600; i=i+6){ //move 360 degrees forward
myLSS.move(i);
myPosition = myLSS.getPosition();
delay(1);
}
for(int i=3600; i>10; i=i-6){ //move 360 degrees backward
myLSS.move(i);
delay(1);
}

The forward loop is substantially slower; taking around 30 seconds to traverse 360 degrees (jerks forward and pauses like the second hand of a clock), while the entire backward loop completes in around 1 second.

I am going to edit my code to read for position less often. As an aside, does anyone know if there is a way to query the servo position more efficiently?

1 Like

@Cucumber_Harvester If you’re able to get this far, you can likely create your own code without the need of the library (the serial communication protocol is really easy to understand). That way you control everything, including timing, delays etc.

Is there a way to query only the position of one servo? The getPosition() command seems to poll all 32 servos, which can be a waste of time.

1 Like

@scharette (creator of that library) might be able to offer some insight. Querying each servo normally is as simple as changing the ID number when sending a command.

1 Like

@o_lampe

The line in your post is exactly how you would do it.

The function is implemented in the library folder/LSS.cpp like this.
As you can see, it writes only to the address of the used LSS (i.e.: myLSS object) and only tries to read a reply from that single servo, too.

What makes you think it is polling from all 32 servos exactly?

@Cucumber_Harvester
What baud rate are you using with your LSS? If not doing so already, I recommend using the default baud rate, 115200.

Hi @scharette,

I’m using the default baudrate of 115200.

1 Like

You could try my second suggestion:

It may be better to simply calculate the time it will take to reach the requested position, then send the command to move, wait for the time it will take to do so, and send the other command.

If you set the max speed to 72 deg/sec it should take about 2.5 seconds to reach the next position (0 or 180) so you could wait that time (delay(2500)) and then you can send the query command, and if the condition is satisfied send the next move command, that way you don’t continuously request the position.

1 Like

That is a great idea! I second this! :slight_smile:
I’d go maybe a bit further and say maybe start querying for position a few hundred ms before and maybe every 50-100 ms after that until the condition is satisfied.
That way if there is a faster motion (such as when suddenly moving with gravity and load) or slower (against gravity with load) you can still be efficient.
As a side note if your polling (in loop) has no delay/time constraints, that will prob. cause you issues, too.

1 Like

Sorry, that was only wild guessing. I expected to see a getPosition(servoID) construct.
Would be handy when the servo movement I’m currently busy with, depends on another servos position.
e.g. if(getPosition(otherServo) >= xy)


1 Like