示例#1
0
 /// <summary>
 /// Handles the reset notification of the Laser partner.
 /// </summary>
 /// <remarks>Posts a <typeparamref name="LaserRangeFinderResetUpdate"/> to itself.</remarks>
 /// <param name="reset">notification</param>
 void LaserResetNotification(sicklrf.Reset reset)
 {
     _mainPort.Post(new LaserRangeFinderResetUpdate(reset.Body));
 }
示例#2
0
// TT Nov-2006 - Changed for new CTP
//        public void ReplaceLaserData(sicklrf.StateType stateType)
        public void ReplaceLaserData(sicklrf.State stateType)
        {
            if (stateType.TimeStamp < _lastLaser)
            {
                return;
            }
            _lastLaser = stateType.TimeStamp;
            TimeSpan delay = DateTime.Now - stateType.TimeStamp;
            lblDelay.Text = delay.ToString();

            // TT - Changes supplied by Ben Axelrod to highlight
            // any objects immediately in front of the robot made
            // the following code redundant
            /*
            for (int x = 0; x < stateType.DistanceMeasurements.Length; x++)
            {
                int range = stateType.DistanceMeasurements[x];
                if (range > 0 && range < 8192)
                {
                    int h = bmp.Height * 500 / stateType.DistanceMeasurements[x];
                    if (h < 0)
                    {
                        h = 0;
                    }
                    Color col = LinearColor(Color.DarkBlue, Color.LightGray, 0, 8192, range);
                    g.DrawLine(new Pen(col), bmp.Width - x, half - h, bmp.Width - x, half + h);
                }
            }
            */

            // TT - May-2007
            // Added an option to display a map instead of 3D view
            if (options.DisplayMap)
            {
                // Display a top-down map using the colour convention
                // for an occupancy grid
                picLRF.Image = DrawMap(stateType);
            }
            else
            {
                // Display the simulated 3D view
                picLRF.Image = Draw3DView(stateType);
            }

            if (btnConnectLRF.Enabled)
            {
                btnConnectLRF.Enabled = false;
            }
            if (!btnDisconnect.Enabled)
            {
                btnDisconnect.Enabled = true;
            }
        }
示例#3
0
        /// <summary>
        /// Handles Replace notifications from the Laser partner
        /// </summary>
        /// <remarks>Posts a <typeparamref name="LaserRangeFinderUpdate"/> to itself.</remarks>
        /// <param name="replace">notification</param>
        /// <returns>task enumerator</returns>
        IEnumerator<ITask> LaserReplaceNotification(sicklrf.Replace replace)
        {
            // When this handler is called a couple of notifications may
            // have piled up. We only want the most recent one.
            sicklrf.State laserData = GetMostRecentLaserNotification(replace.Body);

            LaserRangeFinderUpdate request = new LaserRangeFinderUpdate(laserData);

            _mainPort.Post(request);

            yield return Arbiter.Choice(
                request.ResponsePort,
                delegate(DefaultUpdateResponseType response) { },
                delegate(Fault fault) { }
            );

            // Skip messages that have been queued up in the meantime.
            // The notification that are lingering are out of data by now.
            GetMostRecentLaserNotification(laserData);

            // Reactivate the handler.
            Activate(
                Arbiter.ReceiveWithIterator<sicklrf.Replace>(false, _laserNotify, LaserReplaceNotification)
            );
        }
        public void ReplaceHandler(sicklrf.Replace replace)
        {
            Tracer.Trace("TrackRoamerUsrfService::ReplaceHandler()");

            _state = replace.Body;
            replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
        }
        // ====================================================================================
        // as generated:
        //[ServiceHandler]
        //public void SubscribeHandler(sicklrf.Subscribe subscribe)
        //{
        //    throw new NotImplementedException();
        //}
        /// <summary>
        /// Handles Subscribe requests
        /// </summary>
        /// <param name="subscribe">request message</param>
        IEnumerator<ITask> SubscribeHandler(sicklrf.Subscribe subscribe)
        {
            Tracer.Trace("TrackRoamerUsrfService::SubscribeHandler()");

            yield return Arbiter.Choice(
                SubscribeHelper(_submgrPort, subscribe.Body, subscribe.ResponsePort),
                delegate(SuccessResult success)
                {
                    if (_state != null &&
                        _state.DistanceMeasurements != null)
                    {
                        _submgrPort.Post(new submgr.Submit(
                            subscribe.Body.Subscriber, DsspActions.ReplaceRequest, _state, null));
                    }
                },
                null
            );
        }
