Community

Discarding Buffered Motion

Which of these will discard the remaining motion in the buffer?

  • Stop()
  • EStop()
  • Abort()

Will all three?

@todd_mm

Stop() or FeedRateSet(0) are the only ways to “Pause” motion which can be continued later. Steaming motion can effectively be paused by sending the same points down for whatever duration you’d like pause.

So, I definitely want to discard what’s in the (sent) motion buffer. Does EStop() do that? What if it’s an EStop (or EStopModify) as a user limit action? Does that behave the same way? And, if it propagates up to the MultiAxis, will all that motion data get dumped, too?

We’re trying to probe, and I want to “cancel” the sent motion at the end of the move after the probe input changes.

@todd_mm

Yes, you would be unable to resume the previous motion profile after an EStop or EStopModify event. User limits create actions on an Axis or MultiAxis object in the same as the direct Functions do. It would propagate as normal.

Why is is the concept of discarding so important to you? If you issue a new move command after a Stop event it will discard the old motion profile at that time. You will need to ClearFaults() after any event unless you choose to Resume() or FeedRateSet(1.0) on after a stop event. That should accomplish your goal.

I’m seeing the motor jump after we clean up from a probe strike. I’m trying to ensure that it’s not still executing motion that I gave it before the strike.

@todd_mm

That indicates that there is a disconnect between the actual position of the motor and the positions that we are sending out to it. You want to avoid letting the drive take over or abort our axis so the command = actual feature prevents a disconnect. You are likely experiencing a small one in any case where the physical and logical axis aren’t being controlled from the same source (the RMP).

I suspect what is most likely happening here is the drive is taking control over motion when the probe strike happens. It starts ignoring the master positions until a later time when it starts listening to the commanded position again. Then the drive would jump to reach the commanded position.

Motion Scope would be a good way to diagnose and evaluate what you are experiencing.

1 Like

IDK if I understand what you’re describing.

When would the “drive take over?” When the probe input goes high, I’m expecting RMP to EStop the drive. At that point, I expect the drive to be stopped and all motion that I’ve sent it would have been discarded. Is the drive going to continue to do something on its own without RMP commanding it?

If the drive is “taking over,” what is it actually doing?

Some drives have internal configurable actions for the probe input. (Safety features?) Jacob is suggesting you confirm that your drive isn’t doing some internal action (such as a controlled stop, etc.) where it would temporarily ignore position demands from the RMP.

EStop and EStopModify will discard any motions you’ve commanded and you’ll have to start over.

If you’re seeing a jump, you may want to verify (MoScope or recorder) command positions sent to the drive.

1 Like

Thanks for the advice and info, guys.

The probe input is not one of the high-speed inputs on the drive. It’s from a different I/O node on the network. RMP is acting as the latch for axis positions and EStopModify’ing the axis when the input goes high (via user limits). Is there still a chance that the drive is doing something on its own?

Here’s data from the scope (I used my own viz tool—the scope is a little clunky WRT plot clarity).

The bad behavior that I’m observing is visible as the jump in actual velocity at end of the second graph. My first question is, why isn’t command equal to actual? Is that just a quirk of commanding positions and not velocities? (We’re sending motion points with MovePT())
That there’s a difference between actual and commanded position seems like the cause of the jump, but I want to make sure that I understand the data that’s coming back from the scope.

I doubt the drive is doing anything on its own.

What happened around time 41180 when command position drops? Also I’m wondering why the motor doesn’t move until time ~41192?

Command is set equal to actual only when the drive is disabled.

Let me make sure I understand the process here:

EStopModify()
WaitForDone()
ClearFaults()
new MovePT()

Are you sure the new MovePT starts from the current value of Command Position?

I’m almost certainly sending the wrong “hold still” position to RMP after the probe strike. I’m trying to figure out where that’s coming from. The change in commanded position is what I’m sending after probe cleanup is finished.

As for the process that I’m using, it’s much like what you outlined.

  • EStopModify()
  • WaitForDone()
  • ClearFaults()
  • AmpDisable()
  • AmpEnable()
  • new MovePT()

I added the disable/enable in an attempt to fix the position sync issue, but that’s apparently not the problem.
At 41187, I’m commanding that (incorrect) position.

I can’t explain the 10ms delay between the commanded position changing and the actual position following it. Just for fun, here’s more detail about that time.

Is 10ms a long time for a response? It seems like I see 10-20ms following times between commanded and actual. Were you asking about something else?

10ms seems a little long but if it’s normal for you, let’s not focus there.

Ok I want to confirm I understand what you’re saying. At 41187, you issue a new MovePT() and streaming it a constant value for command position, and you suspect it’s the wrong position?

If that’s the case, keep us posted on what you find.

After the probe strikes and we “handle it” (in the CNC software), we send the motor “hold still” motion in preparation for the next meaningful motion. I appear to be sending the wrong “current position.”

This question was primarily an investigation to ensure that I’m using RMP correctly. Thanks for the help.

It appears that my problem was the “current position” data.

In general, any data we retrieve in multiple places or in loops is “cached” in recorders (I’ve heard it referred to as “block I/O”).

After the probe input went high, we wait for motion to stop, clear faults, etc.
Then, we get the current position and use this as the next commanded position.

The current position I get via block I/O (RSIAxisAddressTypeACTUAL_POSITION) is not the same as what I get from calling Axis::ActualPositionGet().
Some of this discrepency could be due to us only updating the data from block I/O every time the sync interrupt fires. However, when I look at the data +/- 15 ms from when I attempt to acquire the actual position of the axis, I still don’t see numbers like what I’m getting from block I/O.

Block I/O reports the position: 29 296 507
The scope data has actual positions in the range of [29 301 010, 29 304 088] in the range -15ms/+15ms.
The actual position that I was expecting was something like 29 304 241 (the observed actual position in the scope data).

(There’s not a great way to map motion scope data to any sort of calendar time, so my correlation of events could be off by, perhaps +/- 5ms.)

Now, I’m not pointing fingers at RMP for misbehaving. I’m curious if I’m using things correctly.

We started using block I/O because some of the API calls were taking a long (short) time to return, as if there were some safety iterlocks (e.g. mutexes) protecting the shared data. I don’t have objections to safety, but I don’t really know which API calls have the time consuming protection and which don’t.
Is there any guidance in the docs regarding this?

Also, how does the API for (e.g.) ActualPositionGet() behave? Does it query the drive or just read some host/firmware memory?

Are there any caveats for block I/O that I should know? Would you expect it to lag behind instantaneous-current data at all?

Thanks for the update.

I think your usage sounds fine. ActualPositionGet() should be reading from the same firmware memory you are reading with the recorder. It does not read from the drive.

Could you try controller->MemoryDoubleGet(axis_actual_addr) to see if reading the value directly matches your recorded value or ActualPositionGet()? Both of those should already be scaled by OriginPositionGet() so I’m confused. You could double-check to see if OriginPositionGet() returns something close to the magnitude of the discrepancy.

We don’t yet have a document for method execution times, but it is on our list of things to do.

Just as a follow-up:

  • MemoryDoubleGet() returns the same value as ActualPositionGet().
  • OriginPositionGet() returns 0 (we clear it early on and never set it).

I don’t have time to investigate it further, but the most likely explanation I can think of is that the block I/O data is sufficiently stale not to be relied upon in this circumstance.

Thanks for your help.