Пример #1
0
        /// <summary>
        /// takes current state/pose, new sensors data, odometry and everything else - and evaluates new state and pose
        /// </summary>
        /// <param name="behaviorData"></param>
        public void EvaluatePoseAndState(IBehaviorData behaviorData, IDrive driveController)
        {
            // consider compass or AHRS reading for determining direction:
            if(behaviorData.sensorsData.CompassHeadingDegrees != null)
            {
                behaviorData.robotPose.direction.heading = behaviorData.sensorsData.CompassHeadingDegrees;
            }

            // use GPS data to update position:
            if (behaviorData.sensorsData.GpsFixType != GpsFixTypes.None)
            {
                behaviorData.robotPose.geoPosition.Lat = behaviorData.sensorsData.GpsLatitude;
                behaviorData.robotPose.geoPosition.Lng = behaviorData.sensorsData.GpsLongitude;
            }

            // utilize odometry data: 
            if (driveController.hardwareBrickOdometry != null)
            {
                // already calculated odometry comes from the hardware brick (i.e. Arduino)

                IOdometry odom = driveController.hardwareBrickOdometry;

                behaviorData.robotPose.XMeters = odom.XMeters;
                behaviorData.robotPose.YMeters = odom.YMeters;
                behaviorData.robotPose.ThetaRadians = odom.ThetaRadians;
            }
            else
            {
                // we have wheels encoders data and must calculate odometry here:
                long[] encoderTicks = new long[] { behaviorData.sensorsData.WheelEncoderLeftTicks, behaviorData.sensorsData.WheelEncoderRightTicks };

                driveController.OdometryCompute(behaviorData.robotPose, encoderTicks);
            }
        }
Пример #2
0
        /// <summary>
        /// called often, must return promptly. It is a thread safe function.
        /// </summary>
        public override void Process()
        {
            StartedLoop();

            // every cycle we create new behaviorData, populating it with existing data objects:
            IBehaviorData behaviorData = new BehaviorData()
            {
                sensorsData = this.currentSensorsData,
                robotState  = this.robotState,
                robotPose   = this.robotPose
            };

            // use sensor data to update robotPose:
            robotSlam.EvaluatePoseAndState(behaviorData, driveController);

            // populate all behaviors with current behaviorData:
            foreach (ISubsumptionTask task in subsumptionTaskDispatcher.Tasks)
            {
                BehaviorBase behavior = task as BehaviorBase;

                if (behavior != null)
                {
                    behavior.behaviorData = behaviorData;
                }
            }

            subsumptionTaskDispatcher.Process();     // calls behaviors, which take sensor outputs, and may compute drive inputs

            // look at ActiveTasksCount - it is an indicator of behaviors completed or removed. Zero count means we may need new behaviors combo.
            MonitorDispatcherActivity();

            // when active behavior is waiting (yielding), no action items are computed.
            // otherwise driveInputs will be non-null:
            if (behaviorData.driveInputs != null)
            {
                //Debug.WriteLine("ShortyTheRobot: Process()   - have drive inputs V=" + behaviorData.driveInputs.velocity + "   Omega=" + behaviorData.driveInputs.omega);

                driveController.driveInputs = behaviorData.driveInputs;

                driveController.Drive();    // apply driveInputs to motors

                robotState.velocity = behaviorData.driveInputs.velocity;
                robotState.omega    = behaviorData.driveInputs.omega;
            }

            this.BehaviorData = behaviorData;   // for tracing

            sensorsController.Process();        // let sensorsController do maintenance

            EndingLoop();
        }
Пример #3
0
        /// <summary>
        /// takes current state/pose, new sensors data, odometry and everything else - and evaluates new state and pose
        /// </summary>
        /// <param name="behaviorData"></param>
        public void EvaluatePoseAndState(IBehaviorData behaviorData, IDrive driveController)
        {
            bool          wasHeadingSetByCompass = false;
            IDisplacement displacement           = null;

            // consider compass or AHRS reading for determining direction:
            //if (!useOdometryHeading && behaviorData.sensorsData.CompassHeadingDegrees != null)
            //{
            //    behaviorData.robotPose.direction.heading = behaviorData.sensorsData.CompassHeadingDegrees;
            //    wasHeadingSetByCompass = true;
            //}

            // use GPS data to update position:
            if (behaviorData.sensorsData.GpsFixType != GpsFixTypes.None)
            {
                // we need to know displacement in meters:
                displacement = new GeoPosition(behaviorData.sensorsData.GpsLongitude, behaviorData.sensorsData.GpsLatitude) - behaviorData.robotPose.geoPosition;

                behaviorData.robotPose.geoPosition.Lat = behaviorData.sensorsData.GpsLatitude;
                behaviorData.robotPose.geoPosition.Lng = behaviorData.sensorsData.GpsLongitude;
            }
            else
            {
                // utilize odometry data
                // we might have wheels encoders data - it will be ignored if using hardwareBrickOdometry:
                long[] encoderTicks = new long[] { behaviorData.sensorsData.WheelEncoderLeftTicks, behaviorData.sensorsData.WheelEncoderRightTicks };

                // compute dXMeters  dYMeters  dThetaRadians:
                displacement = driveController.OdometryCompute(behaviorData.robotPose, encoderTicks);
            }

            if (displacement != null)
            {
                // update robotPose: XMeters  YMeters, Lat, Lng,  ThetaRadians, heading:
                behaviorData.robotPose.translate(displacement.dXMeters, displacement.dYMeters);
                behaviorData.robotPose.rotate(displacement.dThetaRadians);
            }

            if (!wasHeadingSetByCompass)
            {
                // rotate according to odometry:
                SetCurrentHeadingByTheta(behaviorData);
            }
        }
