Jump to content
OMRON Forums

curtwilson

Members
  • Posts

    723
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by curtwilson

  1. In this case, your spindle motor is not instantaneously commanded to zero velocity; rather it is decelerated according to its Motor[x].AbortTa and Motor[x].AbortTs saved setup elements. Apparently you have these parameters set for a very quick stop. You will want to set these parameters for a more gradual deceleration. Larger positive values specify longer times, and larger negative values specify lower rates (because they are inverse rates).
  2. I think you will have more flexibility if you poke your dither value into Motor[x].MasterPos instead of Motor[x].CompPos. (Note that because MasterPos adds into the net desired position value instead of the net actual position value as CompPos does, its direction sense is opposite.) MasterPos should give you what you want because there are two modes of operation for it. In "offset mode" (Motor[x].MasterCtrl bit 1 [value 2] = 1), which you want to use for the actual dithering operation, the master position and trajectory position can be superimposed. In "standard mode" (Motor[x].MasterCtrl bit 1 = 0), computed trajectories would take out what the master added in. (Another note: because you are poking directly into the MasterPos register, you want to leave the "following enable" bit -- MasterCtrl bit 0 [value 1] at 0.) So it looks like you can get the effect you want by setting the mode bit to 1 when you are superimposing the dithering, then change it to 0 for pure trajectory moves relative to a fixed origin. Whenever you change this mode bit, you must be sure that a "pmatch" command is issued before the next programmed axis move is commanded. A pmatch occurs automatically when you start a motion program, but if you make the change in the middle of a motion program, you must use an explicit pmatch command before the next axis move command. You may want to look at how you set Motor[x].PosReportMode if you are querying positions in the different modes.
  3. You want to use Atul's method to check the status of Coord[1].ProgActive. This is a "function" status bit that is computed from several internal status bits. It is 1 if the program is running or suspended so that execution could continue at that point. In this case, you would need to abort the program before you could work with the program buffer.
  4. What mechanism are you using to generate the trigger? Software commands or hardware output (position compare) from the ASIC? Can you generate a hardware position compare output from the feedback of the real motor? This is what the people who need the highest accuracy use.
  5. The variable-time spline is significantly more flexible in the Power PMAC than in older PMACs. The manual does not do an adequate job of explaining how to use it to make it act like the older PMACs. Use the triple time specification (which you can do on one line) to get the effect you want. My apologies for the confusion.
  6. I think you have a good strategy here. To implement this, assuming X, Y, and Z use Motors 1, 2, and 3 in C.S. 1: - Assign your A, B, and C "axes" in C.S. 1 to PMAC Motors 4, 5, and 6. These will operate as virtual motors. - Set Ix03 and Ix04 for these motors to the address of a register that always holds a zero value (e.g. X:$0770). This means that the following error will be equal to the motor command "position" (which is a torque value for you). - Set all servo gains except Ix30 to 0. The proportional gain term Ix30 will act as a scale factor to the output. - Set the Ix02 servo output address parameter to the address of the torque offset register for the real motor you want to affect. The addresses are $45 for Motor 1, $81 for Motor 2, and $BD for Motor 3. - Set Ix11 for the virtual motors to 0 to disable fatal following error limit. - Set bit 20 and bit 17 of Ix25 to 1 on virtual motors to disable amplifier fault and overtravel limit functions.
  7. Most people who do this assign M-variables to the instantaneous desired velocity registers for each axis, then take the vector sum. This works better than noisy instantaneous actual velocity values. For example, define: M160->X:$86,0,24,S ; Motor 1 instant cmd vel register M260->X:$106,0,24,S ; Motor 2 instant cmd vel register Then in a PLC program: P60=SQRT(M160*M160+M260*M260) ; Instantaneous vector velocity M4602=P60*P61 ; Scale and output
  8. If you are not commutating the motor (Motor[x].PhaseCtrl bits 0 and 2 = 0), the motor will only write to the single register specified by Motor[x].pDac. If you are commutating but not closing the current loop (Motor[x].pAdc = 0), the motor will write to the register specified by Motor[x].pDac and the next register (e.g. both the A and B phase DACs). If you are commutating and closing the current loop, the motor will write to the register specified by Motor[x].pDac and the next 2 registers (e.g. the A, B, and C phase DAC/PWM registers). Any output register not automatically written to by the motor is available for general purpose use (provided, of course, that you have the output hardware to make it useful). Power PMAC works the same as the older PMAC and Turbo PMAC in this respect.
  9. For what you want to do, I think you will want to keep the motor technically enabled and closed-loop when the brake is on, but effectively disable it. If it is a servo motor, you could set Motor[x].Servo.Kp to 0 (and probably Ki also). If you are doing direct microstepping, you would want to set Motor[x].IdCmd to 0. This would mean that there would be no current in the motor. Next, you would want to assign the motor to an axis in a coordinate system, so it can execute as part of the sequence in a motion program. &1 #1->X assigns Motor 1 to the X axis in C.S. 1 Now when you want to re-establish electronic control of the motor, release the brake, wait for the brake to disengage, and move the motor, you can issue a command like: &1 cpx Motor[x].Servo.Kp=100 PowerBrick[0].GpioData[0].17.1=1 dwell 2000 x10000 I would probably embed all of the commands to re-establish control into a subroutine so the command could look like &1 cpx call EngageControl(1) x10000 with the subroutine looking something like: open subprog EngageControl(MotorNum) Motor[MotorNum].Servo.Kp = 100; Motor[MotorNum].Servo.Ki = 0.0001; PowerBrick[0].GpioData[0].17.1 = 1; dwell 2000; return
  10. The brake control algorithms were not intended to support real move commands - delayed or not - given while the brakes are still engaged. We consider a move command in this state to be erroneous - not valid in the context of the state machine for the system. We do not presently provide explicit protection against this in the Power PMAC, as our users typically include this as part of their own application-specific state machine logic. You misunderstand the purpose of our "BrakeOffDelay" time parameter. The delay is to provide time for the servo (especially the power stage) to engage fully before starting the release of the brake. If the brake release starts too early on an axis with a net load such as gravity, you can get uncontrolled motion before full control is established. It is not intended to provide a precise delay from enabling the amplifier until a move can be started. We are now evaluating the addition of logic to reject a move command that is given with the brake still engaged. If the process of disengaging the brake has not started, it would start the process. (In other words, it would treat your j^10000 command as a j/ command.) But we do not believe that providing the functionality to start the motion after two delays (the BrakeOffDelay we provide and the additional delay you point out would be necessary) would fit into our safety logic well.
  11. Yes, a word is 32 bits. So any M-variable of less than 32-bits is written to with a read-modify-write sequence. The follow-on is yes, using 32-bit M-variables is faster. Let's say you had 20 Boolean flags you wanted to store in USHM. Speed-wise you would be better off declaring 20 32-bit variables, even though you would only actually be using one bit of each. The PPMAC processor does have atomic 64-bit access instructions, which the compiler uses when accessing "double" variables. So, for example, if you access one of our P-variables, or a Ddata register in USHM, in your C-code, it cannot be interrupted in the middle. (The same is true with our Script access to double registers like this.) I don't remember the exact details, but basically the user I was talking about was trying to copy logged 64-bit floating-point variable values from one place to another using 2 separate 32-bit accesses in C. Occasionally the source value was being overwritten in between the two accesses and he ended up with an incoherent value. If you really want to, you can find the old thread somewhere on this forum. It was a couple of years ago, I think. Since you asked about execution speed, I want to point out something that is non-intuitive to many. In the Script environment, to keep users from needing to perform explicit type-matching of variables as you would have to do in C, the Script execution engine automatically converts everything to double-precision floating-point format (64 bits in Power PMAC, 48 bits in older PMACs). Therefore, when it comes time to store the resulting value, the quickest operation is to store it in a 64-bit floating point variable (e.g. P, Q, Ddata), because that requires no format conversion (which takes longer than the second 32-bit access). Of course, the tradeoff is inefficient use of memory.
  12. Fundamentally, all memory and I/O accesses by the Power PMAC processor are 32-bit or 64-bit. The actual write operation is atomic -- it cannot be interrupted. (For 64-bit registers, the register must be accessed by a single 64-bit write [e.g. to a "double" variable] for the operation to be atomic. And yes, one Power PMAC user found this out the hard way...) If your operation to change the value of a register requires you first to read the present value of the register, modify some bits of the register, then write back to the register, this is never an atomic operation, no matter how many of the bits of the register you are dealing with. In the Script environment, the complexity of the read-modify-write sequence is often hidden from you. If you write to a "partial-word" data structure element or "partial-word" user-defined M-variable, this action automatically incorporates a read-modify-write operation (that is interruptible). In the C environment operating on I/O, you must explicitly access a full 32-bit register, and write your own masking code to modify the register. In the C environment operating on memory, if you access a partial-word data structure element, the compiler will generate the code to do the read-modify-write operation, but in the Power PMAC processor, this is not an atomic operation. Also, if your operation requires multiple write operations (32-bit or 64-bit), this is never an atomic operation. If you need to ensure a coherent set of data across the multiple registers, you must ensure that this overall operation is not interrupted by anything that could destroy that coherence.
  13. curtwilson

    DesAccel

    We do not store a value of DesAccel between servo cycles. Each servo cycle we compute DesAccel = DesVel[n] - DesVel[n-1] and then multiply it by the acceleration feedforward gain, but have no need to store it for the next cycle. We store DesVel so we can compute DesAccel in the next servo cycle.
  14. Monitor the actual hardware register value(s) of the ASIC like Gate1[6].Chan[0].ServoCapt in the IDE Watch window while you move the encoders. The values reported have nothing to do with conversion table or motor setup, so if there is a problem, you have isolated it to the ASIC setup or a signal problem.
  15. Steve: You are correct that different tasks of the same priority level in PPMAC cannot interrupt each other; they execute in a round-robin fashion. The potential worry is if you have tasks of different priority levels accessing the same word in a read-modify-write sequence. The potential result is non-intuitive for many people, as it is the lower-priority task that "wins" in the case of a conflict, because when it resumes to finish its sequence after being interrupted, it overwrites what the higher priority task had written to the register. The priority levels in PPMAC are, from highest to lowest: 1. Gate3 capture/compare interrupt (rarely used) 2. Phase interrupt 3. Servo interrupt 4. Real-time interrupt 5. Background Usually, the conflicts in user code are between RTI and background. They can occur with either memory or I/O registers, although they would be much more likely to occur with I/O, which generally requires 2 100-nanosecond accesses, so the chance of getting an interrupt is much higher than with memory (which might be a good thing as you are more likely to find the problem early in development).
  16. In the Script environment, it is possible for the read/modify/write sequence necessary to change a bit or bits of a 32-bit word to be interrupted by a higher-priority task. If the higher-priority task writes to this same word, the lower-priority task will then undo what the higher-priority task has done. To protect against this, we have a process-locking mechanism in the Script environment using non-saved setup element bits Sys.Lock (i=0 to 31). When a Script command reads Sys.Lock and finds it to be 0, it sets it to 1 in an atomic (non-interruptible) operation. So you can do a sequence like this: while (Sys.Lock[8] == 1) {} // Wait for process 8 to be unlocked, then lock it for this task myvar = 1; // Do read/modify/write operation Sys.Lock[8] == 0; // Unlock process 8 to release for other tasks
  17. I'm not sure that I understand the physical description of the system, but I deduce the following from the plot. In the period you are concerned about, the change in #1 actual position and following error are equal and opposite. This means that the commanded position for the motor has not changed. This indicates to me that there is likely a physical interaction pushing the motor away from its desired position during this period. Now the question is why the Motor 1 servo loop cannot counteract whatever physical effect is offsetting it. The first thing to look at is whether you have enough (or any) integral gain (I133) to overcome the disturbance in a reasonable time. Also check I163 to make sure you haven't limited your integral output. Without an integrator in the servo loop, you can get this kind of behavior, with proportional gain needing an error to provide the countervailing torque/force to balance the disturbance.
  18. A Turbo PMAC2 expects these flags in specific bits of a register, and the U, V, and W flags do not appear in these bits. Your best strategy is to copy these input flag values into the proper bits of a holding register in memory, for example, open register X:$10FF. A background compiled PLC program would do this every background cycle, the same frequency at which these values would be checked. Note that it will not be possible to use hardware capture of encoder position for the motor with this technique for homing or other purposes. If you want to do triggered moves like homing, you must set up for software capture by setting I597 to 1. I525, which specifies which register to read for these flags, would be set to this address of $10FF. A PMAC2 expects the flags in the following bits of the 24-bit register: HOME: bit 16 PLIM: bit 17 MLIM: bit 18 USER: bit 19 So your PLC program could just do four single-bit copy operations into the holding register each scan.
  19. The register at X:$0049 is a 24-bit register. The data for a 16-bit DAC is in the high 16 bits of these 24 bits - the first 4 hex digits if you try to read it that way -- $FF52 in your example. If you just want to read it as a signed decimal value, divide the 24-bit value by 256 (2^8) to get the 16-bit value. In your example, $FF52 converts to 65,362 unsigned decimal. But it is a signed value, so the value you are interested in is 65,362 - 65,536 = -174. The Quick Plot routine converts this to volts of a +/-10V DAC. In your example, the calculation would be: V = (-174/32768) * 10 = -0.0531V
  20. You are starting to figure out the tradeoffs and limitations on your own. Of course, the main limiting factor for servo cycle frequency is the computational requirement of the processor. Unfortunately, there are so many variables that there is no simple answer to the maximum servo frequency in a given application. Most users will view the "CPU Resources" window in PEWIN32 PRO (found under the "PMAC Resources" tab). This shows you graphically and numerically the amount of processor time spent at each task level. This makes it easy to see the differences as you change system parameters. Some of it can be understood pretty easily. For example, if 20% of processor time is spent in servo tasks at a given servo frequency, then if you double the servo frequency, 40% of processor time will be required for those same tasks. Our general rule of thumb is that you do not want to spend more than 50% of your CPU time in phase and servo tasks combined. As you try to increase servo performance by increasing servo frequency, you will find that you reach a point of diminishing returns where you stop getting noticeable increases. For example, increasing from 5kHz to 10kHz will give you more improvement than increasing from 10kHz to 20kHz. What you are really doing is decreasing the sampling delay from 200usec to 100usec (a reduction of 100) in the first case, and then from 100usec to 50usec (a reduction of only 50) in the second case. Also, with the derivative term, increasing the frequency increases the effective quantization noise from the numerical differentiation, so you can actually get a decrease in performance at some point (but the higher your position resolution, the higher the frequency you can reach before you hit this point).
  21. A common way of doing this type of task is with a fixed motion program executing in a looping fashion - e.g.: tm5 while (DoingThis) { MyNsyncVal = ... MyXpos = ... MyYpos = ... MyZpos = ... MyApos = ... MyBpos = ... MyCpos = ... MyQvar1 = ... MyQvar2 = ... N(MyNsyncVal) X(MyXpos) Y(MyYpos) Z(MyZpos) A(MyApos) B(MyBpos) C(MyCpos) } By doing all of the computation and move commands in a single synchronized and sequenced thread, you eliminate all sorts of problems with handshaking and possible loss of synchronicity.
  22. At re-initialization, motors that do not have hardware channels auto-assigned to them have input and output pointers assigned to the register at the Sys.pushm address. These motors are not activated, so the register is not actually addressed. If you have an active motor, and want to assign an output to a do-nothing, harmless register, Sys.pushm is a good choice. As for inputs, you do want to be a little more careful, I think. Safety flag inputs like pLimits, pAmpFault, pEncLoss, and pAuxFault are better just set to 0 to disable the function altogether. I'm not sure why you would want to redirect position input pointers.
  23. We have had a few users switch between compensation tables based on some variable. Typically this has been done by putting all of the potentially used tables in the PMAC, with the tables not being used writing their corrections to an unused motor (e.g. #32). In your case, you would probably use a PLC program that would look at your temperature value and decide which tables point to your 3 real motors and which tables point to the unused motor. The tricky thing is that this has to be done with pointers (M-variables) and really pairs of pointers used in an indirect addressing method. The pointer to the start of the comp table belonging to motor 1 (which does not need to use #1 for either source or target) is at address X:$3192. So the contents of this register contain the starting address of the table in PMAC's memory. (In a simple test here, that address for me is $02FFF4.) The contents of the X-register at this address are the address of a key register for the target motor. This value should be $89 for Motor 1, $109 for Motor 2, $189 for Motor 3, and so on, to $1009 for Motor 32. So, how to make use of this? First, let's define some M-variables: #define FirstTablePtr M5001 FirstTablePtr->X:$003192,0,24 ; 1st table ptr to start #define FirstTableTarget M5002 FirstTableTarget->X:$0010FF,0,24 ; Dummy address to start ; Pointers to M-variable definitions for indirect addressing #define FirstTableTargetAdr M5012 FirstTableTargetAdr->Y:$00538A,0,24 ; Address of M5002 definition The following command needs to be done once to initialize the pointer: FirstTableTargetAdr = FirstTablePtr Then, whenever you want to change the target motor number of the table, you use a command like: FirstTableTarget = TargetMotorNum * $80 + 9 where "TargetMotorNum" is defined as some general-purpose variable.
  24. I think the settings you want for this using Charles' strategy are as follows: EncTable[n].type=1 // Single-register read EncTable[n].pEnc=PowerBrick[0].Chan[0].SerialEncDataA.a EncTable[n].index1=9 // Shift left 9 bits for proper rollover EncTable[n].index2=0 // No shift right required EncTable[n].ScaleFactor=1/512 // 1/2^9 for output in encoder LSBs Other entry settings are factory default.
  25. Something has to be changing Plc[10].Ldata.Coord. You can monitor it externally using the full name. Even if you cannot trace it, it takes very little time to set it each time you want to issue a command.
×
×
  • Create New...