I ran some more tests. When I run the full scale range section of the demo, it seems that once "WaitSet" is called (which in turn calls "CheckDone" which returns "Complete") if the movement has not reached the target, the program stalls. I think that it is supposed to keep trying until it is at the target within the allowable error.
I replaced the full scale section with the following code:
for(int ii = 0; ii <=3; ii++)
{
MySet(1,gotodeg[ii]); // gotodeg[] defined as 180, 0, 359, 0
print("\n%d\n", gotodeg[ii]);
for(int iii = 0; iii <= 5; iii++)
{
err1 = gotodeg[ii] - GetPos(1);
print("%4d,%8d,%8d \n", err1, gotodeg[ii], GetPos(1));
pause(300);
}
}
The code shows how the actual approaches target.
And I varied the pause from 100 to 400. Then I looked at changing the gain parameter.
The results I got are listed below for a couple of cases for the motion from 0 to 259 and from 359 to 0.
Found another error. This one is what resulted in differences between the parameter values that work in Spin vs C. -- I was returning an array element from a function - bad.
These were my reflections from the first version:
I found that the parameters, particularly gain and Dmin required different values in the C program than they did in the Spin program. In the spin version, I used a gain of 12 for all 3 of my servos. The C version requires approx gain =18 to 24.
With the fix to my C program a gain of 12 works, but tuning for individual servos gives best running at 12 - 18.
Dmin in the Spin program was 30 for my 2 easy servos and 32 for the problem servo. In the C program, I have to use 38 for all the servos.
The corrected Dmin is now the same as used in the Spin version 29-30 for the good servos and 31 for the problem one.
Even then with the full scale changes (0 to 359 to 0) I had to add a long delay (1.5 to 2 seconds) between sending the position command and checking for complete. I also had to increase the allowable error. I can still have the problem servo freeze occasionally.
Now, no need for any programmed delay; the driver function CheckDone and its PASM does it automatically. With the good setting of Dmin - no more freezes.
Sounds good to me. One other thing I was thinking of for the pasm is a "constant velocity" mode. SetVelocity(servo, rpm). Sound useful?
Yes, it does. One of the tricky things if using these for robot wheels will be getting equal velocity of multiple wheels. Will 1500+70 give same rpm as 1500-70 or (I assume) will actual feedback in deg/time of each have to be measured and pulse be adjusted?
Hopefully there is someone here who is familiar with Rev robotics and their Expansion Hub. My question is: is this servo compatible and does the control signal frequency match the output on the REV hub?
Hopefully there is someone here who is familiar with Rev robotics and their Expansion Hub. My question is: is this servo compatible and does the control signal frequency match the output on the REV hub?
yes and no, before asking the question i unziped the file and i dig in and then i found this:
extern int binary_FourPly_dat_start[];
cog360servo = cognew((void*)binary_FourPly_dat_start, MyParm);
but where is linked/loaded the binary_FourPly_dat_start reference ?
I assumed it was not finished, I'm missing something ?
That statement refers to the FourPly.spin file included in the zip folder. It results in the PASM (DAT section of the spin program) being run when the statement:
If you are using SimpleIDE click on the button in the lower left corner of the window. That will open the Project frame. You should see the spin file listed. If it is not, click on Project in the menu and then on "Open Tab to Project:". That will give a file open screen. Change the file type to spin and double click on FourPly.spin. Then click on the Servo360driver tab in the main frame and you should be able to build and run the program.
Note that PASM can control 4 servos in 1 cog. I only have the main program running 3 servos since that's all I have. I've also used the driver to have one manually turned servo control a second.
Thanks for the help, it's my first time with spin, i really missed that detail.
I opened the file before, but i didn't find any reference to the c variable, but, makes sense in both assembly and c after the compilation there are no variables names, only references.
I'll need to study more
I have 4 servos, I'm surprised you need only one cog.
Tom Crawford wrote the Spin/PASM. I am a real Spin/PASM novice, but his program is nicely commented, and it's interesting to see how he managed to get 4 servos to work in one cog.
I was playing with some test code on the 360 servo and notice that the position sensor only returns 148 different positions as each position only varies by 6.8 microseconds.
So the closest angle that can be made would be about 2.4 degrees.
Which microcontroller are you using it with? The Propeller can easily resolve 1024 positions per rotation. The sensor itself is capable of resolving 4096.
I am using a Flip chip and the issue is that the 360 servo only resolves to that level.
I count the time the signal is high and I get a value between 83280 and 2768 with each value in between changing by 544 and sometimes it drops to 272 which is half of that value.
My post above would seem to imply that there is no granularity in the pulse-width outputs from the servo's encoder. But, after testing that assertion, I find that it's wrong. There is a discrete increment between adjacent pulse widths, and it's ~250 ns., as the following scope capture illustrates:
This was captured while slowly rotating the shaft between two closely-spaced angles and is consistent with the sensor chip's stated resolution of 4096 discrete pulse widths over a full rotation, which works out to a resolution of 0.088 degrees.
Here's how I do it in Spin; same should work for C:
1. Wait for encoder signal to go down. (Use waitpne.)
2. Wait for encoder signal to go up. (Use waitpeq.)
3. Read cnt.
4. Wait for encoder signal to go down. (Use waitpne.)
5. Read cnt.
6. Subtract first cnt reading from second one to get the pulse width.
Using the Prop's waitpeq/pne is important. If you do the checking in a loop, you will lose precision due to the loop overhead.
Here are some numbers. I fiddled my PASM driver to store the actual raw high and low periods in hub memory.
and Work1, #$1F 'feedback pin number
mov FBPinMask, #1 'form the mask for the feedback pin
shl FBPinMask, Work1
waitpne FBPinMask, FBPinMask 'get pulse width: wait for feedback low
waitpeq FBPinMask, FBPinMask 'then high
mov work1, cnt 'beginning of high feedback pulse
waitpne FBPinMask, FBPinMask 'wait for end of high pulse
mov HiPer, cnt
waitpeq FBPinMask, FBPinMask 'now wait for end of low pulse
mov LowPer, cnt
sub LowPer, HiPer 'calculate low period
wrlong LowPer, CAdFBLow 'save low period
sub HiPer, work1 'and high period
wrlong HiPer, CAdFBHigh 'save high period
mov y, HiPer 'calculate total period
add y, LowPer 'total period in tics
Then I fiddled the driver to just display the numbers, the total, the deltas from the previous pass, and the theta.
The servo was static with a pulse width of 1500. I sort of just put rotational pressure on the output member with my finger.
Attached is a screenshot. I am unable to explain the jitter, but the deltas are pretty clearly multiples of about 20. That is what I would expect for a total period of about 80K, divided by 4096.
I don't like to use CNT as it overflows and that is not accounted for in the process.
Yes, it can overflow and wrap around. But that's not a problem when you read two values in sequence, as I showed above, and subtract one from the other.
The low pulse time I found to be the same so measuring it is redundant.
At a given temperature, the overall frequency is likely to be constant. However, it may be temperature dependent. So you should always measure the low time, too, and use the ratio of the high time to the total time to get your pulse width percentage.
I have added constant velocity to my Fourplex driver.
@twm47099: Tom, the driver is strictly upward compatible from what I had before (it does take up more hub memory). I added two new methods:
SetVelocity(servo, RPM, CW_CCW) 'set it and forget it
GetPulseWidth(servo)
The key turned out to be the conversion from RPM to ClicksPerTic:
(RPM * 4096) / 3000
I completely redid the demo. It is sort of semi-interactive and does a much better job of showing what the driver can do. I especially like the Constant velocity demo; it sets a constant velocity and repeatedly displays the pulse width needful to maintain the velocity as one manually varies the load.
I will put this on OBEX in a week or so; I want to wait for some feedback, perhaps even from Parallax.
Tom,
I tried the demo (using spin) and it worked well. In line 71
FBS.width(theservo, (1460- (theservo * 5)))
I changed the 1475 to 1460 since my servo0 didn't move with a Pulse Width of 1475.
I'll port this to C and make a C library probably this weekend. I did make the previous version into a C library, I haven't posted it yet because I'm still not sure where I want to put some of the defines and variable declarations (the header file or require them in the user program.)
I wrote a C program using the library to calibrate the servos for use in an open loop robot drive as part of progressing to learn to write a closed loop drive. I'll put that on a back burner and use your new version to actually get the robot (an activitybot using the 360servos) working.
Is there a way to get the actual rpm from the pasm so it could be printed or transmitted as data to a control program (using an XBee for example).
It would be pretty easy to return the rpm in constant velocity mode, not so easy in fixed pulse width mode or set position mode (since I had no need to calculate it).
Comments
I replaced the full scale section with the following code: The code shows how the actual approaches target.
And I varied the pause from 100 to 400. Then I looked at changing the gain parameter.
The results I got are listed below for a couple of cases for the motion from 0 to 259 and from 359 to 0.
Tom
Tom
I deleted the attachment - The fixed one is attached to the next post
These were my reflections from the first version: With the fix to my C program a gain of 12 works, but tuning for individual servos gives best running at 12 - 18.
The corrected Dmin is now the same as used in the Spin version 29-30 for the good servos and 31 for the problem one.
Now, no need for any programmed delay; the driver function CheckDone and its PASM does it automatically. With the good setting of Dmin - no more freezes.
The new version is attached.
Tom
Tom
I've thought about making a QFN Propellerized servo for years...
Nice thing about 4-wires is that main board could talk to servo using simple serial I/O.
One wire for transmit and one for receive...
-Magi
Welcome to the forums!
Do you have a link to the hardware?
http://www.revrobotics.com/REV-31-1153/
-Magi
I would like to use the 360 feedback servo as multi-turn regular servo, position control and holding the position.
I'm using SimpleIDE and a Cog per servo and using a PID algorithm, the PID interval is 20 ms.
Position control without any torque is easy.
If i put some torque, the problems will start, back and forward, and i can't get the servo to stop.
I have a spent a lot of time trying to tune the PID parameters without success.
Can some help with a working solution ? What i really want is to replace a regular servo with the 360 feedback servo.
So no fast movements back & forward, responsive keeping the the position, etc. Is this possible ?
I can post the relevant code (cog code) if it helps, a full working project to test, but like, i said i don't know if a PID is the correct way to go.
Thanks
Did you take a look at twm's C version about nine comments back?
yes and no, before asking the question i unziped the file and i dig in and then i found this:
extern int binary_FourPly_dat_start[];
cog360servo = cognew((void*)binary_FourPly_dat_start, MyParm);
but where is linked/loaded the binary_FourPly_dat_start reference ?
I assumed it was not finished, I'm missing something ?
That statement refers to the FourPly.spin file included in the zip folder. It results in the PASM (DAT section of the spin program) being run when the statement: is executed.
If you are using SimpleIDE click on the button in the lower left corner of the window. That will open the Project frame. You should see the spin file listed. If it is not, click on Project in the menu and then on "Open Tab to Project:". That will give a file open screen. Change the file type to spin and double click on FourPly.spin. Then click on the Servo360driver tab in the main frame and you should be able to build and run the program.
Note that PASM can control 4 servos in 1 cog. I only have the main program running 3 servos since that's all I have. I've also used the driver to have one manually turned servo control a second.
Hope this helps,
Tom M.
Thanks for the help, it's my first time with spin, i really missed that detail.
I opened the file before, but i didn't find any reference to the c variable, but, makes sense in both assembly and c after the compilation there are no variables names, only references.
I'll need to study more
I have 4 servos, I'm surprised you need only one cog.
Tom M.
So the closest angle that can be made would be about 2.4 degrees.
Mike
-Phil
I count the time the signal is high and I get a value between 83280 and 2768 with each value in between changing by 544 and sometimes it drops to 272 which is half of that value.
148 = (83280 - 2768) / 544
6.8 microseconds = 544/80
Mike
The output pulse widths from the encoder vary continuously. [See below.] They do not jump in 6.8 microsecond increments.
-Phil
This was captured while slowly rotating the shaft between two closely-spaced angles and is consistent with the sensor chip's stated resolution of 4096 discrete pulse widths over a full rotation, which works out to a resolution of 0.088 degrees.
-Phil
I'm using C code and not spin and have several choices, all of which work but have so far varying resolution issues.
Mike
1. Wait for encoder signal to go down. (Use waitpne.)
2. Wait for encoder signal to go up. (Use waitpeq.)
3. Read cnt.
4. Wait for encoder signal to go down. (Use waitpne.)
5. Read cnt.
6. Subtract first cnt reading from second one to get the pulse width.
Using the Prop's waitpeq/pne is important. If you do the checking in a loop, you will lose precision due to the loop overhead.
-Phil
Then I fiddled the driver to just display the numbers, the total, the deltas from the previous pass, and the theta.
The servo was static with a pulse width of 1500. I sort of just put rotational pressure on the output member with my finger.
Attached is a screenshot. I am unable to explain the jitter, but the deltas are pretty clearly multiples of about 20. That is what I would expect for a total period of about 80K, divided by 4096.
I don't like to use CNT as it overflows and that is not accounted for in the process.
Since PHSA always counts up from zero it works. Dividing it by 80 gets me milliseconds.
The low pulse time I found to be the same so measuring it is redundant.
Mike
At a given temperature, the overall frequency is likely to be constant. However, it may be temperature dependent. So you should always measure the low time, too, and use the ratio of the high time to the total time to get your pulse width percentage.
-Phil
@twm47099: Tom, the driver is strictly upward compatible from what I had before (it does take up more hub memory). I added two new methods:
The key turned out to be the conversion from RPM to ClicksPerTic:
I completely redid the demo. It is sort of semi-interactive and does a much better job of showing what the driver can do. I especially like the Constant velocity demo; it sets a constant velocity and repeatedly displays the pulse width needful to maintain the velocity as one manually varies the load.
I will put this on OBEX in a week or so; I want to wait for some feedback, perhaps even from Parallax.
I tried the demo (using spin) and it worked well. In line 71 I changed the 1475 to 1460 since my servo0 didn't move with a Pulse Width of 1475.
I'll port this to C and make a C library probably this weekend. I did make the previous version into a C library, I haven't posted it yet because I'm still not sure where I want to put some of the defines and variable declarations (the header file or require them in the user program.)
I wrote a C program using the library to calibrate the servos for use in an open loop robot drive as part of progressing to learn to write a closed loop drive. I'll put that on a back burner and use your new version to actually get the robot (an activitybot using the 360servos) working.
Is there a way to get the actual rpm from the pasm so it could be printed or transmitted as data to a control program (using an XBee for example).
Tom M.
Lemme think on it.