示例#6
0
        /// <summary>
        /// Transitions to "Mapping" meta state or "AdjustHeading" state depending on
        /// environment.
        /// </summary>
        /// <param name="laserData">most recently sensed laser range data</param>
        /// <param name="distance">closest obstacle in corridor ahead</param>
        private void StartMapping(sicklrf.State laserData, int distance)
        {
            StopMoving();

            if (distance < ObstacleDistance)
            {
                if (_state.Mapped)
                {
                    // We have been mapping before but do not seem to
                    // have found anything.
                    _state.LogicalState = LogicalState.RandomTurn;
                }
                else
                {
                    _state.LogicalState = LogicalState.MapSurroundings;
                }
            }
            else
            {
                int step = Math.Min(ObstacleDistance, distance - CorridorWidthMapping);
                // find the best angle from step mm in front of
                // our current position
                _state.NewHeading = FindBestFrom(laserData, 0, step, CorridorWidthMapping);

                LogInfo("Step: " + step + " Turn: " + _state.NewHeading);
                Translate(step);

                _state.LogicalState = LogicalState.AdjustHeading;
                _state.Countdown = step / 50 + Math.Abs(_state.NewHeading / 10);
            }
        }
        protected void GenerateTop(sicklrf.State laserData, int fieldOfView, RoutePlan plan)
        {
            //lock (lockStatusGraphics)
            //{

            if (currentStatusGraphics != null)
            {
                bool haveLaser = laserData != null && laserData.DistanceMeasurements != null && (DateTime.Now - _laserData.TimeStamp).TotalSeconds < 2.0d;

                //Bitmap bmp = (_state.MovingState == MovingState.MapSouth) ? currentStatusGraphics.statusBmp : currentStatusGraphics.northBmp;
                //Bitmap bmp = currentStatusGraphics.statusBmp;
                Bitmap bmp = currentStatusGraphics.northBmp;

                lock (bmp)
                {
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        g.Clear(Color.LightGray);

                        List<Lbl> labels = new List<Lbl>();

                        if (haveLaser)
                        {
                            double angularOffset = -90 + laserData.AngularRange / 2.0;
                            double piBy180 = Math.PI / 180.0;
                            double halfAngle = laserData.AngularResolution / 2.0;
                            double drangeMax = 0.0d;

                            GraphicsPath path = new GraphicsPath();

                            // make two passes, drawing laser data and label every 20th range:
                            for (int pass = 1; pass <= 2; pass++)
                            {
                                for (int i = 0; i < laserData.DistanceMeasurements.Length; i++)
                                {
                                    int range = laserData.DistanceMeasurements[i];
                                    if (range > 0 && range < 8192)
                                    {
                                        double angle = i * laserData.AngularResolution - angularOffset;
                                        double lowAngle = (angle - halfAngle) * piBy180;
                                        double highAngle = (angle + halfAngle) * piBy180;

                                        double drange = range * StatusGraphics.scale;

                                        float lx = (float)(StatusGraphics.xCenter + drange * Math.Cos(lowAngle));
                                        float ly = (float)(StatusGraphics.xCenter - drange * Math.Sin(lowAngle));
                                        float hx = (float)(StatusGraphics.xCenter + drange * Math.Cos(highAngle));
                                        float hy = (float)(StatusGraphics.xCenter - drange * Math.Sin(highAngle));

                                        if (pass == 1)
                                        {
                                            // on the first pass just add lines to the Path and calculate the max range:
                                            if (i == 0)
                                            {
                                                path.AddLine(StatusGraphics.xCenter, StatusGraphics.imageHeight, lx, ly);
                                            }
                                            path.AddLine(lx, ly, hx, hy);

                                            drangeMax = Math.Max(drangeMax, drange);
                                        }
                                        else
                                        {
                                            // on the second pass draw the perimeter and label every 20th range:
                                            g.DrawLine(Pens.DarkBlue, lx, ly, hx, hy);

                                            if (i > 0 && i % 20 == 0 && i < laserData.DistanceMeasurements.Length - 10)
                                            {
                                                float llx = (float)(StatusGraphics.xCenter + drangeMax * 1.3f * Math.Cos(lowAngle));
                                                float lly = (float)(StatusGraphics.xCenter - drangeMax * 1.3f * Math.Sin(lowAngle));
                                                double roundRange = Math.Round(range / 1000.0d, 1); // meters
                                                string str = "" + roundRange;
                                                labels.Add(new Lbl() { label = str, lx = llx, ly = lly, brush = Brushes.Black });
                                            }
                                        }
                                    }
                                }

                                if (pass == 1)
                                {
                                    // draw the laser sweep on the first pass:
                                    g.FillPath(Brushes.White, path);
                                }
                            }
                        }

                        // draw important decision-influencing boundaries:
                        float startAngle = -150.0f;
                        float sweepAngle = 120.0f;

                        // the "stop moving" distance:
                        float radius = (float)(ObstacleDistanceMm * StatusGraphics.scale);
                        //g.DrawRectangle(Pens.Red, xCenter - radius, imageHeight - radius, radius * 2, radius * 2);
                        g.DrawArc(Pens.Red, StatusGraphics.xCenter - radius, StatusGraphics.imageHeight - radius, radius * 2, radius * 2, startAngle, sweepAngle);
                        rayLabel("stop", labels, ObstacleDistanceMm, -60.0d, Brushes.Red);

                        // the "slow down" distance:
                        radius = (float)(AwareOfObstacleDistanceMm * StatusGraphics.scale);
                        g.DrawArc(Pens.Orange, StatusGraphics.xCenter - radius, StatusGraphics.imageHeight - radius, radius * 2, radius * 2, startAngle, sweepAngle);
                        rayLabel("slow", labels, AwareOfObstacleDistanceMm, -60.0d, Brushes.Orange);

                        // the "stop mapping, enter the open space" distance
                        radius = (float)(SafeDistanceMm * StatusGraphics.scale);
                        g.DrawArc(Pens.LightBlue, StatusGraphics.xCenter - radius, StatusGraphics.imageHeight - radius, radius * 2, radius * 2, startAngle, sweepAngle);
                        rayLabel("enter", labels, SafeDistanceMm, -60.0d, Brushes.LightBlue);

                        // the "max velocity" distance:
                        radius = (float)(FreeDistanceMm * StatusGraphics.scale);
                        g.DrawArc(Pens.Green, StatusGraphics.xCenter - radius, StatusGraphics.imageHeight - radius, radius * 2, radius * 2, startAngle, sweepAngle);
                        rayLabel("free", labels, FreeDistanceMm, -60.0d, Brushes.Green);

                        // the fieldOfView arc:
                        radius = (float)(StatusGraphics.imageHeight - 10);
                        g.DrawArc(Pens.LimeGreen, StatusGraphics.xCenter - radius, StatusGraphics.imageHeight - radius, radius * 2, radius * 2, (float)(-90-fieldOfView), (float)(fieldOfView*2));
                        rayLabel("field of view", labels, (StatusGraphics.imageHeight+5) / StatusGraphics.scale, 10.0d, Brushes.LimeGreen);

                        // now draw the robot. Trackroamer is 680 mm wide.
                        float botHalfWidth = (float)(680 / 2.0d * StatusGraphics.scale);
                        DrawHelper.drawRobotBoundaries(g, botHalfWidth, StatusGraphics.imageWidth / 2, StatusGraphics.imageHeight);

                        // debug- draw a ray pointing to predefined direction; left is positive, right is negative:
                        //double rayLength = 2000.0d;
                        //rayLine("20", g, rayLength, 20.0d, Pens.Cyan, Brushes.DarkCyan);
                        //rayLine("-20", g, rayLength, -20.0d, Pens.Blue, Brushes.Blue);
                        //rayLine("70", g, rayLength, 70.0d, Pens.Red, Brushes.Red);
                        //rayLine("-70", g, rayLength, -70.0d, Pens.Green, Brushes.Green);

                        // draw laser's time stamp:
                        if (haveLaser)
                        {
                            TimeSpan howOld = DateTime.Now - laserData.TimeStamp;
                            g.DrawString(laserData.TimeStamp.ToString() + " (" + howOld + ")", StatusGraphics.fontBmp, Brushes.Black, 0, 0);
                        }

                        HistoryItem latestDecisionsHistory = StatusGraphics.HistoryDecisions.Peek();
                        HistoryItem latestSaidHistory = Talker.HistorySaid.Peek();

                        if (latestSaidHistory != null)
                        {
                            g.DrawString(latestSaidHistory.message, StatusGraphics.fontBmpL, Brushes.Black, StatusGraphics.imageWidth / 2 + 80, StatusGraphics.imageHeight + StatusGraphics.extraHeight - 20);
                        }

                        if (latestDecisionsHistory != null)
                        {
                            g.DrawString(latestDecisionsHistory.message, StatusGraphics.fontBmpL, Brushes.Black, StatusGraphics.imageWidth / 2 + 80, StatusGraphics.imageHeight + StatusGraphics.extraHeight - 40);
                        }

                        g.DrawString(_state.MovingState.ToString(), StatusGraphics.fontBmpL, Brushes.Black, StatusGraphics.imageWidth / 2 - 40, StatusGraphics.imageHeight + StatusGraphics.extraHeight - 20);

                        // draw distance labels over all other graphics:
                        foreach (Lbl lbl in labels)
                        {
                            g.DrawString(lbl.label, StatusGraphics.fontBmp, lbl.brush, lbl.lx, lbl.ly + 20);
                        }

                        // a 200W x 400H rectangle:
                        Rectangle drawRect = new Rectangle(StatusGraphics.imageWidth / 2 - StatusGraphics.extraHeight, StatusGraphics.imageHeight - StatusGraphics.extraHeight * 2, StatusGraphics.extraHeight * 2, StatusGraphics.extraHeight * 4);

                        if (_state.MostRecentProximity != null)
                        {
                            // the MostRecentProximity class here comes from the proxy, and does not have arrangedForDrawing member. Restore it:

                            double[] arrangedForDrawing = new double[8];

                            arrangedForDrawing[0] = _state.MostRecentProximity.mbr;
                            arrangedForDrawing[1] = _state.MostRecentProximity.mbbr;
                            arrangedForDrawing[2] = _state.MostRecentProximity.mbbl;
                            arrangedForDrawing[3] = _state.MostRecentProximity.mbl;

                            arrangedForDrawing[4] = _state.MostRecentProximity.mfr;
                            arrangedForDrawing[5] = _state.MostRecentProximity.mffr;
                            arrangedForDrawing[6] = _state.MostRecentProximity.mffl;
                            arrangedForDrawing[7] = _state.MostRecentProximity.mfl;

                            // draw a 200x400 image of IR proximity sensors:

                            DrawHelper.drawProximityVectors(g, drawRect, arrangedForDrawing, 1);
                        }

                        if (_state.MostRecentParkingSensor != null)
                        {
                            // the MostRecentParkingSensor class here comes from the proxy, and does not have arrangedForDrawing member. Restore it:

                            double[] arrangedForDrawing = new double[4];

                            arrangedForDrawing[0] = _state.MostRecentParkingSensor.parkingSensorMetersRB;
                            arrangedForDrawing[1] = _state.MostRecentParkingSensor.parkingSensorMetersLB;
                            arrangedForDrawing[2] = _state.MostRecentParkingSensor.parkingSensorMetersLF;
                            arrangedForDrawing[3] = _state.MostRecentParkingSensor.parkingSensorMetersRF;

                            // draw a 200x400 image of parking sensors:

                            DrawHelper.drawProximityVectors(g, drawRect, arrangedForDrawing, 2);
                        }

                        if (plan != null && plan.isGoodPlan)
                        {
                            // right turn - positive, left turn - negative, expressed in degrees:
                            int bestHeadingInt = (int)Math.Round((double)plan.bestHeadingRelative(_mapperVicinity));
                            double bestHeadingDistance = plan.legMeters.Value * 1000.0d;

                            using (Pen dirPen = new Pen(Color.Green, 5.0f))
                            {
                                dirPen.EndCap = LineCap.ArrowAnchor;
                                rayLine("best:" + bestHeadingInt, g, bestHeadingDistance * 1.1d, (double)bestHeadingInt, dirPen, Brushes.Green);
                            }

                            //int xLbl = 10;
                            //int yLbl = bmp.Height - 40;

                            //g.DrawString(comment, StatusGraphics.fontBmpL, Brushes.Green, xLbl, yLbl);
                        }

                        if(_mapperVicinity.robotDirection.bearingRelative.HasValue)
                        {
                            int goalBearingInt = (int)Math.Round((double)_mapperVicinity.robotDirection.bearingRelative);
                            double goalDistance = 3000.0d;

                            using (Pen dirPen = new Pen(Color.LimeGreen, 2.0f))
                            {
                                dirPen.EndCap = LineCap.ArrowAnchor;
                                rayLine("goal:" + goalBearingInt, g, goalDistance, (double)goalBearingInt, dirPen, Brushes.LimeGreen);
                            }

                        }
                    }
                }
            }
        }
        /// <summary>
        /// Finds the best free corridor (maximum free space ahead) in a 360 degree scan.
        /// </summary>
        /// <param name="south">the backward half of the scan</param>
        /// <param name="north">the forward half of the scan</param>
        /// <returns>best heading in degrees (right turn - positive, left turn - negative)</returns>
        private int FindBestComposite(sicklrf.State south, sicklrf.State north)
        {
            try
            {
                // sanity check:
                LogInfo("FindBestComposite() south: " + south.DistanceMeasurements.Length + " points,  north: " + north.DistanceMeasurements.Length + " points");

                if (south.DistanceMeasurements.Length + north.DistanceMeasurements.Length < 360)
                {
                    LogError("FindBestComposite() - bad laser measurement");
                    return 0;
                }

                sicklrf.State composite = new sicklrf.State();

                composite.DistanceMeasurements = new int[361];

                for (int i = 0; i < composite.DistanceMeasurements.Length; i++)
                {
                    // the trick is to have halves of the South scan become sides of the full North scan,
                    // so that a 360 degrees composite has heading 0 in the middle.

                    if (i < 90)
                    {
                        composite.DistanceMeasurements[i] = south.DistanceMeasurements[i + 90];
                    }
                    else if (i < 270)
                    {
                        composite.DistanceMeasurements[i] = north.DistanceMeasurements[i - 90];
                    }
                    else // 270...359
                    {
                        composite.DistanceMeasurements[i] = south.DistanceMeasurements[i - 270];
                    }
                }

                composite.AngularResolution = 1.0;
                composite.AngularRange = 360;
                composite.Units = north.Units;

                return FindBestHeading(composite, 0, 0, CorridorWidthMoving, "Best Composite");
            }
            catch (Exception exc)
            {
                LogError(exc);
                return 0;
            }
        }
        protected void updateMapperWithLaserData(sicklrf.State laserData)
        {
            int numRays = laserData.DistanceMeasurements.Length;

            List<IDetectedObject> laserObjects = new List<IDetectedObject>(numRays / step + 5);

            for (int i = 0; i < laserData.DistanceMeasurements.Length; i += step)
            {
                double rangeMeters = laserData.DistanceMeasurements[i] / 1000.0d;  // DistanceMeasurements is in millimeters;

                if (rangeMeters > minReliableRangeMeters && rangeMeters < maxReliableRangeMeters)
                {
                    double relBearing = forwardAngle - i * 180.0d / numRays;

                    GeoPosition pos1 = (GeoPosition)_mapperVicinity.robotPosition.Clone();

                    pos1.translate(new Direction() { heading = _mapperVicinity.robotDirection.heading, bearingRelative = relBearing }, new Distance(rangeMeters));

                    DetectedObstacle dobst1 = new DetectedObstacle()
                    {
                        geoPosition = pos1,
                        firstSeen = laserData.TimeStamp.Ticks,
                        lastSeen = laserData.TimeStamp.Ticks,
                        detectorType = DetectorType.SONAR_SCANNING,
                        objectType = DetectedObjectType.Obstacle
                    };

                    dobst1.SetColorByType();

                    laserObjects.Add(dobst1);
                }
            }

            if (laserObjects.Count > 0)
            {
                int countBefore = 0;
                lock (_mapperVicinity)
                {
                    countBefore = _mapperVicinity.Count;
                    _mapperVicinity.AddRange(laserObjects);
                    _mapperVicinity.computeMapPositions();
                }
                //Tracer.Trace(string.Format("laser ready - added {0} to {1}", laserObjects.Count, countBefore));
            }
        }
