Esempio n. 1
0
        /// <summary>
        /// Estimate pose
        /// </summary>
        /// <param name="gridMap">Map</param>
        /// <param name="scan">Scanned points</param>
        /// <param name="estimate">Estimate position</param>
        /// <returns>true if estimation was madde, false if failed</returns>
        protected bool EstimateTransformationLogLh(OccGridMap gridMap, ScanCloud scan, ref Vector3 estimate)
        {
            GetCompleteHessianDerivs(gridMap, scan, estimate, out Matrix4x4 H, out Vector3 dTr);

            if ((H.M11 != 0.0f) && (H.M22 != 0.0f))
            {
                if (!Matrix4x4.Invert(H, out Matrix4x4 iH))
                {
                    logger?.LogError($"Failed to calculate inverse matrix from {H}");
                    return(false);
                }

                Vector3 searchDir = Vector3.Transform(dTr, iH);

                if (searchDir.Z > 0.2f)
                {
                    logger?.LogWarning($"SearchDir angle change ({MathEx.RadToDeg(searchDir.Z)}°) too large");
                    searchDir.Z = 0.2f;
                }
                else if (searchDir.Z < -0.2f)
                {
                    logger?.LogWarning($"SearchDir angle change ({MathEx.RadToDeg(searchDir.Z)}°) too large");
                    searchDir.Z = -0.2f;
                }

                estimate += searchDir;

                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Draw field and everything
        /// </summary>
        private void Draw()
        {
            DrawArea.Children.Clear();
            DrawBackground();

            // What SLAM map to show ?
            switch (VisibleSLAMComboBox.SelectedIndex)
            {
            // CoreSLAM ?
            case 0:

                // Construct hole map image
                WriteableBitmap holeMapBitmap = new WriteableBitmap(coreSlam.HoleMap.Size, coreSlam.HoleMap.Size, 96, 96, PixelFormats.Gray16, null);
                Int32Rect       csRect        = new Int32Rect(0, 0, coreSlam.HoleMap.Size, coreSlam.HoleMap.Size);
                holeMapBitmap.WritePixels(csRect, coreSlam.HoleMap.Pixels, holeMapBitmap.BackBufferStride, 0);

                Image holeMapImage = new Image()
                {
                    Source = holeMapBitmap,
                    Width  = coreSlam.PhysicalMapSize,
                    Height = coreSlam.PhysicalMapSize,
                };

                DrawArea.Children.Add(holeMapImage);
                break;

            // HectorSLAM ?
            case 1:

                // Construct occupancy map image
                OccGridMap      map = hectorSlam.MapRep.Maps[VisibleHectorSLAMLayerComboBox.SelectedIndex];
                WriteableBitmap occupancyMapBitmap = new WriteableBitmap(map.Dimensions.X, map.Dimensions.Y, 96, 96, PixelFormats.Gray8, null);
                Int32Rect       hsRect             = new Int32Rect(0, 0, map.Dimensions.X, map.Dimensions.Y);
                occupancyMapBitmap.WritePixels(hsRect, map.GetBitmapData(), occupancyMapBitmap.PixelWidth, 0);

                Image occMapImage = new Image()
                {
                    Source = occupancyMapBitmap,
                    Width  = map.Properties.PhysicalSize.X,
                    Height = map.Properties.PhysicalSize.Y,
                };

                DrawArea.Children.Add(occMapImage);
                break;
            }

            // Draw real field edges
            //DrawField();                                           //plus réaliste pour moi de commenter ça car sinon ca veut dire qu'on connait déja le monde

            // Draw poses
            DrawPose(lidarPose, 0.2f, Colors.Blue);                                     // c'est là qu'on dessine la position du Lidar (robot) en fct de la méthode
            DrawPose(coreSlam.Pose, 0.2f, Colors.Red);
            DrawPose(hectorSlam.MatchPose, 0.2f, Colors.Green);

            // Update labels
            RealPoseLabel.Text       = lidarPose.ToPoseString();
            CoreSLAMPoseLabel.Text   = coreSlam.Pose.ToPoseString();
            HectorSLAMPoseLabel.Text = hectorSlam.MatchPose.ToPoseString();
        }
Esempio n. 3
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="mapResolution">Meters per pixel</param>
        /// <param name="mapSize">Map size pixels</param>
        /// <param name="numDepth">Number of map levels</param>
        /// <param name="startCoords">Start coordinates as fraction of whole map size</param>
        public MapRepMultiMap(float mapResolution, Point mapSize, int numDepth, Vector2 startCoords)
        {
            parallelOptions = new ParallelOptions()
            {
                MaxDegreeOfParallelism = numDepth
            };

            // Create map
            Maps = new OccGridMap[numDepth];
            for (int i = 0; i < numDepth; ++i)
            {
                Debug.WriteLine($"HectorSLAM map level #{i} resolution: {mapResolution} m/pix, size: {mapSize}");
                Maps[i] = new OccGridMap(mapResolution, mapSize, startCoords);

                // Decrease map accuracy - next level is half the pixel size of previous level
                mapSize        = new Point(mapSize.X / 2, mapSize.Y / 2);
                mapResolution *= 2.0f;
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Match scan data
        /// </summary>
        /// <param name="gridMap">Map</param>
        /// <param name="scan">Scanned points</param>
        /// <param name="hintPose">Estimation hint pose in world coordinates (meters)</param>
        /// <param name="numIterations">Number of estimate iterations to do</param>
        /// <returns>Best position estimate in world coordinates (meters)</returns>
        public Vector3 MatchData(OccGridMap gridMap, ScanCloud scan, Vector3 hintPose)
        {
            if (scan.Points.Count > 0)
            {
                Vector3 estimate = gridMap.GetMapCoordsPose(hintPose);

                for (int i = 0; i < gridMap.EstimateIterations; i++)
                {
                    EstimateTransformationLogLh(gridMap, scan, ref estimate);
                }

                // Normalize Z rotation
                estimate.Z = MathEx.NormalizeAngle(estimate.Z);

                // Return world coordinates
                return(gridMap.GetWorldCoordsPose(estimate));
            }

            // When no scan points provided, return hint pose
            return(hintPose);
        }
Esempio n. 5
0
        /// <summary>
        /// ...
        /// </summary>
        /// <param name="coords">Map coordinates</param>
        /// <returns></returns>
        protected static Vector3 InterpMapValueWithDerivatives(OccGridMap gridMap, Vector2 coords)
        {
            float[] intensities = new float[4];

            // Check if coords are within map limits.
            if (gridMap.Properties.IsPointOutOfMapBounds(coords))
            {
                return(Vector3.Zero);
            }

            // Map coords are always positive, floor them by casting to int
            Point indMin = coords.ToFloorPoint();

            // Get factors for bilinear interpolation
            Vector2 factors = coords - indMin.ToVector2();
            int     sizeX   = gridMap.Dimensions.X;
            int     index   = indMin.Y * sizeX + indMin.X;

            // Get grid values for the 4 grid points surrounding the current coords.
            intensities[0] = gridMap.GetCachedProbability(index);
            intensities[1] = gridMap.GetCachedProbability(index + 1);
            intensities[2] = gridMap.GetCachedProbability(index + sizeX);
            intensities[3] = gridMap.GetCachedProbability(index + sizeX + 1);

            float dx1 = intensities[0] - intensities[1];
            float dx2 = intensities[2] - intensities[3];

            float dy1 = intensities[0] - intensities[2];
            float dy2 = intensities[1] - intensities[3];

            float xFacInv = 1.0f - factors.X;
            float yFacInv = 1.0f - factors.Y;

            return(new Vector3(
                       ((intensities[0] * xFacInv + intensities[1] * factors.X) * yFacInv) +
                       ((intensities[2] * xFacInv + intensities[3] * factors.X) * factors.Y),
                       -((dx1 * xFacInv) + (dx2 * factors.X)),
                       -((dy1 * yFacInv) + (dy2 * factors.Y))));
        }
Esempio n. 6
0
        /// <summary>
        /// Get complete hessian matrix derivatives
        /// </summary>
        /// <param name="gridMap">Map</param>
        /// <param name="scan">Scanned points</param>
        /// <param name="pose">Pose at which to calculate</param>
        /// <param name="H"></param>
        /// <param name="dTr"></param>
        protected void GetCompleteHessianDerivs(OccGridMap gridMap, ScanCloud scan, Vector3 pose, out Matrix4x4 H, out Vector3 dTr)
        {
            // Transformation of lidar measurements.
            // Translation is in pixels, need to convert it meters first.
            Matrix3x2 transform =
                Matrix3x2.CreateRotation(pose.Z) *
                Matrix3x2.CreateTranslation(pose.X * gridMap.Properties.CellLength, pose.Y * gridMap.Properties.CellLength) *
                Matrix3x2.CreateScale(gridMap.Properties.ScaleToMap);

            // Do the measurements scaling here, rather than wasting time in the rotDeriv calculation
            float sinRot = MathF.Sin(pose.Z) * gridMap.Properties.ScaleToMap;
            float cosRot = MathF.Cos(pose.Z) * gridMap.Properties.ScaleToMap;

            // Divide work to chunks
            int chunkSize = (scan.Points.Count + worker.NumThreads - 1) / worker.NumThreads;

            Vector3[]   vectors  = new Vector3[worker.NumThreads];
            Matrix4x4[] matrixes = new Matrix4x4[worker.NumThreads];

            // Do work in parallel threads
            worker.Work(index =>
            {
                var localH  = new Matrix4x4();
                var localTr = Vector3.Zero;

                foreach (Vector2 scanPoint in scan.Points.Skip(index * chunkSize).Take(chunkSize))
                {
                    Vector2 scanPointMap         = Vector2.Transform(scanPoint, transform);
                    Vector3 transformedPointData = InterpMapValueWithDerivatives(gridMap, scanPointMap);

                    float funVal = 1.0f - transformedPointData.X;

                    localTr.X += transformedPointData.Y * funVal;
                    localTr.Y += transformedPointData.Z * funVal;

                    float rotDeriv = ((-sinRot * scanPoint.X - cosRot * scanPoint.Y) * transformedPointData.Y +
                                      (cosRot * scanPoint.X - sinRot * scanPoint.Y) * transformedPointData.Z);

                    localTr.Z += rotDeriv * funVal;

                    localH.M11 += transformedPointData.Y.Sqr();
                    localH.M22 += transformedPointData.Z.Sqr();
                    localH.M33 += rotDeriv.Sqr();

                    localH.M12 += transformedPointData.Y * transformedPointData.Z;
                    localH.M13 += transformedPointData.Y * rotDeriv;
                    localH.M23 += transformedPointData.Z * rotDeriv;
                }

                matrixes[index] = localH;
                vectors[index]  = localTr;
            });

            // Aggragate threaded results
            H   = new Matrix4x4();
            dTr = Vector3.Zero;

            for (int i = 0; i < worker.NumThreads; i++)
            {
                H   += matrixes[i];
                dTr += vectors[i];
            }

            // Symmetry for inversion
            H.M21 = H.M12;
            H.M31 = H.M13;
            H.M32 = H.M23;

            // Make 4x4 matrix inversible
            H.M44 = 1.0f;
        }