private async Task <bool> ExecuteDockAsync(bool lastTry)
        {
            // Find the charger. It should be right in front of us.
            // Depending upon how far away from the charger we are we may need a different head pitch.
            // Start by assuming that we're fairly close to the charger which means we need to look more downward to see the charger.
            double headPitch = 35;
            await _skillHelper.MoveHeadAsync(headPitch, 0, 0);

            if (!await FindChargerAsync())
            {
                headPitch = 15;
                await _skillHelper.MoveHeadAsync(headPitch, 0, 0);

                if (!await FindChargerAsync())
                {
                    _skillHelper.MistySpeak("I can't find the charger.");
                    await Task.Delay(3000);

                    return(false);
                }
            }
            _skillHelper.MistySpeak("I see the charger.");

            _skillHelper.LogMessage($"Charger is located at [x, y, yaw] : [{_chargerPose.X:f3}, {_chargerPose.Y:f3}, {_chargerPose.Yaw.Degrees():f1}].");

            int retries = 0;

            while (_chargerPose.X - IDEAL_ALIGNMENT_DISTANCE > 0.04 || IDEAL_ALIGNMENT_DISTANCE - _chargerPose.X > 0.02 ||
                   Math.Abs(_chargerPose.Y) > 0.01 || Math.Abs(_chargerPose.Yaw.Degrees()) > 2.5)
            {
                var goalPose = new Simple2DPose()
                {
                    X   = IDEAL_ALIGNMENT_DISTANCE,
                    Y   = 0,
                    Yaw = 0
                };

                MoveSequence moveSequence = NavigationHelper.CalculateMoveSequence(_chargerPose, goalPose);

                _skillHelper.LogMessage($"Movement sequence to goal is turn {moveSequence.Turn1.Degrees():f0} degrees, drive {moveSequence.DriveDistance:f3} meters, " +
                                        $"and turn {moveSequence.Turn2.Degrees():f0} degrees.");

                if (!await _skillHelper.TurnAsync(moveSequence.Turn1.Degrees()))
                {
                    return(false);
                }
                if (_abort)
                {
                    return(false);
                }

                if (!await _skillHelper.DriveAsync(moveSequence.DriveDistance, true))
                {
                    return(false);
                }
                if (_abort)
                {
                    return(false);
                }

                if (!await _skillHelper.TurnAsync(moveSequence.Turn2.Degrees()))
                {
                    return(false);
                }
                if (_abort)
                {
                    return(false);
                }

                if (headPitch != 35)
                {
                    // In case we had to lift the head to originally find the charger.
                    headPitch = 35;
                    await _skillHelper.MoveHeadAsync(headPitch, 0, 0);
                }

                await Task.Delay(1000);

                if (!await CanSeeChargerAsync(1))
                {
                    _skillHelper.LogMessage("Can no longer see the charger.");
                    _skillHelper.MistySpeak("Uh oh. I can't see the charger any more.");
                    return(false);
                }

                _skillHelper.LogMessage($"Charger now located at [x, y, yaw] : [{_chargerPose.X:f3}, {_chargerPose.Y:f3}, {_chargerPose.Yaw.Degrees():f1}]. " +
                                        $"Error : [{(_chargerPose.X - goalPose.X):f3}, {(_chargerPose.Y - goalPose.Y):f3}, {(_chargerPose.Yaw.Degrees() - goalPose.Yaw.Degrees()):f1}].");

                if (retries++ > 5)
                {
                    _skillHelper.LogMessage("Failed to line up with the charger.");
                    _skillHelper.MistySpeak("I can't seem to line up right.");
                    await Task.Delay(5000);

                    return(false);
                }
            }

            _skillHelper.MistySpeak("I should be all lined up now. Going to turn around and back on to the charger.");

            // Turn around.
            // Note that we do 2 x 91 degrees. Misty tends to turn slightly less than requested and any turn where the absolute
            // value is over 180 degrees will get converted to a <180 turn in the other direction.
            _skillHelper.LogMessage("Turning 180 degrees to face away from charger.");
            if (!await _skillHelper.TurnAsync(91))
            {
                return(false);
            }
            if (_abort)
            {
                return(false);
            }
            if (!await _skillHelper.TurnAsync(91))
            {
                return(false);
            }
            if (_abort)
            {
                return(false);
            }

            // Back on to charger.
            _skillHelper.LogMessage($"Driving {IDEAL_ALIGNMENT_DISTANCE:f3} meters to back on to charger.");
            if (!await _skillHelper.DriveAsync(-IDEAL_ALIGNMENT_DISTANCE - 0.1, true))
            {
                return(false);
            }
            if (_abort)
            {
                return(false);
            }

            // Move forward slightly.
            _misty.DriveHeading(0, 0.01, 1000, false, OnResponse);

            // It can take several seconds for the charging indicator to update...
            _charging = false;
            DateTime start = DateTime.Now;

            while (!_charging && DateTime.Now.Subtract(start).TotalSeconds < 8)
            {
                await Task.Delay(250);
            }

            // If charging then the battery current is a positive number about 0.4 Amps
            if (_charging)
            {
                _skillHelper.MistySpeak("Ahh. I feel the power.");
                await Task.Delay(2000);
            }
            else
            {
                if (!lastTry)
                {
                    _skillHelper.MistySpeak("Hmm. I don't seem to be charging. I'm going to drive forward and try docking again.");
                    _skillHelper.LogMessage("Did not detect that we're charging. Driving forward and trying again.");

                    await _skillHelper.DriveAsync(IDEAL_ALIGNMENT_DISTANCE + 0.1);

                    if (_abort)
                    {
                        return(false);
                    }
                    await _skillHelper.TurnAsync(180);

                    return(false);
                }
            }

            return(true);
        }