示例#10
0
        protected void LaserHandler(sicklrf.Replace replace)
        {
            // Angular Range = r
            // Desired Angular Range = rd
            // Minimum Angle = amin = (r/2) - (rd/2)
            // Maximum Angle = amax = (r/2) + (rd/2)
            // Angular Resolution = e
            // Minimum measurement = mmin = floor(amin / e)
            // Maximum measurement = mmax = ceil(amax / e)
            // Assert e > 0
            // Assert rd > e
            // Total measurements = mtot
            // Assert mtot > 1 (or two)

            if (replace == null)
                return;

            sicklrf.State laserState = replace.Body;
            if (laserState == null)
                return;

            if (laserState.DistanceMeasurements == null)
                return;

            if (laserState.DistanceMeasurements.Length < 2)
                return;

            if (laserState.AngularResolution <= 0)
                return;

            if ((_halfObstacleAngleRange * 2) <= laserState.AngularResolution)
                return;

            // Note: this assumes laserState.AngularRange % 2 = 0
            int halfRange = laserState.AngularRange / 2;
            double amin = halfRange - _halfObstacleAngleRange;
            double amax = halfRange + _halfObstacleAngleRange;

            int mmin = (int)Math.Floor(amin / laserState.AngularResolution);
            int mmax = (int)Math.Ceiling(amax / laserState.AngularResolution);

            // TODO: check that MinimumObstacleRange is less than this
            int computedRange = 8000; // 8000 is around the maximum reported value from the sicklrf

            if (mmin == mmax)
            {
                computedRange = laserState.DistanceMeasurements[mmin];
            }
            else
            {
                for (int index = mmin; index <= mmax; ++index)
                {
                    computedRange = Math.Min(computedRange, laserState.DistanceMeasurements[index]);
                }
            }

            //Trace.WriteLine("samples: " + (mmax - mmin) + ", range: " + computedRange);

            if (computedRange <= _state.MinimumObstacleRange)
            {
                _soar.Obstacle = true;
            }
            else
            {
                _soar.Obstacle = false;
            }
        }
