New Parallax 360 Feedback Servo

12346

Comments

  • 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.

    Tom

  • twm47099twm47099 Posts: 632
    edited November 2017 Vote Up0Vote Down
    I've corrected a couple of errors, and it seems to work better.
    Tom
    I deleted the attachment - The fixed one is attached to the next post
  • 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.

    The new version is attached.

    Tom
  • Sounds good to me. One other thing I was thinking of for the pasm is a "constant velocity" mode. SetVelocity(servo, rpm). Sound useful?
    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
  • Found another error.
    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?

    Tom
  • The latter, for sure. Probably have to measure over "several" pulses.
    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
  • Any chance of replacing the circuit board in this servo?

    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...
    Prop Info and Apps: http://www.rayslogic.com/
  • 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?

    -Magi
  • MagiW wrote: »
    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?

    -Magi

    Welcome to the forums!

    Do you have a link to the hardware?


    Infernal Machine
  • Here is their website, there is a link to a PDF:
    http://www.revrobotics.com/REV-31-1153/

    -Magi
  • Hello everyone.

    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









  • Ptiago,
    Did you take a look at twm's C version about nine comments back?
    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
  • ptiagoptiago Posts: 32
    edited November 2017 Vote Up0Vote Down
    Tom,

    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 ?




  • twm47099twm47099 Posts: 632
    edited November 2017 Vote Up0Vote Down
    ptiago wrote: »
    Tom,

    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:
    cog360servo = cognew((void*)binary_FourPly_dat_start, MyParm);
    
    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.
  • Twm,

    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.

    Tom M.
  • 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.

    Mike
  • Which microcontroller are you using it with? The Propeller can easily resolve 1024 positions per rotation. The sensor itself is capable of resolving 4096.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • 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.

    148 = (83280 - 2768) / 544

    6.8 microseconds = 544/80

    Mike

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 21,772
    edited November 2017 Vote Up0Vote Down
    What program are you using? You should be getting much better resolution than what you're reporting.

    The output pulse widths from the encoder vary continuously. [See below.] They do not jump in 6.8 microsecond increments.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • 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:

    encoder_output.png

    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
    512 x 436 - 20K
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • Great news, now I have to figure out what code to use to best capture that.

    I'm using C code and not spin and have several choices, all of which work but have so far varying resolution issues.

    Mike
  • 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.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • 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.
      repeat
        pst.newline
        hightime := FBS.getRawHigh(servo0)
        lowtime := FBS.getRawLow(servo0)
        pst.dec(hightime)
        pst.char(" ")
        pst.dec(lowtime)
        pst.str(string("   "))
        pst.dec(hightime+lowtime)
        pst.str(string("   "))
        pst.dec(oldhightime-hightime)
        oldhightime := hightime
        pst.char(" ")
        pst.dec(oldlowtime-lowtime)
        oldlowtime := lowtime
        pst.str(string("   "))
        pst.dec(FBS.getpos(servo0))
        waitcnt(clkfreq/2+cnt)   
    

    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.
    1020 x 579 - 167K
    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
  • This is the code I settled on that runs in cog:
    void doPulse(void *par)
    {
      CTRA = 0x20000000 + Pin;
      FRQA = 1;
      
      while (1)
      {
        while (get_state(Pin) == 1);
        PHSA = 0;
        while (PHSA == 0);
        while (get_state(Pin) == 1);
        Position = PHSA;
      }
    }
    

    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
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 21,772
    edited November 2017 Vote Up0Vote Down
    iseries wrote:
    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.

    -Phil
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • I think the frequency may vary from unit to unit, as well.
    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
  • 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.
    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
  • 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).

    Tom M.
  • 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).

    Lemme think on it.
    Re-inventing the wheel is not a waste of time if, when you are done, you understand why it is round.
    Cool, CA, USA 95614
Sign In or Register to comment.