Set transporter speed based on parameter of transported product?

Viewed 75

In my model I am transporting (path guided) several types of products (motors) by an agv trough a manufacturing line with 27 cycles. It´s a flowing manufacturing line. That means the product gets manufactured while the agv is constantly running.

To model that I created an agent population called "motors" with parameter "axelType" (string) which is loaded from column "axel_type" in database "manufacturing_sequence" (local excelsheet) and is placed on Main.

enter image description here enter image description here enter image description here

Each motor is placed on an transporter "agvAssembly" (in Flowchart as: Transporter) and runs from node "locationCycle1" all the way to "locationCycle27".

Now I want to change the transporters speed at each of the 27 cycle nodes dependent on the currently loaded motor. To do that I got another database called "speeds_axel" which includes all the needed speeds for the cycles and respective parameter name for axelType (column axel_type).

enter image description here

So now, when the transporter enters a node I have to check first the nodes name. Than I want to read out the parameter "axelType" of the currently in that node entered agent "Motor" and search in the database for the respective speed.

In the block "transporter Fleet" - "On enter node:" I wrote as an example for cycle 1 the following:

if (node == locationCycle1) {
    
    unit.setMaximumSpeed(
        selectFrom(speeds_axel)
        .where(speeds_axel.axel_type.eq(motor.axelType))
        .firstResult(false, speeds_axel.cycle1)/60.0,MPS);
}

When running the model I get the following error: "motor cannot be resolved to a variable" (location: TransporterFleet)

I think that error accures because my approach doesn't specify which motor I mean. How can I clarify to AnyLogic that I always mean the current motor which enters the node?

I need something like this:

if (node == locationCycle1) {
    
    unit.setMaximumSpeed(
        selectFrom(speeds_axel)
        .where(speeds_axel.axel_type.eq("get motor which is currently in locationCycle1".axelType))
        .firstResult(false, speeds_axel.cycle1)/60.0,MPS);
}

2 Answers

the biggest problem in your model is that you don't follow conventions. An agent type should be named with an uppercase first letter

Why is this important? Because you want to make the difference between Motor, motor, and motors Motor is the class (or Agent Type) motor is an instance of that class (or agent type) motors is a population.

Since you don't follow this convention, you make mistakes of this kind since motor is a class

in your case when you do motor.cycle1 if you followed the conventions, you would be doing Motor.cycle1 (which is obvioulsy wrong) Note that Motor is the Agent Type name, and what you really want is to know for a particular motor what the value of cycle1 is

The first thing you need to do with this model, is get back to using the conventions, and this will probably solve this problem and many problems in the future.

Just because you have a population called motors (which the agents within your flow 'come from' --- though it looks like they don't actually; see later), this does not mean that you can 'magically' refer to the current agent via the singular form motor at any point in the code. (And, similarly, your agent type being Motor does not mean you can use the lower-case form to refer to 'the current one'.)

In Transporter Fleet block "On enter node" actions, you refer to the current transporter via the unit keyword; see the help page. The motor is not the transporter; it's the thing being transported.

So, just use the "On exit" (or, better, "On at exit") actions of your MoveByTransporter blocks (which trigger on arrival at the destination node), where you can refer to the current motor (the agent in the flow) via the agent keyword; again, see the block help.

But, from a quick glance, there appear to be a few important changes/simplifications you should also make (though hard to definitively tell without details of all your code):

  • You are using a Source block to add agents (motors) to the flow when you have already created the motors in your population. You should be using an Enter block instead to add the (already-existing) Motor agents to the flow at the appropriate time (triggered by code: I imagine you want one to start at model start time, requiring code in Main's "On startup" action, and then others added either at certain simulation times or when earlier motors reach a certain stage in the process...). If your population was actually just for 'templates' of data for each motor axle type (and you would then potentially create multiple instances of motors for a given axle type) then your current logic might make sense, but your screenshot of your manufacturing_sequence table makes clear that isn't the case. (If you did go that route, you would want to rename your population so that its purpose was clear.)

  • It looks like you have a 'looping' process (with the same process behaviour for all your in-sequence nodes), so you should look to make your process generic with an explicit loop (so you don't have near-copies of blocks for every node in your sequence). There is a fair amount of detail in terms of how you do this but roughly:

    • Track the node the motor is currently in (or its sequence number) via a variable in the Motor agent.
    • Use a collection (List) which contains the nodes-in-order to determine where it has to go to next.
    • Your process would have a MoveByTransporter --> Delay --> SelectOutput sequence (plus TimeMeasureStart/End if you're using them), where SelectOutput loops back to the MoveByTransporter if the motor is not yet at the last node.
Related