示例#11
0
        IEnumerator<ITask> OnLaserReplaceHandler(sicklrf.Replace replace)
        {
            if (_driveControl != null)
            {
                WinFormsServicePort.FormInvoke(
                    delegate()
                    {
                        _driveControl.ReplaceLaserData(replace.Body);
                    }
                );
            }

            LogObject(replace.Body);
            yield break;
        }
示例#12
0
        /// <summary>
        /// Adjusts the velocity based on environment.
        /// </summary>
        /// <param name="laserData">most recently sensed laser range data</param>
        /// <param name="distance">closest obstacle in corridor ahead</param>
        private void AdjustVelocity(sicklrf.State laserData, int distance)
        {
            _state.Mapped = false;
            // Why does AdjustVelocity call Turn() ???
            // This does not seem to make any sense, and the robot gets
            // stuck in oscillations to the left and right
            int test = FindBestFrom(laserData, 0, _state.Velocity / 10, CorridorWidthMoving);

            if (distance > FreeDistance)
            {
                MoveForward(MaximumForwardVelocity);

                //if (Math.Abs(test) < 10)
                if (Math.Abs(test) < 10)
                {
                    Turn(test / 2);
                    // TT Jun-2007 - Changed to slow down
                    _state.Countdown = Math.Abs((test / 2) / 5);
                }
            }
            else if (distance > AwareOfObstacleDistance)
            {
                MoveForward(MaximumForwardVelocity / 2);

                //if (Math.Abs(test) < 45)
                if (Math.Abs(test) < 45)
                {
                    Turn(test / 2);
                    // TT Jun-2007 - Changed
                    _state.Countdown = Math.Abs((test / 2) / 5);
                }
            }
            else
            {
                MoveForward(MaximumForwardVelocity / 4);

                if (Math.Abs(test) < 60)
                {
                    Turn(test);
                    // TT Jun-2007 - Changed
                    //_state.Countdown = Math.Abs(test / 10);
                    _state.Countdown = 5;
                }
            }
        }
