I am using an SSC-32 hooked up to 3 HSR-5990TG servos and driven via the serial port in my computer and a program I wrote using Visual Basic 2008. I am trying to drive the servos to follow sinusoids of the same freq but different phase smoothly for a robotics application. The critical part of the code is attached below. Ultimately what I am doing is splitting the sinusoid up in to multiple points using a timer and telling the servos to get to an updated position at each timer tick. I use the very convenient time to complete function of the SSC-32 group move to decide the velocities of the servos to complete the move on time before the next update. Of course, depending on the duration of the timer tick, the motion can be smooth (servos not able to move fast enough to reach the end position before the next signal is sent) or can be choppy if the servo has enough time to decelerate/stop at the desired end position.
It is desirable for the setup I am trying to build to have the sinusoidal motion smooth independent of the update rate/timer tick interval. So I modified the code such that the servos are first told to reach a certain position in a certain amount of time, then before that position is reached, they are told to go to another position. So the desired position is always leading the actual position. This works well, servo operation is smooth across a variety of update rates. To get a better idea about what I did, check out the picture below:
http://i19.photobucket.com/albums/b188/type11969/drivingvectors.png
The blue sinusoid is what I am trying to follow. The various colored lines represent the steps that I am telling the servos to follow. As you can see, before each step is completed, the servo gets an updated position. The penalty is a decrease in amplitude (although I’ve found the HSRs to overshoot a decent amount anyway). This penalty doesn’t really show itself unless the update is large.
So now for the problem/question/oddity. If I have the update rate set to 15ms (position updated every 30ms), the servos respond well. Same at 30ms, 90ms, 120ms, etc. They visually and audibly seem to be moving at the same speed. BUT, if I set the update rate set to 20ms, 40ms, etc or really anything off that 30ms multiple, the servos slow down dramatically even though the driving frequency is the same.
So what could be causing this? I think it boils down to the serial port or SSC-32 rates of some sort, but I am but a lowly Mech Eng so I don’t understand all that business. Any ideas?
Apologies for the length.
[code]Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If Time <= halfstep Then
Led1.Value = True
'phase00m = freq0 * (Time - dT) + phase0
'Vel0 = Math.Abs(Amp0 * (((1 / 2) * Math.Sin(phase00)) - ((1 / 2) * Math.Sin(phase00m))) / dT)
'If Vel0 <= 100 Then
'Vel0 = 100
'End If
Pos0 = initPos0 + Amp0 * ((1 / 2) * Math.Sin((freq0 * dT) + phase0))
'phase11m = freq1 * (Time - dT) + phase1
'Vel1 = Math.Abs(Amp1 * (((1 / 2) * Math.Sin(phase11)) - ((1 / 2) * Math.Sin(phase11m))) / dT)
'If Vel1 <= 100 Then
'Vel1 = 100
'End If
Pos1 = initPos1 + Amp1 * ((1 / 2) * Math.Sin((freq1 * dT) + phase1))
'phase22m = freq2 * (Time - dT) + phase2
'Vel2 = Math.Abs(Amp2 * (((1 / 2) * Math.Sin(phase22)) - ((1 / 2) * Math.Sin(phase22m))) / dT)
'If Vel2 <= 100 Then
'Vel2 = 100
'End If
Pos2 = initPos2 + Amp2 * ((1 / 2) * Math.Sin((freq2 * dT) + phase2))
knobPos0.Value = (Pos0 - 1500) / 11.1
'KnobVel0.Value = Vel0
KnobPos1.Value = (Pos1 - 1500) / 11.1
'KnobVel1.Value = Vel1
KnobPos2.Value = (Pos2 - 1500) / 11.1
'KnobVel2.Value = Vel2
SerialPort1.Write("#0 P" & Pos0 & "" + "#1 P" & Pos1 & "" + "#2 P" & Pos2 & "T" & numDT.Value & "" + Chr(13))
Time = Time + halfstep
inc = 1
ElseIf Time > halfstep Then
If inc = 1 Then
Led1.Value = False
Pos0 = initPos0 + Amp0 * ((1 / 2) * Math.Sin((freq0 * (Time + plusstep)) + phase0))
Pos1 = initPos1 + Amp1 * ((1 / 2) * Math.Sin((freq1 * (Time + plusstep)) + phase1))
Pos2 = initPos2 + Amp2 * ((1 / 2) * Math.Sin((freq2 * (Time + plusstep)) + phase2))
knobPos0.Value = (Pos0 - 1500) / 11.1
KnobPos1.Value = (Pos1 - 1500) / 11.1
KnobPos2.Value = (Pos2 - 1500) / 11.1
SerialPort1.Write("#0 P" & Pos0 & "" + "#1 P" & Pos1 & "" + "#2 P" & Pos2 & "T" & numDtplus & "" + Chr(13))
inc = 0
Time = Time + halfstep
ElseIf inc = 0 Then
Led1.Value = True
Pos0 = initPos0 + Amp0 * ((1 / 2) * Math.Sin((freq0 * (Time + dT)) + phase0))
Pos1 = initPos1 + Amp1 * ((1 / 2) * Math.Sin((freq1 * (Time + dT)) + phase1))
Pos2 = initPos2 + Amp2 * ((1 / 2) * Math.Sin((freq2 * (Time + dT)) + phase2))
knobPos0.Value = (Pos0 - 1500) / 11.1
KnobPos1.Value = (Pos1 - 1500) / 11.1
KnobPos2.Value = (Pos2 - 1500) / 11.1
SerialPort1.Write("#0 P" & Pos0 & "" + "#1 P" & Pos1 & "" + "#2 P" & Pos2 & "T" & numDT.Value & "" + Chr(13))
inc = 1
Time = Time + halfstep
End If
End If
End Sub
Private Sub Start_but_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles but_Start.Click
SerialPort1.Close()
SerialPort1.Open()
'Vel0 = 0
'Vel1 = 0
'Vel2 = 0
Time = 0
numDtplus = 1.5 * numDT.Value
dT = numDT.Value / 1000
halfstep = dT / 2
plusstep = dT + halfstep
initPos0 = 1500
Amp0 = 11.1 * sldAmp0.Value
phase0 = (Pi / 180) * sldph0.Value
freq0 = 2 * Pi * numFreq.Value
initPos1 = 1500
Amp1 = 11.1 * sldAmp1.Value
phase1 = (Pi / 180) * sldph1.Value
freq1 = 2 * Pi * numFreq.Value
initPos2 = 1500
Amp2 = 11.1 * sldAmp2.Value
phase2 = (Pi / 180) * sldph2.Value
freq2 = 2 * Pi * numFreq.Value
Pos0 = initPos0 + Amp0 * ((1 / 2) * Math.Sin((freq0 * Time) + phase0))
Pos1 = initPos1 + Amp1 * ((1 / 2) * Math.Sin((freq1 * Time) + phase1))
Pos2 = initPos2 + Amp2 * ((1 / 2) * Math.Sin((freq2 * Time) + phase2))
SerialPort1.Write("#0 P" & Pos0 & "" + "#1 P" & Pos1 & "" + "#2 P" & Pos2 & "T" & numDT.Value & "" + Chr(13))
knobPos0.Value = (Pos0 - 1500) / 11.1
KnobPos1.Value = (Pos1 - 1500) / 11.1
KnobPos2.Value = (Pos2 - 1500) / 11.1
inc = 0
Timer1.Interval = numDT.Value / 2
Timer1.Enabled = True
End Sub[/code]