question

Patrick Zweekhorst avatar image
0 Likes"
Patrick Zweekhorst asked anthony.johnson answered

Customizing rotation AGV network in FS 2022.2

Hi @anthony.johnson

We have been doing some tests on the new AGV functions and we have some questions on how some things work. First of all the new features look really useful and work pretty nice!!

We are trying to customize the rotation of the AGV at the transfers. This seems to be almost working already, but maybe you could explain the steps a bit more. We are for example not sure what all parameters mean. Our code now looks like this:
1657098918505.png

We want the AGV to wait 10 seconds before the rotation starts. When the rotation is finished the AGV again needs to wait 10 seconds before it continues to travel. After these wait times the AGV either needs to unload or load the items. We have now done this by sending a delayed message. Is this how you intended this feature to be used, or are we maybe missing some steps?

We are for example not sure if we have the information to know if the AGV should rotate +90 degrees or -90 degrees. Is there information available in this code to know this? Can the settings from the AGV network be used? Or should we decide that our self in this code?

Thank you for some extra explanation about this code.

Patrick

AgvTestRotate.fsm


FlexSim 22.1.2
agvcustomizationdelegate
1657098918505.png (39.3 KiB)
agvtestrotate.fsm (42.6 KiB)
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

1 Answer

anthony.johnson avatar image
2 Likes"
anthony.johnson answered

My initial thought was that the code would be much simpler than that. You're just tasked with making the AGV rotate, and telling the AGV system how long it will take. You really shouldn't do anything other than that. If you want to do other things, then make them part of separate tasks like load/unload.

To just add an extra 10 seconds before and after the rotation, you just do what you did without all the other stuff:

return addkinematic(kinematics, 0, 0, rotation, rotSpeed, 0, 0, 0, 0, startTime + 10, KINEMATIC_ROTATE) + 10;

The number of degrees you need to rotate is encoded in param(2), and will be negative if you need to rotate negative degrees.

I've added more detailed documentation for the AGV customization delegate. This will be in the next beta/release, but I'm copy/pasting it here so you can see it now.

AGV Customization Delegate

In addition to the standard features provided through FlexSim's user interface, the AGV module provides a mechanism for advanced users to customize AGV travel at a much more detailed level. The AGV network uses an "AGV Customization Delegate", which allows for hooks to be placed at certain points in the AGV navigation logic. There is a default, internally defined customization delegate that the AGV network uses, but you can override the logic of this default delegate by adding and configuring a special node at MODEL:/AGVNetwork>variables/customizationDelegate, as follows:

  1. Navigate in the tree to MODEL:/AGVNetwork>variables/customizationDelegate
  2. Right click on that node, and choose Edit > Designate this Node (so)
  3. In a script window execute the script: nodeadddata(so(), DATATYPE_SIMPLE)
  4. Add a subnode to that node named sdt::attributetree and give it the text: AGV::UserAGVCustomizationDelegate.
  5. Copy the node and then paste it onto itself. This will instantiate a "UserAGVCustomizationDelegate" class, which has hooks where you can implement customizations in FlexScript.

The various customization hooks are best described within the context of an AGV's overall travel operation. An AGV performs several sequential operations as part of configuring and completing a travel task. They are:

  1. Resolve Routing
    The AGV system uses a "lazy" dijkstra's algorithm to cache routing tables, stored by destination. When you reset your model, all cached routing tables are cleared. Then when an AGV must travel to a certain destination, if that destination does not have a cached routing table, it will build a table on-the-fly using dijkstra's algorithm, and then store it off for later reuse. This table defines 'cost' and 'next' routing values for getting from every point in the AGV path network to that destination point. A destination may actually have multiple routing tables, where each table is uniquely addressed by a tuple key based on conditional rules.
    The AGV system also allows for more dynamically built tables, where a route to a destination is resolved using the A* algorithm and is completely recalculated on every travel operation. This mode is enabled either when the shouldBuildCustomRoute hook returns 1, or when you have defined dynamic routing constraints in the system.
    In both dijkstra's and A* mode, the AGV will call the getPathTravelWeight hook to resolve the 'cost' of traveling on a given section of path.
  2. Build Travel Path
    In this step, the AGV uses the routing table to build a locally-stored travel path to the destination. Here the AGV resolves things like the orientation of the AGV while traveling on each path section in the route, and also builds a list of lookahead allocation points that the AGV must acquire while traveling the path.
  3. Set Travel Path Speed Profile
    In this step, the AGV goes through its travel path and sets maximum travel speeds, acceleration, and deceleration values for each travel path section. It first traverses the travel path forward, calling the customization delegate setSpeedProfile hook. Then it traverses backwards, resolving points where the AGV must start decelerating in order to meet path section speed requirements.
  4. Lookahead Allocation/Kinematics
    In this step, the AGV repeatedly allocates ahead to its next allocation point, calling the addKinematics and addRotation hooks to add kinematics that traverse the travel path sections up to the next allocation point. It adds kinematics as-if it will not immediately allocate ahead at the next lookahead point, and then schedules a pre-arrival event for the next point at which it needs to allocate ahead. If, at that time, it cannot immediately allocate ahead, then it simply lets the kinematics finish, coming to a stop at the lookahead point. If, on the other hand, the AGV does immediately allocate ahead, then it resets the kinematics to start at the current position and speed, then repeats the process again, adding kinematics to travel to the next lookahead point.

Customization Hooks

Adding the user customization delegate creates empty hook nodes for you to fill out. If you leave a hook unimplemented, then it will simply perform the default logic for that hook. To implement a hook, add text data to the corresponding node, toggle it as FlexScript, implement the proper customization code, and return the required value from the function.