示例#13
0
        /// <summary>
        /// Finds closest obstacle in a corridor.
        /// </summary>
        /// <param name="laserData">laser scan</param>
        /// <param name="width">corridor width</param>
        /// <param name="fov">field of view in degrees</param>
        /// <returns>distance to the closest obstacle</returns>
        private int FindNearestObstacleInCorridor(sicklrf.State laserData, int width, int fov)
        {
            int index;
            int best = 8192;
            // TT - There is a timing issue during startup whereby the
            // LRF actually does not supply any data! Just ignore it.
            if (laserData == null || laserData.DistanceMeasurements == null)
                return 0;
            int count = laserData.DistanceMeasurements.Length;
            double rangeLow = -laserData.AngularRange / 2.0;
            double rangeHigh = laserData.AngularRange / 2.0;
            double span = laserData.AngularRange;

            for (index = 0; index < count; index++)
            {
                double angle = rangeLow + (span * index) / count;
                if (Math.Abs(angle) < fov)
                {
                    angle = angle * Math.PI / 180;

                    int range = laserData.DistanceMeasurements[index];
                    // TT - The simulated LRF returns zero if there is
                    // no hit. It should return max range. I reported
                    // this and it should be fixed in V1.5.
                    if (range == 0)
                        range = 8192;
                    int x = (int)(range * Math.Sin(angle));
                    int y = (int)(range * Math.Cos(angle));

                    if (Math.Abs(x) < width)
                    {
                        if (range < best)
                        {
                            best = range;
                        }
                    }
                }
            }

            // TT - Log the value
            //LogInfo("Nearest Obstacle: " + best);
            return best;
        }
示例#14
0
        // TT May-2007 - Draw an occupancy grid style map using the LRF data
        private Bitmap DrawMap(sicklrf.State stateType)
        {
            double angle;
            int range;

            Bitmap bmp = new Bitmap(stateType.DistanceMeasurements.Length, LRFImageHeight);
            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.LightGray);

            // Loop invariants
            double startAngle = stateType.AngularRange / 2.0;
            // AngularResolution is zero! This is a bug that I have
            // reported and it should be fixed in V1.5. In the meantime,
            // calculate the value.
            double angleIncrement = (double)stateType.AngularRange / (double)stateType.DistanceMeasurements.Length;
            double rx, ry;
            int ix, iy;
