Changing Allocation Counts: Invalidating RMP Objects

[RMP 8.3.1]

In the APIs that set the count of some (preallocated) objects, I see some very hard-to-miss notes:

This should be done after Creating the Controller and before any other RapidObject creation as it will invalidate non-Controller Objects. (AxisCountSet(), RecorderCountSet(), MotionCountSet())

The maximum number of UserLimits available can be checked with UserLimitCountMax(). UserLimitCountSet should be done after either setting AxisCountSet and/or starting the network (both of those can modify the AxisCount). Internally, RapidCode Axis objects will use UserLimits so it is important to only call UserLimitCountSet after all Axis object counts have been set, but before creating any Axis objects. (UserLimitCountSet())

Just to be clear, which objects will be (instantly) invalidated when I invoke one of these methods:

  • RapidCodeNetworkNode
  • Axis
  • MultiAxis
  • IO
  • IOPoint
  • user limits (not objects exactly, but referenced by an index)
  • recorders (same as user limits)

Is this correct?

Yes.

1 Like

It seems, that if I change allocated counts enough, that user limits API functions will start to complain when I don’t expect them to.

Scenario:

  • Start the network
  • Set recorder count to 4
  • Set user limit count to 32
  • configure some stuff, including user limits
  • Set recorder count to 6
    • first, discarding all previously configured stuff
  • attempt to (re) configure some stuff, including user limits
    • BOOM!

The exceptions that I’m seeing look like this:

Control: Object cannot be used after reallocation :: {userlimit.c, line 4993} (Error 1585) (RSI::RapidCode::Impl::MotionController::UserLimitDisable) (Object 0) (File …\…\source\motioncontroller.cp…

(I routinely disable user limits before attempting to configure them.)

Control: Object cannot be used after reallocation :: {userlimit.c, line 4993} (Error 1585) (RSI::RapidCode::Impl::MotionController::UserLimitConditionSet) (Object 0) (File …\…\source\motioncontroll…

(This is the first thing I do in order to configure a “new” user limit.)

I have verified that the index being used is less than the value returned by UserLimitCountGet().

Creating? a User Limit

First, if I reallocate some global RMP objects, how do I “create” a new user limit? I don’t mean setting the count, I mean using the API. I would have thought that UserLimitConditionSet(...) would be OK, or, really that most of the APIs would be OK since there really isn’t a “getter” for a user limit object. We only have handles/indices to work with.

Multiple Reallocations

Is there any conceptual problem with changing the counts of various objects multiple times? (Pretend that I have a good reason.) I mean, as long as I throw away all the old objects (which I’m doing for Axis and IO objects).

Similarly, if I change the user limit count a second time, (at least some of) my calls to RecorderDataCountSet(...) fail:

Control: Object cannot be used after reallocation :: {recorder.c, line 2857} (Error 1585) (RSI::RapidCode::Impl::MotionController::RecorderDataCountSet) (Object 0) (File …\…\source\motioncontroller…

I’m in the same position regarding these “objects,” in that I don’t know how to “create” them.

Ideally the *CountSet() methods should be called near the start of your program before you even start the network with the largest maximum number of those objects you intend to use and then not called again.

Please elaborate on “configured stuff and configured some stuff” with the actual rapid code function calls you are making. There a lot of potential calls that could cause problems here.

I don’t think I’ll be able to meaningfully distill 25% of my multithreaded application into a chronological list of API calls that I make. It’s just too big and changes slightly every time I run it. I’m not submitting a bug as much as asking for clarification about expectations I should have.

Configure Stuff

  • Axis
    • set error actions
    • set origin offsets
    • configure interrupts
    • make SDO calls
    • get/set PDO values
    • enable/disable
    • many, many, many things
  • User Limits
    • configure, config, enable user limits
    • perhaps even one or two will hit/activate
  • Recorders
    • set data counts, addresses, masks, etc.
    • start recorders
    • potentially stop (some) recorders (depending on circumstances)

Application Behavior

The thing that makes what I’m doing complicated is that there is no central agent that knows what the requirements are for the number of user limits or recorders. Any of a dozen different objects of mine determine their own needs, and then submit requests to an agent acting as the interlocutor to the motion controller to set the count, etc. So, generally, the interlocutor asks each of its “clients” how many “thingies” they need, they reply, a total is calculated, and the count is set (API call).

One down side of this strategy is that changing counts invalidates all my RMP objects, so I have to destroy and recreate them. This is OK, but to accomplish this, I basically start over as if I just started the network.

It’s possible that one of my modular objects will decide, based on its individual configuration (not known early on, when the initial count of objects is assessed) that it needs more of these resources than are currently allocated. In this case, the interlocutor will set the count (again), discard all my objects, and start over, as if the network had just been started.

In this circumstance, I’m seeing problems with recorders and user limits because I cannot discard anything about them and start over. The API doesn’t return anything to me that I can “get” again. I just use the indices (a handle to an RMP object, essentially) to use them. I don’t know of a way to “reset” them or have RMP re-create/re-issue them, like I would using MotionController::AxisGet(...), for example.

Needs

I’m not so much asking for software design advice here. I realize that knowing everything up front would make this problem wonderfully simple to fix. In my case, I cannot feasibly know everything up front. I’m trying to use RMP features that seem sensible, but that’s just based on my own reading of the docs.
I want to know what I should expect from RMP in this scenario.

  • Is it legal to change allocation counts for a specific resource multiple times?
    • It seems like this ought to work.
    • What kind of behavior (on my part) is allowable?
    • What API calls (or host/firmware settings changes) could I make that could cause the behavior I’m seeing?
      • I can’t give you a simple list or MWE. It’s neither simple nor minimal. I need to be able to narrow down my investigation to likely candidates for problem behavior.
  • Is there any way to get RMP to “recreate” obsolesced user limits or recorders (similar to what AxisGet(...) does)?
    • In other words, how do I recover from one of the OBJECT_OBSOLESCED errors I might encounter?

Anecdotal evidence suggests that there are some things I can do that will result in the obsolesced errors to go away, but I don’t know precisely what that might be.

  • wait long enough?
  • recreate the motion controller (without restarting the RTA)?

I think this would work.

So, are you saying that changing object counts multiple times won’t work?

I’m hoping for something other than a workaround, here.

Is there a good reason why user limits or recorders should ever tell me that they’ve been obsolesced without any recourse to fix just that problem? For the sake of simplicity (which means robustness and maintainability), I’d like to do only what’s necessary to fix a problem.

You could give these two a try:
UserLimitReset()
and
RecorderReset()

It’s hard to know what will and won’t work for your specific application given the many many things that are happing in an unknown order.

The description for user limit reset API function doesn’t sound like it would do anything. The recorder one, maybe. But I’m only looking at the documentation. Can’t you look at the actual implementation and tell me how it works?

Suppose whatever happens, resulting in a user limit index being marked as obsolesced, happens. Can you tell me how the motion controller would ever deduce that the user limit was no longer obsolesced? Is there an API call that is supposed to do it? I assume you can look in the code and tell how or why a user limit (or recorder) gets marked this way. What ever clears the mark?

Is there no way that you can tell me how the APIs could reasonably be called that would result in the behavior I’m seeing? You don’t need to fix my application. I just want to know how yours behaves.

Hey Todd,

Fundamentally, we expect you to assign your object counts first and foremost. Doing any configuration of objects might be invalidated by further allocations as we change where the objects are stored memory on reallocation.

I would recommend to everyone that they call all of these methods before starting configuration on any of the parts.

If you determine you later need more objects, you kick off a fresh pass of your initialization code which would set counts, configure objects, then move on to normal operation. It may be better to just buffer extra objects which you don’t plan to use expect for rare cases. Initially set your recorder count to 6 even if you plan to only use 4. There some small processing time which is required for unused objects. This is why we don’t just set the UserLimitCount to 2048 by default. But going from 4 to 6 or blocking out your expected rare uses is reasonable. Tightening the belt should only be required if you are trying to go cheap on the computer.

1 Like

Thanks for the info, Jacob.

I can appreciate the desirability of the omniscient foreknowledge approach, but it’s too late for me to change to that (and I wouldn’t prefer to do it anyway) unless there were a really big payoff (e.g., there’s absolutely no other way).

I am content to reinitialize, since we need to be able to recover from disastrous events (like temporarily disconnecting the EtherCAT master from node 0), so it’s reasonable (for me) to discard things and start over.

My application saves the allocation counts (as soon as it knows them) so that the next time it starts, it can preallocate the correct quantities all up front. The scenarios I’m struggling with are on initial startups and physical network reconfiguration when nodes are added.

The problem I’m encountering is happening while I’m doing the re-initialization. Previous to yesterday, I was discarding everything except the motion controller object and initializing from there. I’ve since added the “ability” to initialize from that point, too, deleting and recreating the motion controller. If that’s what I have to do, I can cope with that. Yesterday, I added the power to jump the initialization back a step further and recreate the motion controller object. I haven’t seen the obsolesced errors since I did that.

What I really need from you is an understanding of what I need to do in order to sufficiently recover from the fallout of reallocating. I consider the exceptions I’m getting from the user limit and recorder APIs to be kind of wrong/bad, but I don’t insist that you upend your product just because it’s Not The Absolute Correct-est Behavior™.

I thought perhaps I was not doing enough to discard my “old objects” (the docs refer to subordinates of the motion controller object), but if I’m just (ab)using RMP features by reallocating, then I’ll do what I need to do in order to reinitialize. I just don’t want to have to do more than what’s necessary—partly because I want to actually know what’s necessary, and partly because starting from step 0 every time can be frustratingly time-consuming for the customer. I dislike voodoo and magic, so I’d like to behave intelligently within the limits set by RMP. I just need to know what they are.

Hi Todd,

I was able to reproduce, unit test, and resolve the behavior you were experiencing. It isn’t an intended use case, but it should be safety for you to use in future releases.

2 Likes

Can you describe the newer behavior in terms of what’s different?

Hi Todd,

In version 10.2.3+, you will be able to make calls to UserLimits and Recorders indexes you have previously leveraged without getting the “Control: Object cannot be used after reallocation” error. They will however be a blank slate like they are on initial creation/access.

That would certainly match my assumptions of how they would behave if they’d been deallocated and recreated (under the covers).

Thanks, Jacob.