Exemple #1
0
    /// <summary>
    /// Compute the cost associated with a given state, currently only TowardWallCost is used.
    /// </summary>
    /// <param name="state"></param>
    /// <returns>a scalar cost value</returns>
    public float GetStateCost(RedirectionManager.State state)
    {
        float cost = TowardWallCost(state);

        //Debug.LogError("!!!!!!! cost:"+cost+", pos:" + state.posReal + ", dir:" + state.dirReal);
        return(cost);
    }
Exemple #2
0
    public override List <Segment> GetNextSegments(RedirectionManager.State state)
    {
        List <Segment> segs = new List <Segment>();

        if (this.transitions == null) // this segment has no further transition
        {
            this.proba = 1;
            segs.Add(this);
            return(segs);
        }
        else if (IsEndOfSegment(state))
        {
            int num = this.transitions.Count;
            foreach (var transition in this.transitions)
            {
                transition.endSeg.proba = 1.0f / num;
                segs.Add(transition.endSeg);
            }
            return(segs);
        }
        else
        {
            this.proba = 1;
            segs.Add(this);
            return(segs);
        }
    }
Exemple #3
0
 /// <summary>
 /// To see if we need to update the current segment according to user's state.
 /// Whether a user stays at current segment, or he/she will jump into the next segment if near the end of the current one.
 /// </summary>
 /// <param name="state"></param> the state of the environment
 public void UpdateCurrentSegment(RedirectionManager.State state)
 {
     if (currSeg.IsEndOfSegment(state))
     {
         // We need to follow the Transition to the next segment
         Segment nextSeg = currSeg.transitions[0].endSeg;
         foreach (var trans in currSeg.transitions)
         {
             // return the segment with smaller id (user's path is predefined by segment id)
             if (trans.endSeg.id < nextSeg.id)
             {
                 nextSeg = trans.endSeg;
             }
         }
         currSeg = nextSeg;
     }
 }
Exemple #4
0
    public override List <Segment> GetNextSegments(RedirectionManager.State state)
    {
        List <Segment> segs = new List <Segment>();

        if (IsEndOfSegment(state))
        {
            foreach (var transition in this.transitions)
            {
                segs.Add(transition.endSeg);
            }
            return(segs);
        }
        else
        {
            segs.Add(this);
            return(segs);
        }
    }
Exemple #5
0
 public void UpdateWaypoint(RedirectionManager.State userCurrState)
 {
     if ((userCurrState.pos - Utilities.FlattenedPos3D(this.targetWaypoint.position)).magnitude < this.DISTANCE_TO_WAYPOINT_THRESHOLD)
     {
         // This is the last target
         if (this.waypointIterator == this.waypoints.Count - 1)
         {
             // Gather Summary Statistics for each episode
             simulationManager.statisticsLogger.experimentResults.Add(simulationManager.statisticsLogger.GetSummaryStatistics());
             this.simulationManager.EndRound();
         }
         else
         {
             this.waypointIterator++;
             this.targetWaypoint.position = new Vector3(
                 this.waypoints[this.waypointIterator].x,
                 this.targetWaypoint.position.y,
                 this.waypoints[this.waypointIterator].y);
         }
     }
 }