//            Pen whitePen = new Pen(Color.White);
//            Pen blackPen = new Pen(Color.Black, 2);
//            blackPen.EndCap = LineCap.Round;

            // First draw the free space
            // Note that this code draws the free space using a series
            // of white "rays" from the LRF. The result is some small
            // "slivers" that are not filled in between the rays.
            // Some people fill in the whole area outlined by the
            // hit points on the assumption that if two rays are close
            // together then there is probably nothing in between.
            // Strictly speaking this is not correct because the LRF
            // tells you nothing about the spaces between rays.
            for (int x = 0; x < stateType.DistanceMeasurements.Length; x++)
            {
                range = stateType.DistanceMeasurements[x];
                // NOTE: Scans are backwards, i.e. right to left
                angle = (startAngle - x * angleIncrement) * Math.PI / 180;
                // The Simulated LRF returns zero if there is no hit
                // This is not the way that a real LRF works
                if (range <= 0)
                    range = (int) options.MaxLRFRange;
                rx = range * Math.Cos(angle);
                ry = range * Math.Sin(angle);
                ix = (int)(ry * LRFImageHeight / options.MaxLRFRange) + bmp.Width / 2;
                iy = bmp.Height - (int)(rx * LRFImageHeight / options.MaxLRFRange);
                // NOTE: This code relies on the fact that the DrawLine
                // method will clip at the edges of the bitmap!
                g.DrawLine(Pens.White, bmp.Width / 2, bmp.Height - 1, ix, iy);
            }

            // Now draw the obstacles at the points of the laser hits
            for (int x = 0; x < stateType.DistanceMeasurements.Length; x++)
            {
                range = stateType.DistanceMeasurements[x];
                // NOTE: Scans are backwards, i.e. right to left
                angle = (startAngle - x * angleIncrement) * Math.PI / 180;
                // The Simulated LRF returns zero if there is no hit
                // This is not the way that a real LRF works
                if (range <= 0)
                    range = (int)options.MaxLRFRange;
                rx = range * Math.Cos(angle);
                ry = range * Math.Sin(angle);
                ix = (int)(ry * LRFImageHeight / options.MaxLRFRange) + bmp.Width / 2;
                iy = bmp.Height - (int)(rx * LRFImageHeight / options.MaxLRFRange);
                if (range < options.MaxLRFRange)
                {
                    /*
                    // We need a small dot at the end of the laser ray
                    // However, drawing a point with DrawLine does not work!
                    // So make it a little longer
                    int ix2, iy2;
                    ix2 = ix;
                    if (ix2 > bmp.Width / 2)
                        ix2 = ix - 1;
                    if (ix2 < bmp.Width / 2)
                        ix2 = ix + 1;
                    iy2 = iy;
                    if (iy2 < bmp.Height / 2)
                        iy2 = iy + 1;
                    g.DrawLine(blackPen, ix, iy, ix2, iy2);
                    */

                    // Put a single pixel at the end of the ray
                    // This does not give a nice dark boundary like
                    // drawing a short line, but it is more correct
                    // because technically the laser only gives data
                    // at discrete angles and you can't say anything
                    // about the area in between rays
                    // NOTE: We have to check the bounds of the image
                    // for SetPixel -- it does not clip
                    if (ix >=0 && ix < bmp.Width &&
                        iy >=0 && iy < bmp.Height)
                        bmp.SetPixel(ix, iy, Color.Black);
                }
            }

            // Return the image
            return bmp;
        }
示例#15
0
        /// <summary>
        /// Implements the "Mapping" meta state.
        /// </summary>
        /// <param name="laserData">most recently sensed laser range data</param>
        /// <param name="distance">closest obstacle in corridor ahead</param>
        private void Map(sicklrf.State laserData, int distance)
        {
            switch (_state.LogicalState)
            {
                case LogicalState.RandomTurn:
                    RandomTurn();
                    break;
                case LogicalState.MapSurroundings:
                    _state.Mapped = true;
                    LogInfo("Turning 180 deg to map");
                    Turn(180);

                    _state.LogicalState = LogicalState.MapSouth;
                    _state.Countdown = 15;
                    break;
                case LogicalState.MapSouth:
                    LogInfo("Mapping the View South");
                    _state.South = laserData;
                    Turn(180);

                    _state.LogicalState = LogicalState.MapNorth;
                    _state.Countdown = 15;
                    break;
                case LogicalState.MapNorth:
                    LogInfo("Mapping the View North");
                    _state.NewHeading = FindBestComposite(_state.South, laserData);
                    LogInfo("Map suggest turn: " + _state.NewHeading);
                    _state.South = null;
                    _state.LogicalState = LogicalState.AdjustHeading;
                    break;
                default:
                    LogInfo("Explorer.Map() called in illegal state");
                    break;
            }
        }
