Servo hunting

I am developing an arm using 3 MG995 servos, piicodev Driver board and Raspberry Pi 5
One or more of the servos will hunt or oscillate violently after it has arrived at its angle. When one starts it can lead to other servos hunting. The voltage at the source (12V SLA battery) remains quite stable.

Hi @Geoff45102,

We have a couple of theories for what could be causing this.

One thought is it could be that under load the servo is overshooting causing it to overcorrect. This could then be sending enough force into the other servos causing them to also do the same.

Another thought is there could be crosstalk or interference between the PWM signal lines of the servos. This can happen with longer parallel runs especially.

If you could share some pictures or videos of the setup it might help to identify the cause. You could also try seeing if the issue still occurs with just one servo at a time and if it doesn’t add one more until you find where the issue is originating from.

1 Like

With only one servo connected I have put a cro on the signal and supply leads. They appear quite clean. I can instigate an oscillation by physically pushing on the arm. It seems that the cause is within the servo. Is there some way of damping its feedback loop?

1 Like

Hi Geoff,

Could you share your code? Its easier to recommend some solutions with the bigger picture.

1 Like

The servo positioning information is an analog signal. Any interference from something like capacitive coupling is going to affect that signal rather than the power supply. The only way you could fix that problem is to invest in a better servo.

If you have a number of servos to test you will find significant differences in their stability.

1 Like

This is the code.
Servos 2 and 3 are electrically disconnected.
I feel that the problem is a mechanical one rather than a coding one.

from gpiozero import Button

from PiicoDev_Unified import sleep_ms
from PiicoDev_Servo import PiicoDev_Servo, PiicoDev_Servo_Driver

# Initialise the Servo Driver Module
controller = PiicoDev_Servo_Driver() 

# Simple setup: Attach a servo to channel 1 of the controller with default properties
servo_1 = PiicoDev_Servo(controller, 1)
servo_2 = PiicoDev_Servo(controller, 2)
servo_3 = PiicoDev_Servo(controller, 3)

# Customised setup - Attach a servo to channel 1 of the controller with the following properties:
#    - min_us: the minimum expected pulse length (microsecconds)
#    - max_us: the maximum expected pulse length (microsecconds)
#    - degrees: the angular range of the servo in degrees
# Uncomment the line below to use customised properties
# servo = PiicoDev_Servo(controller, 1, min_us=600, max_us=2400, degrees=180)



inc_1 = 5

angle_1 = 0
servo_1.angle = 0

angle_2 = 180
servo_2.angle = 180

angle_3 = 180
servo_3.angle = 180
#angle_4 = 5

def joint_1_add():
    global angle_1 
    angle_1_old = angle_1
    angle_1 = angle_1 + inc_1
    if angle_1 >= 180:
        angle_1 = 180
    print("1 " + str(angle_1))

    for x in range(angle_1_old,angle_1,1):
        servo_1.angle = x
        sleep_ms(100)                                                                                  

def joint_1_sub():
    global angle_1
    angle_1_old = angle_1
    angle_1 = angle_1 - inc_1
    if angle_1 <= 0:
        angle_1 = 0
    print("1 " + str(angle_1))

    for x in range(angle_1_old,angle_1,-1):
        servo_1.angle = x
        sleep_ms(100)                                                                                  
       
button_1 = Button(pin=17,bounce_time=0.05)
button_2 = Button(pin=5,bounce_time=0.05)

button_1.when_pressed = joint_1_add
button_2.when_pressed = joint_1_sub

#********************************************************

def joint_2_add():
    global angle_2 
    angle_2_old = angle_2
    angle_2 = angle_2 + inc_1
    if angle_2 >= 180:
        angle_2 = 180
    print("2 " + str(angle_2))

    for x in range(angle_2_old,angle_2, 1):
        servo_2.angle = x
        sleep_ms(100)                                                                                  

def joint_2_sub():
    global angle_2
    angle_2_old = angle_2
    angle_2 = angle_2 - inc_1
    if angle_2 <= 0:
        angle_2 = 0
    print("2 " + str(angle_2))

    for x in range(angle_2_old,angle_2,-1):
        servo_2.angle = x
        sleep_ms(100)                                                                                  
       
button_3 = Button(pin=27,bounce_time=0.05)
button_4 = Button(pin=22,bounce_time=0.05)

button_3.when_pressed = joint_2_add
button_4.when_pressed = joint_2_sub


#********************************************************

