Streaming Outputs: Using Them When I Don't Know the Future

[RMP 8.3.1]

Streaming Outputs

The sample app for streaming outputs is somewhat unlike my application. I could use some clarification about how to use the API.

My Application

My application is essentially a finite state machine that acquires some points and sends them down to the motion controller.

In the case of streaming outputs, we will get a “piece” of motion in which one or more outputs will be enabled. That same chunk of motion data may or may not have a corresponding “clear” of the outputs. The signal to clear will come some time later.

I will never be able to know ahead of time which outputs could be set/clear or, when a specific output is to be set, precisely when it will be cleared. I’ll know later when it’s to be cleared, but I won’t know at the time when I want it to be set.

API Questions

StreamingOutputsEnableSet(…)

When do I want to enable/disable streaming outputs?

Are they enabled any time I want RMP to either set or clear the output?

If they are disabled, will RMP ever try to set/clear the output as a result of the motion ID being executed? (The documentation makes it sound like this is the case, but I just want to be sure.)

Would I want to disable when I know that I no longer have any (active) outputs that I want to set/clear as the result of executing motion?

I can imagine that I’d want to enable streaming outputs as soon as I start streaming motion and disable them when I stop streaming motion, but I don’t know if that’s the intended use of the API function.

There’s a seeming discrepancy between the API doc and the topic regarding ...Enable(false). (Emphasis added)

Setting to false resets the current index to 0, but does not free the array backing.

StreamingOutputsEnableSet()

FALSE - resets the current index to 0, and clears the vector backing.

StreamingOutputsClear(…)

(The sample doesn’t use this function.)

This discards any existing streamed outputs (even if they have not triggered)?

In my application, would I want to use this any time other than when I disable streaming outputs?

StreamingOutputsAdd(…)

I only need to ...Add(...) when I want the output to change, right?

Will RMP remove the item from the Streaming Output List (SOL) as soon as the corresponding motion ID has executed? Will subsequent calls to MovePT(...) fail if streaming is still enabled (i.e. if the SOL is empty)? This sounds unlikely, but why is it an error to enable streaming outputs without adding an output? Especially since there’s no API function for detecting the state of streaming outputs, it seems like I’d have keep track of whether I’ve ever called this turned it on or off rather than query RMP, who probably knows better.

There must be sufficient space in the Streaming Output List before adding this output

How large can the list be?

ptPointIndex

Is the point index paramater used here a number from the space of motion IDs, like what’s returned from MotionIdGet()? (It seems like it would be, but the parameter is an int32_t whereas the motion ID is an int16_t.) The name of the parameter, ptPointIndex, suggests that it might be an index into the array of points I’m about to give to MovePT(...). My reading of the docs suggests the latter (something in the MotionElementIdExecutingGet() space). (The sample doesn’t clarify this distinction, but the topic makes it sound like I should use an index into the array of points rather than a motion ID.)

onMask, offMask

When the output is to be set (by RMP), will it use both the onMask and offMask? In other words, will I always want to set one of these parameters to 0, depending on whether I want to “set” or “clear” the output (for a typical digital output)?

For niche cases, when neither of these masks is zero, which one is applied first?

Application Architecture

I can imagine a few ways to implement this, but I’d prefer to use the cleanest. Even better than cleanest is “what works,” so your advice here will be most useful.

Always Enabled

This method would seem to fit best with the FSM-style behavior of my application.

  1. When I start streaming motion, I enable streaming outputs.
  2. (I ...Add(...) an output to the first batch of motion points I send so that calling MovePT(...) doesn’t croak.)
  3. I stream motion like normal, and occasionally ...Add(...) an output that either sets or clears the output.
  4. When I stop streaming motion, I disable and clear the outputs.

Output Micromanager

I don’t prefer this method, but if this is how the API wants to be used, I suppose that’s more important.

  1. As soon as I know I need to set an output…
    1. If outputs aren’t enable them, enable them.
    1. ...Add(...) the output.
  2. As soon as I know I need to clear an output…
    1. ...Add(...) the output
    2. As soon as the motion ID where I cleared it has executed
      1. If there are no more active outputs, disable streaming outputs

I’d recommend you only enable the outputs when you intend to use them.

However, its relatively minor impact if you decide to do so anyway. There is a very slight CPU processing advantage to not enabling Outputs when you don’t plan to use them for application specific reasons. There is a slight coding advantage to not building a throw away UserBuffer Output (See below).

If StreamingOutputsEnable is set to false, the StreamingOutputs you Added will not be processed. You were caught in a validation feature. The MotionAttribute set by enable indicated you wanted to use them, but none were found. If you aren’t finding yourself constrained by your hardware, you should be fine with always enabled.

Thanks for pointing out the documentation error. We store the outputs in a Vector rather than an Array (early versions) so the size isn’t you need to worry about. We just use it on the next Streaming Motion (MovePT etc) call. When EnableSet(FALSE) is called we .clear() the vector that contains Added StreamingOutputs. This is all the Clear function does. We do not remove items from the Added list until you disable or Clear. Use Clear() before you build a new set of outputs unless you want keep those used in the last iteration.

Both (onMask, OffMask) are applied. In most use cases, you don’t need both though. However, imagine you had a node which had a byte representing 8 Digital outputs. You might want a combination of the two in that situation.

If you know you are going to run ‘Always Enabled’, I recommend adding an output to an unneeded UserBuffer on point 0 of your streaming segment. This meets the requirement having an output while not requiring foreknowledge.

1 Like

Thanks for the details, @jacob.

I still have a few questions.

MASKS
So, which mask is applied first? Does it turn bits on first, and then off, or the other way around? I shouldn’t shoot myself in the foot by turning the same bit off/on or on/off, but supposing I did, which would wiv?

SIZE
Is there a size limit on SOL? I assume this is in the firmware and so size is a legitimate concern. Probably, I’ll never reach the limit, but if there is one, I’d prefer to know what it is, or at least its magnitude (tens, hundreds, … ?) or what factors affect the size limit (e.g. recorders are limited by both recorder and data item count).

ptPointIndex
Am I supposed to use an index into the (2-D array of) motion data I’m sending via MovePT(...) (or a motion ID)?

MotionID
Should I expect the output to activate when the target motion ID / index is executING or executED? I need to sync the corresponding object in our CNC software. The combination of MotionIdExecutingGet() / MotionElementIdExecutingGet() tells me that the output is guaranteed to be on (or, at least, the value’s been sent to the node) when this pair is strictly greater than the id/index I inferred/used just before calling MovePT() or is the guarantee that it’s on when it’s currently executing? (I would assume the former, but that’s only a guess).

Hi Todd,

Off Mask is applied, then On Mask. I don’t know the details of what you are trying to accomplish but that ~intent~ should be your guide at any given point. If a bit is in neither mask, it will retain its original state.

On Size, each Output takes up a Frame. Here like with adding points while streaming, your available space is determined by your consumption of points. You will get a Frame_Buffer_Overrun error Message if you ever try to overwrite your current executing one with those you are lining up for the queue. This is configurable using Controller.AxisFrameBufferSizeSet which defaults to 512.

The MotionElementExecutingID at which to set the output. The valid range is from 0 to the last point index of the currently executing streaming move. Aka the associated index of the group of the next Streaming motion call.

It should start executing when it reaches that index not when it is ready to move on the next one.

1 Like

Supposing that I never ...Add(...) an output off during streaming, and then I stop streaming.

What should I expect the output state to be?

I’ve observed that until I disable the motor, I’m not able to force the output low in RapidSetup. Is this what I should expect?