Exemple #6
0
    /// <summary>
    /// The cost is infinite if user is outside the tracked space
    /// When inside, the cost is inverse proportional to the longest walking distance described in the FORCE paper.
    /// </summary>
    /// <param name="state"></param>
    /// <returns>a scalar cost value</returns>
    private float TowardWallCost(RedirectionManager.State state)
    {
        // outside the tracking space
        if (Mathf.Abs(state.posReal.x) >= this.redirectionManager.resetter.maxX ||
            Mathf.Abs(state.posReal.z) >= this.redirectionManager.resetter.maxZ)
        {
            return(Mathf.Infinity);
        }
        else
        {
            Vector2 interPoint = Vector2.zero;
            // check the intersection of a ray casting from user's current pos/ori with the walls of the trackedspace
            for (int i = 0; i < this.redirectionManager.roomCorners.Length; i++)
            {
                interPoint = Utilities.GetIntersection(Utilities.FlattenedPos2D(state.posReal),
                                                       Utilities.FlattenedDir2D(state.dirReal), this.redirectionManager.roomCorners[i % 4],
                                                       this.redirectionManager.roomCorners[(i + 1) % 4]);

                // if we find the intersection point
                if (!interPoint.Equals(Vector2.zero))
                {
                    break;
                }
            }
            if (!interPoint.Equals(Vector2.zero))
            {
                float costLimit = 0.1f; // the max cost will be 100 if distance=0, this is to avoid 0-division
                float distance  = Vector2.Distance(Utilities.FlattenedPos2D(state.posReal), interPoint);
                //Debug.Log("pos: " + state.posReal + ", the interpoint is: " + interPoint
                //    +", distance: "+distance + ", cost:"+ 10 / (distance + costLimit));
                return(10 / (distance + costLimit));
            }
            else
            {
                Debug.LogError("user pos: " + state.posReal + " dir: " + state.dirReal + " Error computing intersection point");
                return(Mathf.Infinity);
            }
        }
    }
Exemple #7
0
 public override bool IsEndOfSegment(RedirectionManager.State currState)
 {
     // near the end direction
     return(Vector2.Angle(this.endDir, Utilities.FlattenedPos2D(currState.dir)) <= Segment.ANGLE_THRESHOLD);
 }
Exemple #8
0
 public override bool IsEndOfSegment(RedirectionManager.State currState)
 {
     return(Vector2.Distance(this.endPos, Utilities.FlattenedPos2D(currState.pos)) <= Segment.DISTANCE_THRESHOLD);
 }
Exemple #9
0
 public abstract bool IsEndOfSegment(RedirectionManager.State currState);
Exemple #10
0
    public const float ANGLE_THRESHOLD    = 5f;   // degree

    public abstract List <Segment> GetNextSegments(RedirectionManager.State state);
Exemple #11
0
    /// <summary>
    /// The main MPC K-stage forward planning, this is basically depth-first tree search with branch cutting.
    /// </summary>
    /// <param name="state"></param> current state
    /// <param name="currSeg"></param> current segment of the user
    /// <param name="depth"></param> the planning depth
    /// <returns></returns>
    public MPCResult Plan(RedirectionManager.State state, Segment currSeg, int depth)
    {
        //Debug.Log("Plan called");
        if (depth == 0)
        {
            return new MPCResult {
                       bestCost = 0, bestAction = { }
            }
        }
        ;
        else
        {
            float bestCost = Mathf.Infinity;

            Action bestAction = GetZeroAction();
            //Debug.Log("Plan depth="+depth+" pos="+state.posReal);
            float         cost;
            List <Action> allowedActions = GetAllowedActions(currSeg);
            //Debug.Log("GetAllowedActions");
            foreach (Action a in allowedActions)
            {
                //Debug.Log("depth=" + depth + ", action=" + a.type+", gain="+a.gain);
                cost = 0f;
                if (a.cost < bestCost)
                {
                    cost += a.cost;
                    List <Segment> nextSegments = currSeg.GetNextSegments(state);
                    //Debug.Log("GetNextSegments");
                    foreach (var nextSeg in nextSegments)
                    {
                        //Debug.Log("?????????? " + state.dirReal);
                        RedirectionManager.State nextState = ApplyStateUpdate(state, a, nextSeg);
                        //Debug.Log("pos="+state.posReal+" next pos="+nextState.posReal);
                        float stateCost = GetStateCost(nextState);
                        cost += stateCost * nextSeg.proba;
                        //Debug.Log("summed cost= " + cost + ", cost of next state: " + stateCost);
                        if (cost >= bestCost)
                        {
                            //Debug.Log("CUTOFF cost=" + cost + ", bestcost=" + bestCost);
                            break;
                        }
                        if (depth > 0)
                        {
                            MPCResult nextResult = Plan(nextState, nextSeg, depth - 1);
                            cost += declineFactor * nextSeg.proba * nextResult.bestCost;

                            //Debug.Log("Depth=" + depth + ", action: " + a.type + " gain: "+a.gain+
                            //        ", final cost=" + cost + ",  next bestcost=" + nextResult.bestCost);
                        }
                    }
                    if (cost < bestCost)
                    {
                        //Debug.Log("update best cost, new best=" + cost + ", old bestcost=" + bestCost+", action: "
                        //    +bestAction.type+", gain="+bestAction.gain);
                        bestCost   = cost;
                        bestAction = a;
                    }
                }
                else
                {
                    //Debug.Log("Depth=" + depth + " action " + a.type+ ":"+a.gain + " cutoff with cost " + a.cost);
                }
            }
            //if (depth==4)
            //{
            //    Debug.Log("Depth=" + depth + " final best cost: " + bestCost + ", best action: " + bestAction.type
            //    + ", gain: " + bestAction.gain + " at pos=" + state.posReal + " dir=" + state.dirReal);
            //}

            return(new MPCResult {
                bestAction = bestAction, bestCost = bestCost
            });
        }
    }