def joint_3_add():
    global angle_3 
    angle_3_old = angle_3
    angle_3 = angle_3 + inc_1
    if angle_3 >= 180:
        angle_3 = 180
    print("3 " + str(angle_3))

    for x in range(angle_3_old,angle_3,1):
        servo_3.angle = x
        sleep_ms(100)                                                                                  

def joint_3_sub():
    global angle_3
    angle_3_old = angle_3
    angle_3 = angle_3 - inc_1
    if angle_3 <= 0:
        angle_3 = 0
    print("3 " + str(angle_3))

    for x in range(angle_3_old,angle_3,-1):
        servo_3.angle = x
        sleep_ms(100)                                                                                  
       
button_5 = Button(pin=19,bounce_time=0.05)
button_6 = Button(pin=6,bounce_time=0.05)

button_5.when_pressed = joint_3_add
button_6.when_pressed = joint_3_sub

# 
# #********************************************************
# 
# # def joint_4_add():
# #     global angle_4 
# #     angle_4_old = angle_4
# #     angle_4 = angle_4 + inc_1
# #     if angle_4 >= 180:
# #         angle_4 = 180
# #     print(angle_4)
# # 
# #     for x in range(angle_4_old,angle_4,1):
# #         servo_4.angle = x
# #         sleep_ms(100)                                                                                  
# # 
# # def joint_4_sub():
# #     global angle_4
# #     angle_4_old = angle_4
# #     angle_4 = angle_4 - inc_1
# #     if angle_4 <= 0:
# #         angle_4 = 0
# #     print(angle_4)
# # 
# #     for x in range(angle_4_old,angle_4,-1):
# #         servo_4.angle = x
# #         sleep_ms(100)                                                                                  
# #        
# # button_7= Button(pin=16,bounce_time=0.05)
# # button_8 = Button(pin=6,bounce_time=0.05)
# # 
# # button_7.when_pressed = joint_2_add
# # button_8.when_pressed = joint_2_sub
1 Like

Thanks Jeff. Could you recommend a better servo, possibly with a position output lead.

1 Like

Hi Geoff,

You may find that a servo smoothing library or function may help.

James Bruton did a similar thing for this project in Arduino.

1 Like

Hi Geoff

That is possibly one way you WILL damage a servo.

The “feedback loop” is usually mechanical. It is usually a potentiometer connected somewhere in the gear train so it is in exactly the same position as the arm WRT its own 270Âș of rotation. I don’t know the exact details but I would think this potentiometer tells the built in smarts exactly where the arm is. When a control signal is received to change that position the motor driver the arm in such a direction it moves to that position requested. I don’t see how it could be “damped”.

If it is a speed problem as indicated in your other post reducing the supply voltage to slow down the movement might help as I replied just now.

The 2 posts might be getting a bit interconnected here.
Cheers Bob

EDIT:
As has been suggested it might be a case of that particular servo not being able to handle your task in a satisfactory manner and a better quality device could be your answer.
Cheers Bob

2 Likes

You have answered your own question - the feedback loop is contained within the servo. Usually it is a direct connection on the PCB from the pot to the controller. That’s why I suggested that the answer is to buy a better quality servo - the manufacturer may have implemented a better form of pot, better shielding for the analog signal, adequate bypass capacitance for the power leads and perhaps some logic in the controller to detect excessive minor movement. You pretty much get what you pay for in servos. But if you buy a lot of the cheap ones and select the best of them you can minimize the problem.

1 Like

It can be ‘damped’ by moving the servo to the desired position in small steps with a delay inserted between steps (see above). But that’s not the problem. The problem is that when the servo is powered up it moves immediately to a default position, and that move is always at full speed. Perhaps some servos don’t have a default position, but that doesn’t solve the problem because the first movement (even if done slowly) will be from an unknown starting position and that will happen at full speed. Note that increasing the supply voltage may make the problem worse, as it could create overshoot and hunting.

1 Like

Hi Jeff

Yes that would work. It would require a bit more coding. The delay could be minimal or might not be needed if the position were changed in say 1Âș or smaller increments. It depends on what the minimum increment is possible with the driving set up. I suggest a delay might not be needed as it is impossible for a motor to go from standstill to full speed instantaneously. There will be a finite time involved. If this were known it might be possible to determine if a delay was needed but as this is unknown a bit of experimenting would be needed.