示例#16
0
        /// <summary>
        /// Adjusts the velocity based on environment.
        /// </summary>
        /// <param name="laserData">most recently sensed laser range data</param>
        /// <param name="distance">closest obstacle in corridor ahead</param>
        private void AdjustVelocity(sicklrf.State laserData, int distance)
        {
            _state.Mapped = false;
            int test = FindBestFrom(laserData, 0, _state.Velocity / 10, CorridorWidthMoving);

            if (distance > FreeDistance)
            {
                MoveForward(MaximumForwardVelocity);

                if (Math.Abs(test) < 10)
                {
                    Turn(test / 2);
                }
            }
            else if (distance > AwareOfObstacleDistance)
            {
                MoveForward(MaximumForwardVelocity / 2);

                if (Math.Abs(test) < 45)
                {
                    Turn(test / 2);
                }
            }
            else
            {
                MoveForward(MaximumForwardVelocity / 4);

                Turn(test);
                _state.Countdown = Math.Abs(test / 10);
            }
        }
示例#17
0
 /// <summary>
 /// Implements the "Moving" meta state.
 /// </summary>
 /// <param name="laserData">most recently sensed laser range data</param>
 /// <param name="distance">closest obstacle in corridor ahead</param>
 private void Move(sicklrf.State laserData, int distance)
 {
     switch (_state.LogicalState)
     {
         case LogicalState.AdjustHeading:
             AdjustHeading();
             break;
         case LogicalState.FreeForwards:
             AdjustVelocity(laserData, distance);
             break;
         default:
             LogInfo("Explorer.Move() called in illegal state");
             break;
     }
 }
示例#18
0
        /// <summary>
        /// Finds the best free corridor (maximum free space ahead) in a 360 degree scan.
        /// </summary>
        /// <param name="south">the backward half of the scan</param>
        /// <param name="north">the forward half of the scan</param>
        /// <returns>beast heading in degrees</returns>
        private int FindBestComposite(sicklrf.State south, sicklrf.State north)
        {
            sicklrf.State composite = new sicklrf.State();

            composite.DistanceMeasurements = new int[720];

            for (int i = 0; i < 720; i++)
            {
                if (i < 180)
                {
                    composite.DistanceMeasurements[i] = south.DistanceMeasurements[i + 180];
                }
                else if (i < 540)
                {
                    composite.DistanceMeasurements[i] = north.DistanceMeasurements[i - 180];
                }
                else
                {
                    composite.DistanceMeasurements[i] = south.DistanceMeasurements[i - 540];
                }
            }

            composite.AngularResolution = 0.5;
            composite.AngularRange = 360;
            composite.Units = north.Units;

            return FindBestFrom(composite, 0, 0, CorridorWidthMoving);
        }
示例#19
0
 /// <summary>
 /// Transitions to the most appropriate state.
 /// </summary>
 /// <param name="laserData">most recently sensed laser range data</param>
 /// <param name="distance">closest obstacle in corridor ahead</param>
 private void UpdateLogicalState(sicklrf.State laserData, int distance)
 {
     if (doCountdown && _state.Countdown > 0)
     {
         _state.Countdown--;
     }
     else if (_state.IsUnknown)
     {
         StartMapping(laserData, distance);
     }
     else if (_state.IsMoving)
     {
         Move(laserData, distance);
     }
     else if (_state.IsMapping)
     {
         Map(laserData, distance);
     }
 }
示例#20
0
        /// <summary>
        /// Finds the best heading in a 180 degree laser scan
        /// </summary>
        /// <param name="laserData">laser scan</param>
        /// <param name="dx">horizontal offset</param>
        /// <param name="dy">vertical offset</param>
        /// <param name="width">width of corridor that must be free</param>
        /// <returns>best heading in degrees</returns>
        private int FindBestFrom(sicklrf.State laserData, int dx, int dy, int width)
        {
            int count = laserData.DistanceMeasurements.Length;
            double span = Math.PI * laserData.AngularRange / 180.0;

            List<RangeData> ranges = new List<RangeData>();

            for (int i = 0; i < count; i++)
            {
                int range = laserData.DistanceMeasurements[i];
                double angle = span * i / count - span / 2.0;

                double x = range * Math.Sin(angle) - dx;
                double y = range * Math.Cos(angle) - dy;

                angle = Math.Atan2(-x, y);
                range = (int)Math.Sqrt(x * x + y * y);

                ranges.Add(new RangeData(range, angle));
            }

            ranges.Sort(RangeData.ByDistance);

            for (int i = 0; i < ranges.Count; i++)
            {
                RangeData curr = ranges[i];

                double delta = Math.Atan2(width, curr.Distance);
                double low = curr.Heading - delta;
                double high = curr.Heading + delta;

                for (int j = i + 1; j < ranges.Count; j++)
                {
                    if (ranges[j].Heading > low &&
                        ranges[j].Heading < high)
                    {
                        ranges.RemoveAt(j);
                        j--;
                    }

                }
            }

            ranges.Reverse();

            int bestDistance = ranges[0].Distance;
            double bestHeading = ranges[0].Heading;
            Random rand = new Random();

            for (int i = 0; i < ranges.Count; i++)
            {
                if (ranges[i].Distance < bestDistance)
                {
                    break;
                }
                if (rand.Next(i + 1) == 0)
                {
                    bestHeading = ranges[i].Heading;
                }
            }

            return -(int)Math.Round(180 * bestHeading / Math.PI);
        }
        /// <summary>
        /// Copies 'distanceMeasurements' paramater to Bitmap contained in the _lrfPanel
        /// </summary>
        /// <param name="distanceMeasurements"></param>
        /// <param name="units"></param>
        internal void SetLRFData(int[] distanceMeasurements, sicklrf.Units units)
        {
            if (_lrfPanel == null || distanceMeasurements == null)
                return;

            double lrfMax = 0;
            int maxIndex = distanceMeasurements.Length - 1;
            float scalingFactor = maxIndex / (float)(_lrfPanel.Width - 1);

            byte[] bmpData = new byte[4 * _lrfPanel.Width * _lrfPanel.Height];
            for (int y = 0; y < _lrfPanel.Height; y++)
            {
                for (int x = 0; x < _lrfPanel.Width; x++)
                {
                    int i = 4 * (y * _lrfPanel.Width + x);
                    int originalDistance = distanceMeasurements[maxIndex - (int)(x * scalingFactor)];
                    lrfMax = Math.Max(originalDistance, lrfMax);

                    double distance = (255.0 / _previousLrfMax) * originalDistance;
                    bmpData[i] = ClampToByte(distance);
                }
            }
            _previousLrfMax = Math.Max(lrfMax, double.Epsilon);
            lrflog.Add(_previousLrfMax);
            Bitmap bmp = LRFBitmap;
            ImageProcessingResultService.CopyBytesToBitmap(bmpData, _lrfPanel.Width, _lrfPanel.Height, ref bmp);
            if (bmp != LRFBitmap)
            {
                LRFBitmap = bmp;
                _lrfPanel.Image = LRFBitmap;
            }
        }