Exemple #12
0
    /// <summary>
    /// Get an estimate of the future state based on the current state, redirector's action and the path to be followed.
    /// ATTENTION: This method is only used for simulation(planning)! A user's actual state is only updated by the tracking system.
    /// </summary>
    /// <param name="s"></param> the current state of the environment.
    /// <param name="a"></param> action to be taken by the redirector.
    /// <param name="seg"></param> the path that the user is walking on in the current stage.
    public RedirectionManager.State ApplyStateUpdate(RedirectionManager.State state, Action a, Segment seg)
    {
        RedirectionManager.State newState = new RedirectionManager.State();
        if (seg is LineSegment)
        {
            LineSegment segment    = (LineSegment)seg;
            Vector2     tangentDir = (segment.endPos - Utilities.FlattenedPos2D(state.pos)).normalized;
            Vector2     delta_p    = this.redirectionManager.speedReal * this.stageDuration * tangentDir;

            // update virtual position and direction
            newState.pos = state.pos + Utilities.UnFlatten(delta_p);
            newState.dir = state.dir;

            // update the real world state according to the action
            if (a.type == ActionType.CURVATURE)
            {
                float s = delta_p.magnitude;
                //Debug.Log("s=" + s);
                float kr    = a.gain; // the curvature gain rou(c)
                float ori_0 = Vector2.SignedAngle(Vector2.right, Utilities.FlattenedDir2D(state.dirReal)) * Mathf.Deg2Rad;
                //Debug.Log("angle:"+ Vector2.SignedAngle(Vector2.right, Utilities.FlattenedDir2D(state.dirReal))+" ori_0:" + ori_0);
                // The new real position depends on user's real orientation
                newState.posReal.x = (Mathf.Sin(ori_0 + kr * s) - Mathf.Sin(ori_0)) / kr + state.posReal.x;
                newState.posReal.z = (Mathf.Cos(ori_0) - Mathf.Cos(ori_0 + kr * s)) / kr + state.posReal.z;
                newState.dirReal   = Utilities.UnFlatten(Utilities.RotateVector(Utilities.FlattenedDir2D(state.dirReal), s * kr * Mathf.Rad2Deg));
                //Debug.Log("ppp " + newState.posReal);
                //Debug.Log("ddd " + newState.dirReal);
            }
            else if (a.type == ActionType.ZERO)
            {
                newState.posReal = state.posReal + state.dirReal * this.redirectionManager.speedReal * this.stageDuration;
                newState.dirReal = state.dirReal;
            }
            else if (a.type == ActionType.RESET)
            {
                newState.posReal = state.posReal - state.dirReal * this.redirectionManager.speedReal * this.stageDuration;
                newState.dirReal = -state.dirReal;
            }
        }
        else if (seg is ArcSegment)
        {
            ArcSegment segment = (ArcSegment)seg;

            // update virtual position and direction
            float s      = this.redirectionManager.speedReal * this.stageDuration;
            float ori_v0 = Vector2.SignedAngle(Vector2.right, Utilities.FlattenedDir2D(state.dir)) * Mathf.Deg2Rad;
            newState.pos.x = (Mathf.Sin(ori_v0 + s / segment.radius) - Mathf.Sin(ori_v0)) * segment.radius + state.pos.x;
            newState.pos.z = (Mathf.Cos(ori_v0) - Mathf.Cos(ori_v0 + s / segment.radius)) / segment.radius + state.pos.z;
            newState.dir   = Utilities.UnFlatten(Utilities.RotateVector(state.dir, s / segment.radius));

            // update the real world state according to the action
            float ori_r0 = Vector2.SignedAngle(Vector2.right, Utilities.FlattenedDir2D(state.dirReal)) * Mathf.Deg2Rad;

            if (a.type == ActionType.CURVATURE)
            {
                float kr = 1 / segment.radius + a.gain; // the compound curvature gain 1/r + rou(c)
                // The new real position depends on user's real orientation
                newState.posReal.x = (Mathf.Sin(ori_r0 + kr * s) - Mathf.Sin(ori_r0)) / kr + state.posReal.x;
                newState.posReal.z = (Mathf.Cos(ori_r0) - Mathf.Cos(ori_r0 + kr * s)) / kr + state.posReal.z;
                newState.dirReal   = Utilities.UnFlatten(Utilities.RotateVector(state.dirReal, s * kr));
            }
            else if (a.type == ActionType.ZERO)
            {
                newState.posReal.x = (Mathf.Sin(ori_r0 + s / segment.radius) - Mathf.Sin(ori_r0)) * segment.radius + state.posReal.x;
                newState.posReal.z = (Mathf.Cos(ori_r0) - Mathf.Cos(ori_r0 + s / segment.radius)) / segment.radius + state.posReal.z;
                newState.dirReal   = Utilities.UnFlatten(Utilities.RotateVector(state.dirReal, s / segment.radius));
            }
            else if (a.type == ActionType.RESET)
            {
                ori_r0             = Vector2.SignedAngle(Vector2.right, Utilities.FlattenedDir2D(-state.dirReal)) * Mathf.Deg2Rad;
                newState.posReal.x = (Mathf.Sin(ori_r0 + s / segment.radius) - Mathf.Sin(ori_r0)) * segment.radius + state.posReal.x;
                newState.posReal.z = (Mathf.Cos(ori_r0) - Mathf.Cos(ori_r0 + s / segment.radius)) / segment.radius + state.posReal.z;
                newState.dirReal   = Utilities.UnFlatten(Utilities.RotateVector(-state.dirReal, s / segment.radius));
            }
        }
        else if (seg is RotationSegment)
        {
            RotationSegment segment = (RotationSegment)seg;

            // update virtual position and direction
            newState.pos = state.pos;
            float rotatedAngle = this.redirectionManager.angularSpeedReal * this.stageDuration * Mathf.Sign(segment.angle);
            newState.dir = Utilities.RotateVector(state.dir, rotatedAngle);

            if (a.type == ActionType.ROTATION)
            {
                newState.posReal = state.posReal;
                rotatedAngle     = rotatedAngle * a.gain;
                newState.dirReal = Utilities.RotateVector(state.dirReal, rotatedAngle);
            }
            else if (a.type == ActionType.ZERO)
            {
                newState.posReal = state.posReal;
                newState.dirReal = Utilities.RotateVector(state.dirReal, rotatedAngle);
            }
        }

        return(newState);
    }