The customization delegate hooks are as follows:

shouldBuildCustomRoute

This hook is executed at the beginning of an AGV's route resolution step. It should return 1 if you want to use a customized travel route, and 0 otherwise. If you return 1, then you must also implement a custom getPathTravelWeight hook. Note that more recent versions of FlexSim have added route cost features that are part of the user interface and use AGV's route caching mechanism. These newer features make this and the getPathTravelWeight hook mostly obsolete, and we advise using those features for customized routing instead of this feature.

The code header for this hook should be as follows:

AGV agv = param(1); // the traveling AGV
AGV.AllocatableObject currentCP; // the Control Point (if any) that the AGV is currently at
Object destination; // the destination object (if any)

getPathTravelWeight

This is executed repeatedly as part of the AGV's route resolution step. As it encounters path sections in traversing the path network, it calls this hook to determine a "cost" of traveling on this section. Generally this hook would return the distance of the path section, or the time to travel the path section, but you can customize it as needed. Note that more recent versions of FlexSim have added route cost features that are part of the user interface and use AGV's route caching mechanism. These newer features make this and the shouldBuildCustomRoute hook mostly obsolete, and we advise using those features for customized routing instead of this feature.

The code header for this hook should be as follows:

AGV agv = param(1); // the traveling AGV
Object path = param(2); // the path whose travel weight is being queried
double fromDist = param(3); // the 'start distance' on the path
double toDist = param(4); // the 'end distance' on the path

setSpeedProfile

This hook is called as part of the speed profile setting step. It allows you to define the max speed, acceleration and deceleration attributes of a travel path section. If you implement this hook, you should return 1.

The code header for this hook should be as follows:

AGV agv = param(1); // the traveling AGV
Object path = param(2); // the path whose travel weight is being queried
double fromDist = param(3); // the 'start distance' on the path
double toDist = param(4); // the 'end distance' on the path

Unfortunately, as of version 22.2, the FlexScript API does not provide a mechanism for setting these attributes directly on a travel path section (perhaps check the API directly to see if this has changed in future releases). However, you can call setsdtvalue() on the travel path section, with the values "peakSpeed", "acc", and "dec" to set these attributes.

addKinematics

This hook is called repeatedly as part of the lookahead allocation/kinematics step. It is called once for each travel path section up to the next lookahead point.

The code header for this hook should be as follows:

treenode kinematics = param(1); // the kinematics node to add kinematics to
AGV.TravelPathSection section = param(2); // the travel path section the AGV is to travel on
double atTravelDist = param(3); // the travel distance at which this kinematic will start
double dist = param(4); // the total distance that should be added to the kinematics, i.e. the distance to travel on that section
double startTime = param(5); // the start time for adding the kinematics
double startSpeed = param(6); // the speed the AGV will be traveling at startTime
double endSpeed = param(7); // the target end speed, i.e. the speed the AGV should be at when finished traveling the distance on the section
int reason = param(8); // 0: OnBuildKinematics, 1: OnAbort/OnPreempt, 2: OnProximityInterrupt
treenode endSpeedOut = param(9); // set the value of this node if the resulting endSpeed != original endSpeed
double peakSpeed = param(10); // the peak speed of the section
double acc = param(11); // the acceleration for the section
double dec = param(12); // the deceleration for the section 
AGV agv = section.agv;

The default implementation of this hook is:

return addkinematic(kinematics, dist, 0, 0, peakSpeed, acc, dec, startSpeed, endSpeed, startTime, KINEMATIC_TRAVEL);

If you implement this hook, your code must satisfy the following:

  • You must add kinematics with the addkinematic() command using KINEMATIC_TRAVEL.
  • Distances defined with addkinematic() should be exclusively defined on the x axis, i.e. the 3rd and 4th parameters of addkinematic() should always be 0.
  • The cumulative distances of the x parameters of all addkinematic() calls should be exactly dist (param(4)).
  • The earliest start time for any addkinematic() call must be no earlier than startTime (param(5)).
  • If adding multiple kinematics with addkinematic(), then those kinematics should not overlap in time.
  • The final end speed must be less than or equal to the passed endSpeed (param(7)). If your kinematics result in an end speed that is less than the passed endSpeed, then you must set endSpeedOut->value to the resulting end speed.
  • You must return from this hook the final end time at which the AGV has traveled the full distance.

addRotation

This hook is called as part of the lookahead allocation/kinematics step. It is only called when the AGV must stop and rotate to a new direction, based on its rotate threshold.

The code header for this hook should be as follows:

treenode kinematics = param(1); // the kinematics node to add kinematics to
double rotation = param(2); // the angle, in degrees, that the AGV must rotate
double rotSpeed = param(3); // the AGV's rotation speed
double startTime = param(4); // the time at which the AGV has come to a stop and can start rotating
AGV.TravelPathSection fromSection = param(5); // the path section that the AGV is transitioning from
AGV.TravelPathSection toSection = param(6); // the path section that the AGV is transitioning to

The default implementation of this hook is:

return addkinematic(kinematics, 0, 0, rotation, rotSpeed, 0, 0, 0, 0, startTime, KINEMATIC_ROTATE);

If you implement this hook, your code must satisfy the following:

  • You must add kinematics with the addkinematic() command using KINEMATIC_ROTATE.
  • Distances defined with addkinematic() should be exclusively defined on the z axis, i.e. the 2nd and 3rd parameters of addkinematic() should always be 0.
  • The cumulative distances of the z parameters of all addkinematic() calls should be exactly rotation (param(2)).
  • The earliest start time for any addkinematic() call must be no earlier than startTime (param(4)).
  • You must return from this hook the final end time at which the AGV has rotated the full rotation.
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.