示例#22
0
        /// <summary>
        /// Finds closest obstacle in a corridor.
        /// </summary>
        /// <param name="laserData">laser scan</param>
        /// <param name="width">corridor width</param>
        /// <param name="fov">field of view in degrees</param>
        /// <returns>distance to the closest obstacle</returns>
        private int FindNearestObstacleInCorridor(sicklrf.State laserData, int width, int fov)
        {
            int index;
            int best = 8192;
            int count = laserData.DistanceMeasurements.Length;
            double rangeLow = -laserData.AngularRange / 2.0;
            double rangeHigh = laserData.AngularRange / 2.0;
            double span = laserData.AngularRange;

            for (index = 0; index < count; index++)
            {
                double angle = rangeLow + (span * index) / count;
                if (Math.Abs(angle) < fov)
                {
                    angle = angle * Math.PI / 180;

                    int range = laserData.DistanceMeasurements[index];
                    int x = (int)(range * Math.Sin(angle));
                    int y = (int)(range * Math.Cos(angle));

                    if (Math.Abs(x) < width)
                    {
                        if (range < best)
                        {
                            best = range;
                        }
                    }
                }
            }

            return best;
        }
示例#23
0
        public void ResetHandler(sicklrf.Reset reset)
        {
            Tracer.Trace("TrackRoamerUsrfService::ResetHandler()");

            // TBD: send reset request to the board partner

            reset.ResponsePort.Post(DefaultSubmitResponseType.Instance);
        }
示例#24
0
        /// <summary>
        /// Gets the most recent laser notification. Older notifications are dropped.
        /// </summary>
        /// <param name="laserData">last known laser data</param>
        /// <returns>most recent laser data</returns>
        private sicklrf.State GetMostRecentLaserNotification(sicklrf.State laserData)
        {
            sicklrf.Replace testReplace;

            // _laserNotify is a PortSet<>, P3 represents IPort<sicklrf.Replace> that
            // the portset contains
            int count = _laserNotify.P3.ItemCount - 1;

            for (int i = 0; i < count; i++)
            {
                testReplace = _laserNotify.Test<sicklrf.Replace>();
                if (testReplace.Body.TimeStamp > laserData.TimeStamp)
                {
                    laserData = testReplace.Body;
                }
            }

            if (count > 0)
            {
                LogInfo(string.Format("Dropped {0} laser readings (laser start)", count));
            }
            return laserData;
        }
示例#25
0
        public void GetHandler(sicklrf.Get get)
        {
            Tracer.Trace("TrackRoamerUsrfService::GetHandler()");

            get.ResponsePort.Post(_state);
        }
示例#26
0
        // TT - Draw the pseudo 3D view including Ben's code to show
        // the width of the robot
        private Bitmap Draw3DView(sicklrf.State stateType)
        {
            // TT - Some minor rearrangement of Ben's code
            int robotWidth = (int)options.RobotWidth; // mm
            double angle, obsThresh;
            Color col;

            Bitmap bmp = new Bitmap(stateType.DistanceMeasurements.Length, LRFImageHeight);
            Graphics g = Graphics.FromImage(bmp);
            g.Clear(Color.LightGray);

            int half = bmp.Height / 2;

            for (int x = 0; x < stateType.DistanceMeasurements.Length; x++)
            {
                int range = stateType.DistanceMeasurements[x];
                if (range > 0 && range < options.MaxLRFRange)
                {
                    int h = bmp.Height * 500 / stateType.DistanceMeasurements[x];
                    if (h < 0)
                    {
                        h = 0;
                    }
                    // TT - Ignore the robot width if it is not set
                    if (robotWidth > 0)
                    {
                        angle = x * Math.PI * stateType.AngularRange /
                                stateType.DistanceMeasurements.Length / 180; // radians
                        obsThresh = Math.Abs(robotWidth / (2 * Math.Cos(angle)));
                    }
                    else
                        obsThresh = 0.0;

                    if (range < obsThresh)
                        col = LinearColor(Color.DarkRed, Color.LightGray, 0, (int)options.MaxLRFRange, range);
                    else
                        col = LinearColor(Color.DarkBlue, Color.LightGray, 0, (int)options.MaxLRFRange, range);

                    g.DrawLine(new Pen(col), bmp.Width - x, half - h, bmp.Width - x, half + h);
                }
            }

            // Return the image
            return bmp;
        }