Пример #4
0
        private void SetCurrentHeadingByTheta(IBehaviorData behaviorData)
        {
            // XMeters and Lng axes are "horizontal right pointed". YMeters and Lat are "vertical up". North (0 degrees) is up.
            // Theta 0 is along the X axis, so we need a 90 degrees offset here.
            // Positive Theta is counterclockwise, positive heading - clockwise. That's why the minus sign.
            double currentHeading = DirectionMath.toDegrees(-behaviorData.robotPose.ThetaRadians + Math.PI / 2);

            if (behaviorData.robotPose.direction != null)
            {
                behaviorData.robotPose.direction.heading = currentHeading;
            }
            else
            {
                behaviorData.robotPose.direction = new Direction()
                {
                    heading = currentHeading,
                    bearing = behaviorData.robotPose.direction == null ? null : behaviorData.robotPose.direction.bearing
                };
            }
        }
Пример #5
0
 public HomeController(IStudentData studentData, IBehaviorData behaviorData)
 {
     _studentData  = studentData;
     _behaviorData = behaviorData;
 }
Пример #6
0
        /// <summary>
        /// determines if an obstacle is too close and comes up with an escape recommendation
        /// </summary>
        /// <param name="behaviorData"></param>
        /// <param name="escapeRecommendation">output</param>
        /// <returns></returns>
        protected override bool TooClose(IBehaviorData behaviorData)
        {
            escapeRecommendation = string.Empty;

            ISensorsData sensorsData = behaviorData.sensorsData;
            double velocity = behaviorData.driveInputs.velocity;    // behaviorData.driveInputs guaranteed not null

            double adjustedTresholdStopMeters = Math.Max(Math.Min(Math.Abs(tresholdStopMeters * velocity / 0.2d), 0.4d), 0.15d); // limit 0.15 ... 0.4 meters depending on velocity

            if (velocity > 0.0d && (sensorsData.IrFrontMeters <= tresholdIrStopMeters || sensorsData.RangerFrontLeftMeters <= adjustedTresholdStopMeters || sensorsData.RangerFrontRightMeters <= adjustedTresholdStopMeters))
            {
                bool leftSideFree = sensorsData.RangerFrontLeftMeters > adjustedTresholdStopMeters && sensorsData.IrLeftMeters > adjustedTresholdStopMeters;      // IR left and right - 10..80 cm
                bool rightSideFree = sensorsData.RangerFrontRightMeters > adjustedTresholdStopMeters && sensorsData.IrRightMeters > adjustedTresholdStopMeters;

                if (!leftSideFree)
                {
                    escapeRecommendation = "EscapeRight";
                }
                else if (!rightSideFree)
                {
                    escapeRecommendation = "EscapeLeft";
                }
                else
                {
                    escapeRecommendation = "Escape";    // advise random turn
                }

                return true;    // activate stop, with escape recommendation
            }

            if (velocity < 0.0d && (sensorsData.IrRearMeters < adjustedTresholdStopMeters))
            {
                escapeRecommendation = "EscapeForward";
                return true;    // activate stop, with escape recommendation
            }

            //if (velocity == 0.0d && behaviorData.driveInputs.omega == 0.0d)
            //{
            //    bool leftSideFree = sensorsData.IrLeftMeters > adjustedTresholdStopMeters;
            //    bool rightSideFree = sensorsData.IrRightMeters > adjustedTresholdStopMeters;
            //    bool rearFree = sensorsData.IrRearMeters > adjustedTresholdStopMeters;

            //    if (leftSideFree)
            //    {
            //        escapeRecommendation = "EscapeLeftTurn";
            //    }
            //    else if (rightSideFree)
            //    {
            //        escapeRecommendation = "EscapeRightTurn";
            //    }
            //    else if (rearFree)
            //    {
            //        escapeRecommendation = "EscapeFullTurn";
            //    }
            //    else
            //    {
            //        escapeRecommendation = "EscapeNone";
            //    }

            //    return true;    // activate stop, with escape recommendation
            //}

            return false;    // deactivate, no stopping and no escape recommendation
        }
Пример #7
0
 /// <summary>
 /// determines if an obstacle is too close and comes up with an escape recommendation
 /// </summary>
 /// <param name="behaviorData"></param>
 /// <returns></returns>
 protected abstract bool TooClose(IBehaviorData behaviorData);
