Shop OBEX P1 Docs P2 Docs Learn Events
Fastest method to share VAR between 2 P1's — Parallax Forums

Fastest method to share VAR between 2 P1's

T ChapT Chap Posts: 4,217
edited 2024-05-08 15:15 in Propeller 1

I have a P1 board that drives 1 BLDC motor with encoder and the code is very involved, the P1 is maxed out for cogs and ram.

I have a project that requires 3 motors and am thinking to add a second P1 to the board to handle the excess, using existing working code. I want the P1MainBoard to act as if it some values in it that are actually values used in the P1SubBoard VAR space and cogs. There could be 10-20 Longs that need to be shared in real time as fast as possible. Most of the values are only moving from the P1SubBoard > P1MainBoard constantly in repeat. A few might move from P1MainBoard > P1SubBoard on demand. The goal is to try to keep existing code as in tact as possible, just move some engine blocks to another P1. But to keep code intact the values from the SubBoard must be read very fast in a loop that never stops sending.

In thinking about this, it looks like many objects will have to get moved the SubBoard and the MainBoard can send Opcodes with values to the SubBoard serially as commands with updates, then the SubBoard drives the objects and does the work. A typical example for one of the three motor engines is a PID that is driving an SPI DAC for motor speed, Direction Pin, checking encoder position. Each PID loop is a cog(x3). SPI DAC motor speed for all 3 motors can be 1 cog(use Chip select 1/2/3 in one SPI loop ie 1 cog). Checking three quad encoders for 3 motors is 3 cogs.

SubBoard 3+1+3 = 7cogs plus a main loop keeping things updated and sharing data = 8

VARs SubBoard to MainBoard in a fast loop, never stops.
LONG EncoderValue1, EncoderValue2, EncoderValue3
WORD MotorSpeed1, MotorSpeed2, MotorSpeed3
Byte ErrorMessage1, ErrorMessage2, ErrorMessage3

VARs MainBoard to SubBoard as needed.
BYTE MotorEnable1, MotorEnable2, MotorEnable3
WORD MotorSpeed1, MotorSpeed2, MotorSpeed3

This is just a starting point of hashing this out, surely more to add to each VAR section for sharing. But I first need to get a plan as to how to do this to get a board underway with 2xP1 chips. With P1's next to each other on a PCB, one option is fast serial. The SubBoard could send a packet with a packet header Opcode and always include a fixed length of values following. The MainBoard looks for the packet header, and reads all subsequent values into their respective VAR values. 256k possible? 128 should be easy I think. A repeat loop in SubBoard is always waiting for 1ms for a byte to come in from MainBoard with an Opcode and optional data bytes. If it sees a valid Opcode, it handles the request, then resumes sending data.

SubBoard

PUB MainLoop
     WaitForByte(1).  ' wait 1 ms for a byte.  if no byte continue
         'If opcode > 0
             ' Do the command
     SendData
       'Send all data in a packet back to MainBoard

Thanks for any suggestions on how to do this.

«1