But experimenting is probably what this Forum is all about.
Cheers Bob
Add on:
I did suggest in the other post to try lowering the supply voltage of the overall speed was too high. This should also improve the hunting.

1 Like

Hi Jeff

Will a servo move to a default position if powered up in the absence of a control signal? I would have thought they would not go anywhere if no control pulse is present. I have never tried it but I think I can find one and see what happens.

Cheers Bob

1 Like

The ones I have tested here move to their centre position on powerup, but I have never seen this mentioned in a specification and it likely differs between manufacturers. Or, it might be a ‘feature’ of the servo library. When it happens it is the reason that moving to the preferred startup position before shutting down doesn’t work.

1 Like

Hi @Geoff45102,

This is certainly an interesting issue.

As others have said, the “feedback loop” is physical. The MG995 servos have a notch connected to a potentiometer that sends a proportional position to the control circuit. It’s not the kind of thing you can modify very easily. I have found this image of a deconstructed one that might help to explain.

image

Regarding the servo returning to a “home” position, I have heard of this functionality, but I can’t imagine this is hardware-related. Is the control signal analog? I had assumed it was a standard digital out, but perhaps if it is analog it may start with the pin at ground and immediately send the servo to a zero position? That feels far fetched, but just thinking out loud I suppose. My guess is that it is code related.

Is there any chance you could send some images of the arm itself, and possibly some code snippets?

Thanks,
Zach

1 Like

Hi Geoff,

These are definitely linked, would it be possible to send through a photo or video of your setup? (A video would be a lot more helpful). There might be some mechanical additions you could make to your project to get rid of the oscillation (at a cost).
Once some photos come through we might be able to offer some advice here.

On the electronics side, if your servo is digital it uses a comparison to move to the desired angle, am i to the ‘left’ of the set point = move right, until it gets there (within some deadband). Then stop
This is an OK control strategy for most use cases of the servo, but it sounds like your robot arm might be a bit outside the tested cases.

One definite solution to your other forum topic, knowing where the servo is - is to disassemble the servo and solder to the wiper of the pot inside and measure the voltage from your micro.

Keen to see it all come together (and some photos in the meantime!)
Liam

Hi Geoff.
I just had a look at the schematic for the PicoDev servo driver.
The Logic ground is designated with a small triangle while the Power ground (Servo power) is designated with a different symbol.

Please make sure these 2 grounds ARE CONNECTED together. This is not obvious on the schematic and would be in doubt.

There is a bit on bottom right of the schematic which suggests they might be connected. It is designated “NT1, NetTie_2”. Now I don’t know what all this means. Perhaps someone at Core could enlighten please. If this “NetTie_2” is not present the 2 grounds would not be connected.
Cheers Bob

If they are not connected there is no ground return for the control signal to the servos and might explain at least the mutual interference where you say moving one causes the others to oscillate. Could cause the unstable operation resulting in your oscillation.

Geoff
URGENT. URGENT

STOP IMMEDIATELY

I just had a look at several data sheets for a MG995 Servo

They all say operating voltage between 4.8V and 7.2V.

There is little wonder your servo seems to traverse as you say “Violently”

This would not help with the “hunting” either.

If you haven’t destroyed the electronics get the supply to within specified range and try again.

I would get 3 new servos anyway as any damage due to over voltage could be cumulative and fail down stream.
Cheers Bob

Thanks everyone for your comments. I re checked the data sheets myself to discover the correct voltage rating. With 6V supply, the hunting is gone. As the arm is for a one off job I can set the various servos to their start up positions (more or less) to get away from the rapid start up movement.

The purpose of the arm is to thread a weighted mouse line into the halyard pulley on top of a 15 metre mast of a sail boat. At 82, the powers that be have banned me from going up the mast so this arm will be hoisted up on a working halyard. That’s the theory anyway.

2 Likes

Hi Geoff
Well, that is quite an unusual project. Good to see that there is some practical use for your efforts and I wish you every success.

Be aware of any cumulative damage that may have occurred due to the over voltage which was near double recommended maximum. If anything should go wrong in the future that requires servo replacement just fit a new one and put it down to experience. A lesson can be learned from all mistakes. This one being that data sheets can be your friend and unless you are very familiar with a device referring to them is pretty well a must.

I am 88 (nearly 89) and I have been banned from even the humble ladder for a while now so I know the feeling. And to think I used to do some work on TV transmitting antennas 500 to 700 feet off the ground. Yes thems were the days.
Cheers Bob

1 Like