Пример #8
0
        /// <summary>
        /// determines if an obstacle is too close and comes up with an escape recommendation
        /// </summary>
        /// <param name="behaviorData"></param>
        /// <param name="escapeRecommendation">output</param>
        /// <returns></returns>
        protected override bool TooClose(IBehaviorData behaviorData)
        {
            escapeRecommendation = string.Empty;

            ISensorsData sensorsData = behaviorData.sensorsData;
            double       velocity    = behaviorData.driveInputs.velocity;                                                        // behaviorData.driveInputs guaranteed not null

            double adjustedTresholdStopMeters = Math.Max(Math.Min(Math.Abs(tresholdStopMeters * velocity / 0.2d), 0.4d), 0.15d); // limit 0.15 ... 0.4 meters depending on velocity

            if (velocity > 0.0d && (sensorsData.IrFrontMeters <= tresholdIrStopMeters || sensorsData.RangerFrontLeftMeters <= adjustedTresholdStopMeters || sensorsData.RangerFrontRightMeters <= adjustedTresholdStopMeters))
            {
                bool leftSideFree  = sensorsData.RangerFrontLeftMeters > adjustedTresholdStopMeters && sensorsData.IrLeftMeters > adjustedTresholdStopMeters;     // IR left and right - 10..80 cm
                bool rightSideFree = sensorsData.RangerFrontRightMeters > adjustedTresholdStopMeters && sensorsData.IrRightMeters > adjustedTresholdStopMeters;

                if (!leftSideFree)
                {
                    escapeRecommendation = "EscapeRight";
                }
                else if (!rightSideFree)
                {
                    escapeRecommendation = "EscapeLeft";
                }
                else
                {
                    escapeRecommendation = "Escape";    // advise random turn
                }

                return(true);    // activate stop, with escape recommendation
            }

            if (velocity < 0.0d && (sensorsData.IrRearMeters < adjustedTresholdStopMeters))
            {
                escapeRecommendation = "EscapeForward";
                return(true);    // activate stop, with escape recommendation
            }

            //if (velocity == 0.0d && behaviorData.driveInputs.omega == 0.0d)
            //{
            //    bool leftSideFree = sensorsData.IrLeftMeters > adjustedTresholdStopMeters;
            //    bool rightSideFree = sensorsData.IrRightMeters > adjustedTresholdStopMeters;
            //    bool rearFree = sensorsData.IrRearMeters > adjustedTresholdStopMeters;

            //    if (leftSideFree)
            //    {
            //        escapeRecommendation = "EscapeLeftTurn";
            //    }
            //    else if (rightSideFree)
            //    {
            //        escapeRecommendation = "EscapeRightTurn";
            //    }
            //    else if (rearFree)
            //    {
            //        escapeRecommendation = "EscapeFullTurn";
            //    }
            //    else
            //    {
            //        escapeRecommendation = "EscapeNone";
            //    }

            //    return true;    // activate stop, with escape recommendation
            //}

            return(false);    // deactivate, no stopping and no escape recommendation
        }
Пример #9
0
        /// <summary>
        /// called often, must return promptly. It is a thread safe function.
        /// </summary>
        public override void Process()
        {
            StartedLoop();

            // every cycle we create new behaviorData, populating it with existing data objects:
            IBehaviorData behaviorData = new BehaviorData()
            {
                sensorsData = this.currentSensorsData,
                robotState = this.robotState,
                robotPose = this.robotPose
            };

            // use sensor data to update robotPose:
            robotSlam.EvaluatePoseAndState(behaviorData, driveController);

            // populate all behaviors with current behaviorData:
            foreach (ISubsumptionTask task in subsumptionTaskDispatcher.Tasks)
            {
                BehaviorBase behavior = task as BehaviorBase;

                if (behavior != null)
                {
                    behavior.behaviorData = behaviorData;
                }
            }

            subsumptionTaskDispatcher.Process();     // calls behaviors, which take sensor outputs, and may compute drive inputs

            // look at ActiveTasksCount - it is an indicator of behaviors completed or removed. Zero count means we may need new behaviors combo.
            MonitorDispatcherActivity();

            // when active behavior is waiting (yielding), no action items are computed.
            // otherwise driveInputs will be non-null:
            if (behaviorData.driveInputs != null)
            {
                //Debug.WriteLine("ShortyTheRobot: Process()   - have drive inputs V=" + behaviorData.driveInputs.velocity + "   Omega=" + behaviorData.driveInputs.omega);

                driveController.driveInputs = behaviorData.driveInputs;

                driveController.Drive();    // apply driveInputs to motors

                robotState.velocity = behaviorData.driveInputs.velocity;
                robotState.omega = behaviorData.driveInputs.omega;
            }

            this.BehaviorData = behaviorData;   // for tracing

            sensorsController.Process();        // let sensorsController do maintenance

            EndingLoop();
        }
Пример #10
0
 /// <summary>
 /// determines if an obstacle is too close and comes up with an escape recommendation
 /// </summary>
 /// <param name="behaviorData"></param>
 /// <returns></returns>
 protected abstract bool TooClose(IBehaviorData behaviorData);