init
This commit is contained in:
363
processors/ripr_agents/aiai/behavior_pincer_fsm.txt
Normal file
363
processors/ripr_agents/aiai/behavior_pincer_fsm.txt
Normal file
@@ -0,0 +1,363 @@
|
||||
# ****************************************************************************
|
||||
# CUI
|
||||
#
|
||||
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
|
||||
#
|
||||
# The use, dissemination or disclosure of data in this file is subject to
|
||||
# limitation or restriction. See accompanying README and LICENSE for details.
|
||||
# ****************************************************************************
|
||||
|
||||
|
||||
behavior pincer_fsm
|
||||
|
||||
script_debug_writes off
|
||||
|
||||
script_variables
|
||||
//debug parameters
|
||||
bool mDrawSteering = false;
|
||||
|
||||
//parameters for how to initially fly pincer (1st phase, separation)
|
||||
string mDirection = "none";
|
||||
double mPincerSpeed = 500 * MATH.MPS_PER_NMPH(); //400 kts
|
||||
double mPincerOffsetAngle = 70.0; //degrees
|
||||
|
||||
//parameters for determining if to chase and how to do so (2nd phase, option A)
|
||||
double mEnemyFOVHalfAngle = 50.0; //degrees
|
||||
double mChaseAngle = 75.0; //degrees
|
||||
double mChaseSpeedlnsideFOV = 600 * MATH.MPS_PER_NMPH(); //600 kts
|
||||
double mChaseSpeedOutsideFOV = 1200 * MATH.MPS_PER_NMPH(); //1200 kts
|
||||
|
||||
//parameters for determining if to drag (run) and how to do so (2nd phase, option B)
|
||||
double mRunDistance = 130 * 1852; //130nm (meters)
|
||||
double mRunAngleLimit = 15.0; //degrees
|
||||
double mDragSpeed = 800 * MATH.MPS_PER_NMPH(); //800 kts
|
||||
double mDragAddedAngle = -1.0; //degrees
|
||||
|
||||
// bidding parameters (similar to pursue-target parameters)
|
||||
double cMIN_JOB_BID = -MATH.DOUBLE_MAX();
|
||||
# double cWEIGHT_CURRENT_TARGET = 10.0;
|
||||
# double cWEIGHT_CLOSING_SPEED_OF = 0.5; #1.0;
|
||||
# double cWEIGHT_SLANT_RANGE_TO = -4.0; #-3.0;
|
||||
# double cWEIGHT_FUEL = 2.0;
|
||||
# double cWEIGHT_WEAPONS_IN_FLIGHT = 0.0;
|
||||
# double cWEIGHT_ANY_WEAPONS_ACTIVE = 20.0;
|
||||
# double cWEIGHT_THREAT_WEAPONS_ENVELOPE = 10000.0;
|
||||
# double cBASE_SLANT_RANGE_CONSTANT = 600000.0; //over 300 nm away [How is this used???]
|
||||
# double cBASE_CLOSING_SPEED_CONSTANT = 1050.0; //over 2000 kts closing speed
|
||||
double cMAX_SLANT_RANGE = 1000000.0; #over 539 nm away, target ranges beyond this are considered unfavorable
|
||||
double cWEIGHT_SLANT_RANGE_TO = 1.0;
|
||||
double cMIN_CLOSING_SPEED = -1050.0; #threats running away (negative closing) faster are considered unfavorable
|
||||
double cWEIGHT_CLOSING_SPEED = 1.0; #scale for how closing speed translates to distance
|
||||
double cWEIGHT_FUEL = 0.0; #try a value of 2.0 if you care about fuel
|
||||
double cWEIGHT_MY_WEAPONS_ACTIVE = 0.0; #changes bid if your own weapons are active on target
|
||||
double cWEIGHT_PEERS_WEAPONS_ACTIVE = 0.0; #changes bid if your peers weapons are active on target
|
||||
double cWEIGHT_THREAT_WEAPONS_ENVELOPE = 10000.0; #uses the global "mWeaponsEnvelope" array, try value of 10000 if you care about that
|
||||
//careful with these two parameters, they are stateful
|
||||
double cWEIGHT_CURRENT_TARGET = 0.0; #changes bid if you are currently targeting the threat
|
||||
|
||||
//util var, not for user edit
|
||||
WsfGeoPoint mPincerPoint;
|
||||
WsfDraw mDraw = WsfDraw();
|
||||
|
||||
WsfRIPRJob mCurrentJob;
|
||||
WsfTrack mWorstTrack;
|
||||
double mWorstDist = MATH.DOUBLE_MAX();
|
||||
double mWorstFOV = MATH.DOUBLE_MAX();
|
||||
end_script_variables
|
||||
|
||||
|
||||
script double GetPincerDragOffset(WsfTrack aTgt)
|
||||
if (aTgt.Speed() >= PLATFORM.Speed())
|
||||
{
|
||||
return 180.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (180 - MATH.ACos(aTgt.Speed()/PLATFORM.Speed()));
|
||||
}
|
||||
end_script
|
||||
|
||||
precondition
|
||||
|
||||
if (!PROCESSOR.IsA_TypeOf("WSF_RIPR_PROCESSOR"))
|
||||
{
|
||||
return Failure("behavior not attached to a RIPR processor!");
|
||||
} // ((WsfRIPRProcessor)PROCESSOR)
|
||||
|
||||
#writeln_d("precondition pincer");
|
||||
if (((WsfRIPRProcessor)PROCESSOR).GetRIPRCommanderProcessor().IsValid())
|
||||
{
|
||||
mCurrentJob = ((WsfRIPRProcessor)PROCESSOR).GetRIPRCommanderProcessor().GetJobFor(TIME_NOW, ((WsfRIPRProcessor)PROCESSOR));
|
||||
if (mCurrentJob.IsValid())
|
||||
{
|
||||
// If we're supposed to fly towards a point, go for it!
|
||||
if (mCurrentJob.Name() == "pincer")
|
||||
{
|
||||
mPincerPoint = (WsfGeoPoint)mCurrentJob.GetData("ZonePoint");
|
||||
mDirection = (string)mCurrentJob.GetData(PLATFORM.Name());
|
||||
if (mPincerPoint.IsValid())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d(PLATFORM.Name(), " pincer point not valid!");
|
||||
return Failure("pincer job did not have valid point");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d(PLATFORM.Name(), " job not a pincer job: ", mCurrentJob.Name());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d(PLATFORM.Name(), " job not valid!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln_d(PLATFORM.Name(), " commander not found!");
|
||||
return Failure("no commander found");
|
||||
}
|
||||
return Failure("current job not a valid pincer job");
|
||||
end_precondition
|
||||
|
||||
|
||||
### FSM states are evaluated after "execute"
|
||||
execute
|
||||
writeln_d(PLATFORM.Name(), " executing pincer!, T=", TIME_NOW);
|
||||
//provide for another channel for pursue-target jobs
|
||||
if (((WsfRIPRProcessor)PROCESSOR).NumJobChannels() <= 1)
|
||||
{
|
||||
((WsfRIPRProcessor)PROCESSOR).SetNumJobChannels(2);
|
||||
}
|
||||
((WsfRIPRProcessor)PROCESSOR).ClearTarget();
|
||||
|
||||
//save off the closest opponent track
|
||||
mWorstDist = MATH.DOUBLE_MAX();
|
||||
mWorstFOV = MATH.DOUBLE_MAX();
|
||||
Array<string> targetNames = (Array<string>)mCurrentJob.GetData("ZoneThreatNameArray");
|
||||
foreach(string tgtName in targetNames)
|
||||
{
|
||||
WsfTrack tgt = GetTrackByName(PLATFORM, tgtName);
|
||||
if (tgt.IsValid() && tgt.LocationValid())
|
||||
{
|
||||
double attackRange = tgt.GroundRangeTo(PLATFORM);
|
||||
if (attackRange < mWorstDist)
|
||||
{
|
||||
//run away, drag threats out
|
||||
mWorstDist = attackRange;
|
||||
mWorstTrack = tgt;
|
||||
}
|
||||
double fov = MATH.Fabs(tgt.RelativeBearingTo(PLATFORM));
|
||||
if (fov < mWorstFOV)
|
||||
{
|
||||
mWorstFOV = fov;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# if (mDrawSteering == true)
|
||||
# {
|
||||
# WsfGeoPoint pt = PLATFORM.Location();
|
||||
# pt.Extrapolate(heading, 185200);
|
||||
# mDraw.SetLayer("behavior_pincer");
|
||||
# mDraw.SetDuration(((WsfRIPRProcessor)PROCESSOR).UpdateInterval());
|
||||
# mDraw.SetColor(0.0, 1.0, 0.75); //green-blue
|
||||
# mDraw.SetLineSize(1);
|
||||
# mDraw.BeginLines();
|
||||
# mDraw.Vertex(PLATFORM.Location());
|
||||
# mDraw.Vertex(pt);
|
||||
# mDraw.Vertex(PLATFORM.Location());
|
||||
# mDraw.Vertex(mPincerPoint);
|
||||
# mDraw.End();
|
||||
# }
|
||||
end_execute
|
||||
|
||||
|
||||
script bool ShouldChase()
|
||||
int allOnCap = (int)mCurrentJob.GetData("all_on_cap");
|
||||
if (allOnCap > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int other_dragging_count = 0;
|
||||
if (mDirection == "right")
|
||||
{
|
||||
other_dragging_count = (int)mCurrentJob.GetData("left_drag");
|
||||
}
|
||||
else if (mDirection == "left")
|
||||
{
|
||||
other_dragging_count = (int)mCurrentJob.GetData("right_drag");
|
||||
}
|
||||
double diff = 0;
|
||||
if (mWorstTrack.IsValid() && mWorstTrack.HeadingValid())
|
||||
{
|
||||
double b1 = mWorstTrack.Heading();
|
||||
double b2 = mWorstTrack.TrueBearingTo(PLATFORM.Location());
|
||||
diff = MATH.NormalizeAngleMinus180_180(b2 - b1);
|
||||
}
|
||||
if (other_dragging_count > 0 && MATH.Fabs(diff) > mEnemyFOVHalfAngle)
|
||||
{
|
||||
//the other pincer group is being engaged, turn in now
|
||||
writeln_d(PLATFORM.Name(), " chasing because other pair is dragging");
|
||||
return true;
|
||||
}
|
||||
else if ((mDirection == "right" && diff < -mChaseAngle) ||
|
||||
(mDirection == "left" && diff > mChaseAngle) )
|
||||
{
|
||||
//we have already flanked, so now we can chase (regardless of other side dragging or not)
|
||||
writeln_d(PLATFORM.Name(), " chasing because past chase angle");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
end_script
|
||||
|
||||
|
||||
#show_state_transitions
|
||||
#first default state, start here and go back to here if confused
|
||||
state SEPARATE
|
||||
|
||||
next_state DRAG
|
||||
int allOnCap = (int)mCurrentJob.GetData("all_on_cap");
|
||||
if ( (allOnCap <= 0) &&
|
||||
(mWorstDist < mRunDistance) &&
|
||||
(mWorstTrack.IsValid()) &&
|
||||
(mWorstTrack.HeadingValid()) &&
|
||||
(MATH.Fabs(mWorstTrack.TrueBearingTo(PLATFORM)-mWorstTrack.Heading()) < mRunAngleLimit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
end_next_state
|
||||
|
||||
next_state CHASE
|
||||
return ShouldChase();
|
||||
end_next_state
|
||||
|
||||
next_state SEPARATE
|
||||
double separate_angle = 0;
|
||||
if (mDirection == "left")
|
||||
{
|
||||
separate_angle = -mPincerOffsetAngle;
|
||||
}
|
||||
else if (mDirection == "right")
|
||||
{
|
||||
separate_angle = mPincerOffsetAngle;
|
||||
}
|
||||
double heading = MATH.NormalizeAngle0_360(PLATFORM.TrueBearingTo(mPincerPoint) + separate_angle);
|
||||
PLATFORM.GoToSpeed(mPincerSpeed);
|
||||
PLATFORM.TurnToHeading(heading);
|
||||
return true;
|
||||
end_next_state
|
||||
end_state
|
||||
|
||||
|
||||
state DRAG
|
||||
next_state SEPARATE
|
||||
if ( (!mWorstTrack.IsValid()) ||
|
||||
(mWorstDist > (mRunDistance*1.1)) ||
|
||||
(!mWorstTrack.HeadingValid()) ||
|
||||
(MATH.Fabs(mWorstTrack.TrueBearingTo(PLATFORM)-mWorstTrack.Heading()) > (mRunAngleLimit*1.1)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
end_next_state
|
||||
|
||||
next_state DRAG
|
||||
writeln_d("dragging!");
|
||||
//try to maintain distance
|
||||
PLATFORM.GoToSpeed(mDragSpeed);
|
||||
double dragOffset = GetPincerDragOffset(mWorstTrack);
|
||||
double heading;
|
||||
if (mDirection == "right")
|
||||
{
|
||||
if (mDragAddedAngle > 0)
|
||||
{
|
||||
heading = MATH.NormalizeAngle0_360(heading + mDragAddedAngle);
|
||||
}
|
||||
else
|
||||
{
|
||||
heading = MATH.NormalizeAngle0_360(PLATFORM.TrueBearingTo(mPincerPoint) + dragOffset);
|
||||
}
|
||||
}
|
||||
else if (mDirection == "left")
|
||||
{
|
||||
if (mDragAddedAngle > 0)
|
||||
{
|
||||
heading = MATH.NormalizeAngle0_360(heading - mDragAddedAngle);
|
||||
}
|
||||
else
|
||||
{
|
||||
heading = MATH.NormalizeAngle0_360(PLATFORM.TrueBearingTo(mPincerPoint) - dragOffset);
|
||||
}
|
||||
}
|
||||
PLATFORM.TurnToHeading(heading);
|
||||
return true;
|
||||
end_next_state
|
||||
|
||||
on_entry
|
||||
if (mDirection == "right")
|
||||
{
|
||||
int count = (int)mCurrentJob.GetData("right_drag");
|
||||
mCurrentJob.SetData("right_drag",count+1);
|
||||
writeln_d(PLATFORM.Name(), " increased right_drag to: ", count+1);
|
||||
}
|
||||
else if (mDirection == "left")
|
||||
{
|
||||
int count = (int)mCurrentJob.GetData("left_drag");
|
||||
mCurrentJob.SetData("left_drag",count+1);
|
||||
writeln_d(PLATFORM.Name(), " increased left_drag to: ", count+1);
|
||||
}
|
||||
end_on_entry
|
||||
|
||||
on_exit
|
||||
if (mDirection == "right")
|
||||
{
|
||||
int count = (int)mCurrentJob.GetData("right_drag");
|
||||
mCurrentJob.SetData("right_drag",count-1);
|
||||
writeln_d(PLATFORM.Name(), " decreased right_drag to: ", count-1);
|
||||
}
|
||||
else if (mDirection == "left")
|
||||
{
|
||||
int count = (int)mCurrentJob.GetData("left_drag");
|
||||
mCurrentJob.SetData("left_drag",count -1);
|
||||
writeln_d(PLATFORM.Name(), " decreased left_drag to: ", count-1);
|
||||
}
|
||||
end_on_exit
|
||||
end_state
|
||||
|
||||
state CHASE
|
||||
|
||||
next_state SEPARATE
|
||||
return ! ShouldChase();
|
||||
end_next_state
|
||||
|
||||
next_state CHASE
|
||||
writeln_d("chasing!");
|
||||
if (mWorstFOV <= mEnemyFOVHalfAngle)
|
||||
{
|
||||
PLATFORM.GoToSpeed(mChaseSpeedlnsideFOV);
|
||||
}
|
||||
else
|
||||
{
|
||||
PLATFORM.GoToSpeed(mChaseSpeedOutsideFOV);
|
||||
}
|
||||
double heading = 0;
|
||||
if (mWorstTrack.IsValid())
|
||||
{
|
||||
heading = PLATFORM.TrueBearingTo(mWorstTrack);
|
||||
((WsfRIPRProcessor)PROCESSOR).SetTarget(mWorstTrack);
|
||||
}
|
||||
else
|
||||
{
|
||||
heading = PLATFORM.TrueBearingTo((WsfGeoPoint)mCurrentJob.GetData("ZonePoint"));
|
||||
}
|
||||
PLATFORM.TurnToHeading(heading);
|
||||
return true;
|
||||
end_next_state
|
||||
end_state
|
||||
|
||||
end_behavior
|
||||
Reference in New Issue
Block a user