示例#2
0
        public async Task <bool> AlignToArTag(int dictionary, double size, int tagId, Simple2DPose goalTagPose)
        {
            _abort = false;
            _tagId = tagId;
            _skillHelper.LogMessage($"Starting AR tag alignment. Desired tag pose is [x, y, yaw] {goalTagPose.X:f3}, {goalTagPose.Y:f3}, {goalTagPose.Yaw.Degrees():f0}].");

            // Look straight ahead
            await _skillHelper.MoveHeadAsync(0, 0, 0);

            // Startup AR tag detection
            _misty.EnableCameraService(OnResponse);
            _misty.EnableCameraService(OnResponse);                  // Calling twice to make sure. TODO: something smarter
            _misty.StartArTagDetector(dictionary, size, OnResponse);
            _misty.StartArTagDetector(dictionary, size, OnResponse); // Calling twice to make sure. TODO: something smarter
            _misty.RegisterArTagDetectionEvent(ArTagCallback, 100, true, "artagevent", OnResponse);

            // Wait for measurments to start.
            if (!await WaitForMeasurementAsync(10, 2))
            {
                if (_abort)
                {
                    return(false);
                }

                // Never detected the AR tag. Try a small sweep.
                _skillHelper.MistySpeak("I can't see the tag. Looking around for it.");
                _skillHelper.LogMessage("Do not see the tag. Starting sweep.");
                bool arTagFound = false;
                await _skillHelper.TurnAsync(20);

                int maxTurns = 5;
                while (!arTagFound && --maxTurns >= 0)
                {
                    arTagFound = await WaitForMeasurementAsync(1, 1);

                    if (_abort)
                    {
                        return(false);
                    }
                    if (!arTagFound)
                    {
                        await _skillHelper.TurnAsync(-10);
                    }
                }

                if (!arTagFound)
                {
                    _skillHelper.MistySpeak("I cannot find the tag.");
                    _skillHelper.LogMessage("Never detected the AR tag.");
                    Cleanup();
                    return(false);
                }
            }

            _skillHelper.LogMessage($"AR tag located at [x, y, yaw] : [{_currentTagPose.X:f3}, {_currentTagPose.Y:f3}, {_currentTagPose.Yaw.Degrees():f1}]. " +
                                    $"Offset : [{(_currentTagPose.X - goalTagPose.X):f3}, {(_currentTagPose.Y - goalTagPose.Y):f3}, {(_currentTagPose.Yaw.Degrees() - goalTagPose.Yaw.Degrees()):f1}].");

            if (Math.Abs(_currentTagPose.X - goalTagPose.X) < X_TOLERANCE && Math.Abs(_currentTagPose.Y - goalTagPose.Y) < Y_TOLERANCE &&
                Math.Abs(_currentTagPose.Yaw.Degrees() - goalTagPose.Yaw.Degrees()) < YAW_TOLERANCE)
            {
                _skillHelper.MistySpeak("We're already aligned with the tag. No need to move.");
                _skillHelper.LogMessage("No movement needed to align to tag.");
            }
            else
            {
                int retries = 0;
                while (Math.Abs(_currentTagPose.X - goalTagPose.X) > X_TOLERANCE || Math.Abs(_currentTagPose.Y - goalTagPose.Y) > Y_TOLERANCE ||
                       Math.Abs(_currentTagPose.Yaw.Degrees() - goalTagPose.Yaw.Degrees()) > YAW_TOLERANCE)
                {
                    MoveSequence moveSequence = NavigationHelper.CalculateMoveSequence(_currentTagPose, goalTagPose);
                    _skillHelper.LogMessage($"Movement sequence to goal is turn {moveSequence.Turn1.Degrees():f0} degrees, drive {moveSequence.DriveDistance:f3} meters, " +
                                            $"and turn {moveSequence.Turn2.Degrees():f0} degrees.");

                    await _skillHelper.TurnAsync(moveSequence.Turn1.Degrees());

                    if (_abort)
                    {
                        return(false);
                    }

                    await _skillHelper.DriveAsync(moveSequence.DriveDistance, true);

                    if (_abort)
                    {
                        return(false);
                    }

                    await _skillHelper.TurnAsync(moveSequence.Turn2.Degrees());

                    if (_abort)
                    {
                        return(false);
                    }

                    _skillHelper.LogMessage($"AR tag located at [x, y, yaw] : [{_currentTagPose.X:f3}, {_currentTagPose.Y:f3}, {_currentTagPose.Yaw.Degrees():f1}]. " +
                                            $"Offset : [{(_currentTagPose.X - goalTagPose.X):f3}, {(_currentTagPose.Y - goalTagPose.Y):f3}, {(_currentTagPose.Yaw.Degrees() - goalTagPose.Yaw.Degrees()):f1}].");

                    if (retries++ > 5)
                    {
                        _skillHelper.LogMessage("Failed to line up with the tag.");
                        _skillHelper.MistySpeak("I can't seem to line up right. I give up.");
                        await Task.Delay(5000);

                        Cleanup();
                        return(false);
                    }
                }

                _skillHelper.MistySpeak("Alignment complete.");
            }

            Cleanup();

            return(true);
        }