Comments

  • With short traces, you can do 20Mbaud serial between two P1: https://forums.parallax.com/discussion/110325/fyi-single-wire-high-speed-serial-link-updated-20110514 . They must both be running the same clock speed and requires a cog running ASM to handle the communication.

    A thing to take note of: VAR sections don't always store data in the same order you declare it. It always puts long-sized variables first, then word-sized ones, then byte-sized ones (for alignment reasons).

    Relatedly, if you want to reduce your RAM usage a little, take note that the order of variables (both VAR instance variables and PUB/PRI local variables) matters to the code size (and by extension, speed!). In particular:

    • The first 8 long-sized variables take 1 byte

      • note that in case of local variables, the result variable always takes the first slot, even if no value is intended to be returned. So abuse the result variable where you can (also of course saves 4 bytes of stack)
    • Any variable in the first 128 bytes takes 2 bytes

    • All other variables take 3 bytes
  • MicksterMickster Posts: 2,629
    edited 2024-05-09 07:15

    T Chap> @"T Chap" said:

    A typical example for one of the three motor engines is a PID that is driving an SPI DAC for motor speed, Direction Pin, checking encoder position.
    Each PID loop is a cog(x3).

    Why not all PIDs in one cog?
    My method would be 2 cogs but only because only two counters/cog which I used for PWM. 80_000_000/19_531 = 4096 (12 bits of +/- 10V motor command)

    Checking three quad encoders for 3 motors is 3 cogs.

    This reads like you are back to reading encoders directly on the Prop instead of the LS7366Rs?
    I have a pretty slick alternative that I am playing with right now, using the high-speed state-machines (PIO) of the RPi Pico to read 4 incremental encoders.
    Thinking; deliver positions from all 3 of your encoders via UART, continuously streaming? Two Prop pins instead of.....
    PM me if you want further details B)

    Craig

    Edit: Or, thinking about it, use the extra P1 solely for quad decode/counting and deliver all positions over even a single pin.
    Then put all 3 PIDs in a single cog. For 99.99% of applications, PID sampling @1KHz is easily enough.

  • T ChapT Chap Posts: 4,217

    Thanks for the comments.

    Mickster, I use 7366 all the time now! But it is much more involved to use those vs simple encoder objects, they are great for certain applications for sure most especially when I must have the position stored even on Propeller reboot, power out etc. LS7366 always has it's own battery backup.

    Timing for some PID projects is critical especially since my PID is SPIN, trying to run 3 motors in a single PID(my version) would radically affect perfected PI timings and I am trying to not rewrite code as much as possible. My PID is doing lots of things, including adding deadband ranges(set a range the PID can allow for not being so perfect when motor is stopped, BUT must move to perfect locations when moving THEN switch to user definable deadband margin for position error), stall detection( no encoder movement when it should have moved). As you know the larger the loop ie cycle time the more oscillation(overshooting an encoder line back and forth trying to lock in on the destination position). SPI in a loop with 3 encoders > LS7366 is much more time than a PASM dedicated to 1 encoder. It would be tons of work to merge 3 PID engines into one( ideally merge 3 SPIN PID to 1 PASM), and I don't want to do it.

    There is already a lot of work to do the custom 3 motor additional code, so I don't want to add more learning curve.

  • MicksterMickster Posts: 2,629
    edited 2024-05-09 14:44

    @"T Chap" said:
    Thanks for the comments.

    Mickster, I use 7366 all the time now! But it is much more involved to use those vs simple encoder objects, they are great for certain applications for sure most especially when I must have the position stored even on Propeller reboot, power out etc. LS7366 always has it's own battery backup.

    Timing for some PID projects is critical especially since my PID is SPIN, trying to run 3 motors in a single PID(my version) would radically affect perfected PI timings and I am trying to not rewrite code as much as possible. My PID is doing lots of things, including adding deadband ranges(set a range the PID can allow for not being so perfect when motor is stopped, BUT must move to perfect locations when moving THEN switch to user definable deadband margin for position error), stall detection( no encoder movement when it should have moved). As you know the larger the loop ie cycle time the more oscillation(overshooting an encoder line back and forth trying to lock in on the destination position). SPI in a loop with 3 encoders > LS7366 is much more time than a PASM dedicated to 1 encoder. It would be tons of work to merge 3 PID engines into one( ideally merge 3 SPIN PID to 1 PASM), and I don't want to do it.

    There is already a lot of work to do the custom 3 motor additional code, so I don't want to add more learning curve.

    Good to learn that the 7366 suspected reliability issue has presumably been resolved. The darned things are just not readily available in the UK - the Click module is, but too bulky. Turns out that; in addition to two cores, the Pico has PIO state-machines (I guess their answer to smart pins). These run totally independent to the two cores and are programmed using asm. The P1 encoder reading speed for me is too limited so with the Pico, I can handle many MHz. I run a simple program on one of the cores that reads the encoder counts and zaps the four longs out the COM port (921600 Baud). So a high-speed, four-encoder interface for pocket-change.

    I am a fan of the Flexprop suite and use FlexBasic (fast). I don't do Spin but doesn't FlexProp take existing Spin code and compile it? In summary, it seems to me that a relatively slow interpreter is forcing you to add another device(?)

    Craig

  • What about a P1 board to drive each motor and one P1 is the master that commands the three motor boards. I would configure the motor board as PID with encoder feedback. So the main board could send command to a motor board, lets say +10000, meaning 10 inches of movement in the positive direction on the motor board etc. like a servo driver

  • JonnyMacJonnyMac Posts: 8,965

    I agree with Bob: make a single motor board that has a network connections (e.g., RS-485). Use a 6.25MHz crystal to get 100MHz system clock and have a single P1 devoted to one motor. This simplifies everything, and when you later want to control five motors you're just adding those motor blocks and addressing them from your main controller.

  • evanhevanh Posts: 15,290

    Always depends. :) I recently did an industrial application where the whole reason for doing a custom board was because of space constraints in a rotary head and the related slip-ring count. Otherwise we wouldn't have spent the effort on a custom board at all and just purchased off the shelf instead.

    Ended up with two boards powering 16 small stepper motors. A Prop1 surrounded by 8 drivers on each board. Four slip-rings: Two for power, two for Modbus485.

    Two motors per Cog. Application only needed cut-to-length type control so no axis coordinating nor complex profiles. Just move to a position.

  • evanhevanh Posts: 15,290

    ManAtWork is doing the full high performance universal motion coordination solution using EtherCAT - https://forums.parallax.com/discussion/175668/ethercat-experiments/p1

  • T ChapT Chap Posts: 4,217
    edited 2024-05-10 13:20

    @JonnyMac said:
    I agree with Bob: make a single motor board that has a network connections (e.g., RS-485). Use a 6.25MHz crystal to get 100MHz system clock and have a single P1 devoted to one motor. This simplifies everything, and when you later want to control five motors you're just adding those motor blocks and addressing them from your main controller.

    This is what I have already done, my biggest loss of time and money to date :) . I am now converting the whole system to one box. One master P1 and a P1 that runs 3XPID for 3 motors, 3 encoders, read current on 3 motors.

    You can see the main P1 box with LCD screen and below the first box with P1 of 3, daisy chained RS485.

    Mickster, I have rethought the LS7366 and am going with 3 of those and will create a PASM object that reads the 3 encoders in one COG, and the positions all live in the SubBoard for use in PID, but positions are sent in a loop to the MainBoard using the yet TBD fast interface originally posted about. The main board is what is keeping track of all positions and doing all the local control. 3 motors will be driven from 1 P1 doing only PID, encoder reads, DAC motor-speed output to the separate motor driver boards.

  • T ChapT Chap Posts: 4,217

    @DigitalBob said:
    What about a P1 board to drive each motor and one P1 is the master that commands the three motor boards. I would configure the motor board as PID with encoder feedback. So the main board could send command to a motor board, lets say +10000, meaning 10 inches of movement in the positive direction on the motor board etc. like a servo driver

    Yes this is what it is. But the existing system is a box with P1, LCD and software to synchronize and command the others. Then there are 3 separate systems with P1, single motor control. All communication with the Main Box is RS485. Too much work programming multiple boxes each time a change is needed in protocol etc. I am converting it all to one box, 1 Main P1, 1 MotorDriver P1 with 3 PID driving the motors and reading encoders. It will be much simpler this way. I was mainly trying to look at options for how to stream position from one P1 to the other. I don't have any concerns about the rest. I don't even think this needs super high speed as the positions streaming back to MainBoard are only for reference, since PID is on the sub board P1. I think 256K - 512k is more than fine.

  • T ChapT Chap Posts: 4,217

    This is similar to the end result, except the Main Board will have the second P1 added to it, and add a third BLDC motor board. Add a second USB port for the second P1.

  • @evanh said:
    ManAtWork is doing the full high performance universal motion coordination solution using EtherCAT - https://forums.parallax.com/discussion/175668/ethercat-experiments/p1

    Haha, let's say I tried to. It's still not working, at the moment. What does work reliably is the way Jon suggested it.
    see: https://forums.parallax.com/discussion/166716/cnc-i-may-be-crazy-but
    One P1 as master controller that is connected to several motor controllers over RJ45 cables. The master calculates the trajectory and each motor controller handles one encoder and the PID loops for one motor.

  • JonnyMacJonnyMac Posts: 8,965
    edited 2024-05-11 01:31

    ...will create a PASM object that reads the 3 encoders in one COG [snip]

    I can save you some trouble. I wrote this code a long time ago (started in 2012), and other than freshening the (c) date and matching my current formatting, I haven't changed anything. This code was used in Camera Turret and JonyJib products, so it has had commercial testing. That said, do check things carefully

    I know that high speed is important to you, and there is a bit of a speed bump in this code: in order to allow flexible connections there is a chunk of code required to get the current state of the encoder inputs and put them in the correct order with bit0 alignment.

    sample                  mov       rawpins, ina                  ' snapshot of inputs
                            test      rawpins, e0amask      wc      ' get enc1 bits
                            muxc      newscan, #%00_00_01           
                            test      rawpins, e0bmask      wc       
                            muxc      newscan, #%00_00_10           
                            test      rawpins, e1amask      wc      ' get enc2 bits
                            muxc      newscan, #%00_01_00           
                            test      rawpins, e1bmask      wc       
                            muxc      newscan, #%00_10_00           
                            test      rawpins, e2amask      wc      ' get enc3 bits
                            muxc      newscan, #%01_00_00           
                            test      rawpins, e2bmask      wc       
                            muxc      newscan, #%10_00_00                     
    sample_ret              ret
    

    If you can guarantee that your encoder inputs will be connected in a contiguous group of pins in this order e2b_e2a_e1b_e1a_e0b_e0a, you can simplify the setup and sampling code.

    sample                  mov       newscan, ina                  ' snapshot of inputs
                            shr       newscan, e0pin                ' align to bit0
                            and       newscan, #%00111111           ' clean-up on aisle 6
    sample_ret              ret
    

    In this case, creating the pin masks is not needed, you just need to read the e0a pin from the address packed in par so you can right shift the inputs. You may consider building a mask instead of assuming all are connected so that you could disable encoder 1 or 2 if necessary.

    Or, you can contact me offline and I'll create the derivative version for you at my customary fee. ;)

    Update: While enjoying a cup of coffee I was scanning the code and found a small, non-lethal bug. Though it didn't hurt anything, it could affect read speed. It's fixed now. The corrected version has 10 MAY 2024 as the last update

  • If I had to re-invent this wheel, I would still go with one motor and one encoder per P1, this way all the cogs can be used for one axis.
    On another note I was just curious what a JM fee would set me back in $$$$$ ?

  • MicksterMickster Posts: 2,629
    edited 2024-05-11 12:37

    @JonnyMac
    T Chap and I are doing similar stuff and one of the really neat things about using the LS7366R device; it is SPI and has it's own 5V UPS to keep the device + encoder alive during power-down (it also features a lost-power flag in case the UPS dies). Re-homing a machine can be a royal PITA. This way, the machine can be powered-up in a morning and ready-to-roll. Should any of the axes get disturbed during power-down, no problem because the 7366 keeps counting - effectively, an absolute encoder. Furthermore, in my case, the encoder counting rate needs to be way more than the P1 can handle. The 7366 is good for 40M counts/sec when using differential receivers. I seem to remember that T Chap's encoders are open collector so not true in his case but still way faster than the P1 can handle. I'm doing similar but I have substituted a RPi Pico for the 7366. I can have the Pico on a UPS and handle 4 encoders at high-ish count-rates. OTOH, if the P1 is fast enough for T Chap, he could have a UPS-backed P1, dedicated to simply reading 3 encoders and banging-out the 3 longs, serially. On power-up, the main P1 just starts RX-ing the 3 longs.

    Of course for a re-design, the P2 makes more sense because the smart-pins can handle quadrature and DAC directly, has more pins, memory, speed, etc. If still using the Click 1917 module X 3, cost-wise, we're in P2-Edge territory.

    @T Chap

    No idea what your code looks like and I know very little about Spin but I seem to remember reading that @80MHz, the granularity is ~5uS or 200 ops in a 1ms window? That should be plenty for 3 PIDs.
    In fact, from what I've seen of your machines, even 2ms (500Hz sample) would be more than adequate (considering mechanical time-constants, etc.)

    I suspect that you have a continuous PID where you are repeatedly multiplying by the sample time and using floats? The discretized method and using integers is far more efficient. Which reminds me; there is a continuous PID in the OBEX by cweber that needs to go away, it's flat wrong, can never work.

    DO
    waitcnt (sample time....I recommend 2ms)
    
    PID + offsets (Aff, Vff, integral anti-wind-up) using only integers for 3 axes
    
    Velocity profiler (accel, slew, decel) for 3 axes
    LOOP
    
    

    Gut feeling (only) is that this is achievable.

    Craig

  • MicksterMickster Posts: 2,629

    @DigitalBob said:
    If I had to re-invent this wheel, I would still go with one motor and one encoder per P1, this way all the cogs can be used for one axis.

    I am a big fan of DCS (distributed control systems) for many reasons not least of which is the wiring. A central controller for say, 6+ axes - a rat's nest is hard to avoid. :#

    Craig

  • T ChapT Chap Posts: 4,217

    @JonnyMac Thanks for that info and code for 3 encoders. I have been using your single encoder object a lot lately and it works great. The I also use the LS7366 SPI encoder chip on lots of projects where I want the position to be retained in power outages and every time the P1 reboots. In this case, I am switching this system to the LS7366 to eliminate some needs to totally re-home the system to reset the encoders to 0. With an SPI loop in a cog even in spin for 3 encoders it's pretty good but may convert the SPIN COG to PASM if needed later.

    @DigitalBob and @mickster Yes this idea of one motor - one P1 is the the way. After many hours of thought, running 3 motors the way I need to here is not possible with a MainBoard P1 and a SubBoard P1. There are many moving parts to drive one motor. There is a COG for the Profile Generator( drives the motion profile - Accel, Decel, handles current trips, stalls, Estop deceleration, reverse direction decel and re-accel in reverse, many things already dialed in). Then there is the PID - really PI only. These 2 sets of code are so dialed in I cannot touch them. Then you need a COG for reading the encoder, a COG fo driving the MotorSpeed DAC, and a main programing overseeing everything and checking current setting /comparing to dynamic trip levels.

    There will be a main P1 board with LCD, buttons, io. Here is an image I started to hold the P1 Motor Controller section. This will then connect to the BLDC motor driver board which is separate.

    Main (io, communicate with MainBoard, stream out position ).
    Profile Generator (accel, decel etc)
    PI(D)
    DAC MotorSpeed MCP4922
    Read Encoders via LS7366
    Check Current and compare to stored trip levels
    Serial Object

    It's always great getting the feedback here! Thanks for all the great ideas.

  • T ChapT Chap Posts: 4,217

    I suspect that you have a continuous PID where you are repeatedly multiplying by the sample time and using floats? The discretized method and using integers is far more efficient. Which reminds me; there is a continuous PID in the OBEX by cweber that needs to go away, it's flat wrong, can never work.

    There is continuous PID, never stops and it maintains/holds motor positions at all times unless moving the motors. Not using floats, my PID is quite convoluted and is a mess. But it works :)

  • MicksterMickster Posts: 2,629

    @"T Chap" said:

    I suspect that you have a continuous PID where you are repeatedly multiplying by the sample time and using floats? The discretized method and using integers is far more efficient. Which reminds me; there is a continuous PID in the OBEX by cweber that needs to go away, it's flat wrong, can never work.

    There is continuous PID, never stops and it maintains/holds motor positions at all times unless moving the motors. Not using floats, my PID is quite convoluted and is a mess. But it works :)

    Sure, the discretized method also runs forever but the beauty of it is that; everything happens within the sample....never need to multiply by the sample-time and if the velocity profiler is in the same routine, we automatically have velocity control.

    Craig

  • I was just wondering what you are controlling, CNC, etc. I have a motion control project in work at KSC, single axis. I'm using an Idec HG2G operator and a FC6 PLC. I have my own P1 PLC, but I'm pressed for time and I haven't field tested mine long enough in an Industrial environment to assure reliability. Lots of solenoids, 30 HP motor, contactor's, VFD's, etc. all making transient voltages to reset my Prop P1.

  • T ChapT Chap Posts: 4,217

    I was just thinking it would be nice if you could receive 3 streams of data on 3 pins that would contain the position and other incoming values when needed. But I could not find a solution to allow 1 cog to read 3 constant streams especially at 128k-512k TBD. I don't think I have 3 cogs to spare for this on the main board. But it occurred to me that I could use Jon's idea of a single cog encoder reader that can read 3 encoders at the same time. This way the encoders are routed first to the LX7366 chips then to the MainBoard P1 to maintain position when P1 reboots or powers off. In this idea one cog can maintain the 3 encoder positions as a casual effort. Granted, on power up the positions would be zero on the MainBoard P1 encoder read, so first there would be capture of the current LS7366 positions, write those 3 positions to the 3-encoder object cog and thereafter the MainBoard will know the position at all times without having to stream 3 encoder position longs from 3 motors. Maybe add a periodic update from LS7366 position to the MainBoard positions to avoid any drift. This removes a lot of serial data streaming out, only a la carte values for faults, current trips etc would get sent back.

    DigitalBob , I do custom home automation gadgets. What I have is not correct for CNC.

    Mickster.

    The very oversimplied method is

    SignedError := NewPosition - EncoderPosition
    IF SignedError > 0
        MotorDirection := 1  ' set direction pin 
    IF SignedError < 0
        MotorDirection := 0  ' set direction pin 
    Accumulate Integral 
    Apply Integral Max value ( which sets the output/speed)
    Output := P+I <#1000
    

    everything happens within the sample....never need to multiply by the sample-time.

    I have no ideas what this means!
    The profile generator gets a position to move to, divides it up into ranges ie how much range to accel, how much to decel, what is the FlatRun range, what are the speeds to move at, then uses waitcounts to create the profile. Waitcount starts at a value then decreases its time each iteration while NewPosition++ is going to the PID. PID looks at the NewPosition coming in, compares to the actual position and does a lot of crazy math. But there is a lot of care taken to create the certain acceleration "feel", it's not just ramp from Off to Max speed for the move.

  • T ChapT Chap Posts: 4,217
    edited 2024-05-12 01:05

    I had some other ideas come to mind while working on how to drive 3 separate PID/Profile generators from a Main board P1. The current concept is to put the Motion Profile Generator on the 3 sub boards with P1, then just transmit a position from main. The main board does all the careful sync operations. But what if the 3 Profile generators live on the Main board while the PID lived on the 3 separate boards? How would I stream position from the main board to the 3 separate? Then it occurred that I could send a step on/off pulse and direction signal from Main to the PID boards. The PID takes the steps and adds to the New Position if Dir is 1 and subtracts if Dir is 0. Sort of like a stepper motor but the step is not moving the motor a step but rather adding and subtracting the new position in PID. Pid then acts exactly as it does now. This method allows the main board P1 to control the sync of things AND run the 3 separate Profile Generators under one roof. The PID boards are just dumb and chase the error coming in as pulses that accumulate to create the position to chase.

    The profile generator is in spin so the pulse count can’t exceed spins fastest loop time at 80m clock.

  • MicksterMickster Posts: 2,629
    edited 2024-05-13 11:17

    The profile generator is in spin so the pulse count can’t exceed spins fastest loop time at 80m clock.

    Pulse count should not be an issue as long as the counter can keep up. PID and profiler should be discretized
    Note: Many motion controllers don't run their profilers at the same update-rate as the PID. Galil, for example, for a 1ms PID sample-rate, run their profiler @2ms.

    const accel=1
    const slew=2
    const decel=3

    do
    waitcnt (next 1ms)

    read encoder
    determine position error
    do the PID (or PI)

    if new_position_command then

    select case profile_stage

    case accel
    add calc'd accel counts/sample (1ms in this case)
    if accel_distance_reached then profile_stage=slew

    case slew
    add velocity counts/sample (example: if velocity=20_000 cts/sec then add 20 cts to the command)
    if slew_distance_reached then profile_stage=decel

    case decel
    add calc'd decel counts/sample (1ms in this case)
    if decel_distance_reached then
    profile_stage=accel
    new_position_command=false (motion complete)
    end if

    end if

    loop

    Craig

  • T ChapT Chap Posts: 4,217

    As an alternative to sending Step/Dir as a position to the PID, what about sending quadrature encoder over 2 pins and PID reads converts that to position. In my case, the profile generator is in Spin in it's cogand PID is Spin in another cog. PID shares the save VAR long Positon. One iteration of profile generator results in Position++ or Position-- so what would be involved in outputting quadrature from the profile generator over 2 pins to a PID in a separate board? PID can have a separate COG with a quad encoder reader updating Position at all times based on which way the quad pulses move. I know how to read quad with various objects but have never sent it. It's seems like sending position over quad encoder pulses is much faster and more efficient than serial streaming packets which would be 4 bytes for position, possibly a packet header.

  • MicksterMickster Posts: 2,629

    @"T Chap" said:
    As an alternative to sending Step/Dir as a position to the PID, what about sending quadrature encoder over 2 pins and PID reads converts that to position. In my case, the profile generator is in Spin in it's cogand PID is Spin in another cog. PID shares the save VAR long Positon. One iteration of profile generator results in Position++ or Position-- so what would be involved in outputting quadrature from the profile generator over 2 pins to a PID in a separate board? PID can have a separate COG with a quad encoder reader updating Position at all times based on which way the quad pulses move. I know how to read quad with various objects but have never sent it. It's seems like sending position over quad encoder pulses is much faster and more efficient than serial streaming packets which would be 4 bytes for position, possibly a packet header.

    Some encoders actually output via RS485. It's all based on what your PID sample-rate calls for.

    This is why I suggested using a P1, dedicated to quad decode/counting and sending the three longs to the main P1. A serial object @230K BAUD would be super-safe and could include a header and even a checksum.

    I prefer incremental encoders due to easy-availability but there are cooler options such as SSI and BiSS which are not unlike SPI with line-drivers/receivers.

    Craig

  • I haved used Step/Dir in the past because most of my customers used stepper drives and Step/Dir is supported by almost any drive from any manufacturer. But of course, it is not the most clever way to transmit a position command. It is quite sensitive to noise or setup/hold time problems when reversing direction. Quadrature is more robust.

    If you don't need to be compatible to anything else I'd use a serial data protocol over an RS485 line. That would allow adding CRC and bidirectional communication for feedback and diagnosis. There are a lot of different standard protocols (CAN, Profibus, Modbus, SSI to name a few) but they are all ridiculously complex and/or inefficient so not woth the trouble if you only need to get a single application running. There is something called "smart serial" which is used by LinuxCNC which seems to be quite clever. But it's not commonly used in the industry.

  • T ChapT Chap Posts: 4,217
    edited 2024-05-17 23:26

    I took 2 Prop boards today and tested the theory of sending Quadrature signals from one Prop with a motion profile generator out over 2 pins to a second board with a Prop that runs PID and reads the motor encoder. The system works good and the motion looks the same as having the profile generator and PID on the same Prop in different cogs, sharing position variables versus sending the position over wires. One issue is even at very slow transition speeds the received count is drifting at some time in a looped test counting up and down. Example. count up to 10 back to 1. Count to 100 and back. Count to 1000 and back. The drift is the same. It loses 2 to 4 after a short time ie 30 seconds. On a scope there is no obvious reason, since at some slow rate ie 1 pulses per 500ms it does the same issue. It starts at 0 - 10 - 0 in a repeat loop, or 0 - 100 - 0 in a loop. Then after some time it can change to -1 to 99 to -1. Then -2 to 98 to -2 and continues.

    Side note, I know for a fact that I was slamming the transmit Quad signal from the sender board into the receiver prop while accidentally having the receive pins in output! I'll rig up another test method later to see if in fact the receive side has damaged pins. I use encoders every day and there is never a drift due to noise etc. I hope this is damaged inputs.

    Edit. Drift is not io pins. I changed boards. It is not obvious in a scope. Wires are 8” unshielded. At very slow speeds this should not be happening.

    Bottom line is this seems like a bonafide method to connect to an external PID over Quad, but for sure will have some error checking behind the scenes over to be sure there is no drift.

    Test code to send positions up down in a repeat loop
    
    Pub SimulatePositionSend
      dira[0..1] := %11
      ' FORWARD
      QuadState := 1
      Repeat 
         Repeat 10
           QuadState++
           If QuadState > 4   ' reset upper
               QuadState := 1
           Elseif QuadState < 1    ' reset lower 
               QuadState := 4
           OutputQuad
           w(20_000_000)
         w(60_000_000)
    
         ' REVERSE
         Repeat 10
           QuadState--
           If QuadState > 4   ' reset upper
               QuadState := 1
           Elseif QuadState < 1    ' reset lower 
               QuadState := 4
           OutputQuad
           w(20_000_000)
         w(60_000_000)
    
    
    PUB OutputQuad
          Case QuadState
    
    
             1 :  outa[0..1] := %00
             2 :  outa[0..1] := %10
             3 :  outa[0..1]  := %11
             4 :  outa[0..1] := %01
    
    
    
    
  • I’ve blown out a prop or two myself. They seem to function normal, but the best way to check for a blown prop is to test the counters. The counters can be blown out, but the prop can still execute some code.

  • MicksterMickster Posts: 2,629

    "Drift" = lost or gained counts but here it reads to me like it's trying to correct itself. Feels like some kind of phase lag but I don't see a reason for that.

    Craig.

Sign In or Register to comment.