Hackster is hosting Hackster Holidays, Ep. 4: Livestream & Giveaway Drawing. Start streaming on Wednesday!Stream Hackster Holidays, Ep. 4 on Wednesday!
Agnes BiborkaSoma Fekete
Created December 10, 2019

All around the globe

This is an Alexa and EV3 powered project that helps anyone to find a country on a globe. Made for Voice Challenge.

IntermediateFull instructions provided5 hours77
All around the globe

Things used in this project

Hardware components

Mindstorms EV3 Programming Brick / Kit
LEGO Mindstorms EV3 Programming Brick / Kit
1 Brick 2 Medium Motors
×1
Echo Dot
Amazon Alexa Echo Dot
You can use any type of Echo smart home device.
×1
Globe
Any type of globes, which's diameter is between 25 and 35 centimeters fits to this project.
×1

Software apps and online services

VS Code
Microsoft VS Code

Story

Read more

Custom parts and enclosures

Skill Nodejs - For the code

Here are the files that you need for the proggraming:

Code

Geography

Python
Main Python program, which runs on your EV3 brick
import os
import sys
import time
import logging
import json
import random
import threading

from enum import Enum
from agt import AlexaGadget

from ev3dev2.led import Leds
from ev3dev2.sound import Sound
from ev3dev2.motor import OUTPUT_A, OUTPUT_B, SpeedPercent, MediumMotor

# Set the logging level to INFO to see messages from AlexaGadget
logging.basicConfig(level=logging.INFO, stream=sys.stdout, format='%(message)s')
logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
logger = logging.getLogger(__name__)


class MindstormsGadget(AlexaGadget):
    """
    This is a Mindstorms gadget that performs movement based on voice commands.
    """

    def __init__(self):
        """
        Performs Alexa Gadget initialization routines and ev3dev resource allocation.
        """
        super().__init__()

        # Ev3dev initialization
        self.leds = Leds()
        self.sound = Sound()
        self.longitudeMotor = MediumMotor(OUTPUT_B)
        self.latitudeMotor = MediumMotor(OUTPUT_A)
        # The countries and its coordinates
        self.countries = ["test", "center", "Andorra", "United Arab Emirates", "Afghanistan", "Antigua and Barbuda", "Anguilla", "Albania", "Armenia", "Netherlands Antilles", "Angola", "Antarctica", "Argentina", "American Samoa", "Austria", "Australia", "Aruba", "Azerbaijan", "Bosnia and Herzegovina", "Barbados", "Bangladesh", "Belgium", "Burkina Faso", "Bulgaria", "Bahrain", "Burundi", "Benin", "Bermuda", "Brunei", "Bolivia", "Brazil", "Bahamas", "Bhutan", "Bouvet Island", "Botswana", "Belarus", "Belize", "Canada", "Cocos [Keeling] Islands", "Congo [DRC]", "Central African Republic", "Congo [Republic]", "Switzerland", "Côte d'Ivoire", "Cook Islands", "Chile", "Cameroon", "china", "Colombia", "Costa Rica", "Cuba", "Cape Verde", "Christmas Island", "Cyprus", "Czech Republic", "Germany", "Djibouti", "Denmark", "Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia", "Egypt", "Western Sahara", "Eritrea", "Spain", "Ethiopia", "Finland", "Fiji", "Falkland Islands [Islas Malvinas]", "Micronesia", "Faroe Islands", "France", "Gabon", "United Kingdom", "Grenada", "Georgia", "French Guiana", "Guernsey", "Ghana", "Gibraltar", "Greenland", "Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece", "South Georgia and the South Sandwich Islands", "Guatemala", "Guam", "Guinea-Bissau", "Guyana", "Gaza Strip", "Hong Kong", "Heard Island and McDonald Islands", "Honduras", "Croatia", "Haiti", "Hungary", "Indonesia", "Ireland", "Israel", "Isle of Man", "India", "British Indian Ocean Territory", "Iraq", "Iran", "Iceland", "Italy", "Jersey", "Jamaica", "Jordan", "japan", "Kenya", "Kyrgyzstan", "Cambodia", "Kiribati", "Comoros", "Saint Kitts and Nevis", "North Korea", "South Korea", "Kuwait", "Cayman Islands", "Kazakhstan", "Laos", "Lebanon", "Saint Lucia", "Liechtenstein", "Sri Lanka", "Liberia", "Lesotho", "Lithuania", "Luxembourg", "Latvia", "Libya", "Morocco", "Monaco", "Moldova", "Montenegro", "Madagascar", "Marshall Islands", "Macedonia", "Mali", "Myanmar", "Mongolia", "Macau", "Northern Mariana Islands", "Martinique", "Mauritania", "Montserrat", "Malta", "Mauritius", "Maldives", "Malawi", "Mexico", "Malaysia", "Mozambique", "Namibia", "New Caledonia", "Niger", "Norfolk Island", "Nigeria", "Nicaragua", "Netherlands", "Norway", "Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama", "Peru", "French Polynesia", "Papua New Guinea", "Philippines", "Pakistan", "Poland", "Saint Pierre and Miquelon", "Pitcairn Islands", "Puerto Rico", "Palestinian Territories", "Portugal", "Palau", "Paraguay", "Qatar", "Réunion", "Romania", "Serbia", "Russia", "Rwanda", "Saudi Arabia", "Solomon Islands", "Seychelles", "Sudan", "Sweden", "Singapore", "Saint Helena", "Slovenia", "Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino", "Senegal", "Somalia", "Suriname", "São Tomé and Príncipe", "El Salvador", "Syria", "Swaziland", "Turks and Caicos Islands", "Chad", "French Southern Territories", "Togo", "Thailand", "Tajikistan", "Tokelau", "Timor-Leste", "Turkmenistan", "Tunisia", "Tonga", "Turkey", "Trinidad and Tobago", "Tuvalu", "Taiwan", "Tanzania", "Ukraine", "Uganda", "U.S. Minor Outlying Islands", "the United States", "Uruguay", "Uzbekistan", "Vatican City", "Saint Vincent and the Grenadines", "Venezuela", "British Virgin Islands", "U.S. Virgin Islands", "Vietnam", "Vanuatu", "Wallis and Futuna", "Samoa", "Kosovo", "Yemen", "Mayotte", "South Africa", "Zambia", "Zimbabwe"]
        self.longitudes = [360.0, 0.0,  1.602, 53.848, 67.710, -61.796, -63.069, 20.168, 45.038, -69.060, 17.874, 0.071, -63.617, -170.132, 14.550, 133.775, -69.968, 47.577, 17.679, -59.543, 90.356, 4.470, -1.562, 25.486, 50.638, 29.919, 2.316, -64.757, 114.728, -63.589, -51.925, -77.396, 90.434, 3.413, 24.685, 27.953, -88.498, -106.347, 96.871, 21.759, 20.939, 15.828, 8.228, -5.547, -159.778, -71.543, 12.355, 104.195, -74.297, -83.753, -77.781, -24.013, 105.690, 33.430, 15.473, 10.452, 42.590, 9.502, -61.371, -70.163, 1.660, -78.183, 25.014, 30.802, -12.886, 39.782, -3.749, 40.490, 25.748, 179.414, -59.524, 150.551, -6.912, 2.214, 11.609, -3.436, -61.604, 43.357, -53.126, -2.585, -1.023, -5.345, -42.604, -15.310, -9.697, -62.068, 10.268, 21.824, -36.588, -90.231, 144.794, -15.180, -58.930, 34.309, 114.109, 73.504, -86.242, 43.511, -72.285, 19.503, 113.921, -8.244, 34.852, -4.548, 78.963, 71.877, 43.679, 53.688, -19.021, 12.567, -2.131, -77.298, 36.238, 138.253, 37.906, 74.766, 104.991, -168.734, 43.872, -62.783, 127.510, 127.767, 47.482, -80.567, 66.924, 102.495, 35.862, -60.979, 9.555, 80.772, -9.429, 28.234, 23.881, 6.130, 24.603, 17.228, -7.093, 7.413, 28.370, 19.374, 46.869, 171.184, 21.745, -3.996, 95.956, 103.847, 113.544, 145.385, -61.024, -10.941, -62.187, 14.375, 57.552, 73.221, 34.302, -102.553, 101.976, 35.530, 18.490, 165.618, 8.082, 167.955, 8.675, -85.207, 5.291, 8.469, 84.124, 166.932, -169.867, 174.886, 55.923, -80.782, -75.015, -149.407, 143.956, 121.774, 69.345, 19.145, -56.271, -127.439, -66.590, 35.233, -8.224, 134.583, -58.444, 51.184, 55.536, 24.967, 21.006, 105.319, 29.874, 45.079, 160.156, 55.492, 30.218, 18.644, 103.820, -10.031, 14.995, 23.670, 19.699, -11.780, 12.458, -14.452, 46.200, -56.028, 6.613, -88.897, 38.997, 31.466, -71.798, 18.732, 69.349, 0.825, 100.993, 71.276, -171.856, 125.728, 59.556, 9.537, -175.198, 35.243, -61.223, 177.649, 120.961, 34.889, 31.166, 32.290, -159.996, -95.713, -55.766, 64.585, 12.453, -61.287, -66.590, -64.640, -64.896, 108.277, 166.959, -177.156, -172.105, 20.903, 48.516, 45.166, 22.938, 27.849, 29.155]
        self.latitudes = [0.0, 0.0, 42.546, 23.424, 33.939, 17.061, 18.221, 41.153, 40.069, 12.226, -11.203, -75.251, -38.416, -14.271, 47.516, -25.274, 12.521, 40.143, 43.916, 13.194, 23.685, 50.504, 12.238, 42.734, 25.930, -3.373, 9.308, 32.321, 4.535, -16.290, -14.235, 25.034, 27.514, -54.423, -22.328, 53.710, 17.190, 56.130, -12.164, -4.038, 6.611, 0.228, 46.818, 7.540, -21.237, -35.675, 7.370, 35.862, 4.571, 9.749, 21.522, 16.002, -10.448, 35.126, 49.817, 51.166, 11.825, 56.264, 15.415, 18.736, 28.034, -1.831, 58.595, 26.821, 24.216, 15.179, 40.464, 9.145, 61.924, -16.578, -51.796, 7.426, 61.893, 46.228, 0.804, 55.378, 12.263, 42.315, 3.934, 49.466, 7.947, 36.138, 71.707, 13.443, 9.946, 16.996, 1.651, 39.074, -54.430, 15.783, 13.444, 11.804, 4.860, 31.355, 22.396, -53.082, 15.200, 16.438, 18.971, 47.162, 0.789, 53.413, 31.046, 54.236, 20.594, -6.343, 33.223, 32.428, 64.963, 41.872, 49.214, 18.110, 30.585, 36.205, 0.024, 41.204, 12.566, -3.370, -11.875, 17.358, 40.340, 35.908, 29.312, 19.513, 48.020, 19.856, 33.855, 13.909, 47.166, 7.873, 6.428, -29.610, 55.169, 49.815, 56.880, 26.335, 31.792, 43.750, 47.412, 42.709, -18.767, 7.131, 41.609, 17.571, 21.914, 46.862, 22.199, 17.331, 14.642, 21.008, 16.742, 35.937, -20.348, 3.203, -13.254, 23.635, 4.210, -18.666, -22.958, -20.904, 17.608, -29.041, 9.082, 12.865, 52.133, 60.472, 28.395, 0.523, -19.054, -40.901, 21.513, 8.538, -9.190, -17.680, -6.315, 12.880, 30.375, 51.919, 46.942, -24.704, 18.221, 31.952, 39.400, 7.515, -23.443, 25.355, -21.115, 45.943, 44.017, 61.524, -1.940, 23.886, -9.646, -4.680, 12.863, 60.128, 1.352, -24.143, 46.151, 77.554, 48.669, 8.461, 43.942, 14.497, 5.152, 3.919, 0.186, 13.794, 34.802, -26.523, 21.694, 15.454, -49.280, 8.620, 15.870, 38.861, -8.967, -8.874, 38.970, 33.887, -21.179, 38.964, 10.692, -7.110, 23.698, -6.369, 48.379, 1.373, -0.374, 37.090, -32.523, 41.377, 41.903, 12.984, 6.424, 18.421, 18.336, 14.058, -15.377, -13.769, -13.759, 42.603, 15.553, -12.828, -30.559, -13.134, -19.015]
        # Other varibles
        self.longitude = 0.0
        self.latitude = 0.0
        self.lastLongitude = 0.0
        self.lastLatitude = 0.0
        self.moveLatitude = 0
        self.moveLongitude = 0
        # Constant values, based on your structure and globe. You need to find them using the motortest program.
        # (Optimal values are about 100)
        self.longconstant = 93.6
        self.latconstant = 107

    def on_connected(self, device_addr):
        """
        Gadget connected to the paired Echo device.
        """
        self.leds.set_color("LEFT", "GREEN")
        self.leds.set_color("RIGHT", "GREEN")
        logger.info("{} connected to Echo device".format(self.friendly_name))

    def on_disconnected(self, device_addr):
        """
        Gadget disconnected from the paired Echo device.
        """
        self.leds.set_color("LEFT", "BLACK")
        self.leds.set_color("RIGHT", "BLACK")
        logger.info("{} disconnected from Echo device".format(self.friendly_name))

    def on_custom_mindstorms_gadget_control(self, directive):
        """
        Handles the Custom.Mindstorms.Gadget control directive.
        :param directive: the custom directive with the matching namespace and name
        """
        try:
            payload = json.loads(directive.payload.decode("utf-8"))
            print("Control payload: {}".format(payload))
            control_type = payload["type"]
            if control_type == "country":

                self.setLocation(payload["location"])

        except KeyError:
            print("Missing expected parameters: {}".format(directive))

    def setLocation(self, location):
        """
        This function is the most important part of this program. 
        At first, the robot finds the location in the list, then it calculates the moving values.
        """
        print("Location {}".format(location))
        self.longitude = self.longitudes[self.countries.index(location)]
        self.latitude = self.latitudes[self.countries.index(location)]
        print("Coordinates: {}, {}".format(self.longitude, self.latitude))
        self.moveLatitude = (self.latitude-self.lastLatitude)*self.latconstant
        self.moveLongitude = (self.longitude-self.lastLongitude)*self.longconstant
        if self.moveLatitude>0:
            self.latitudeMotor.run_timed(speed_sp=-100, time_sp=self.moveLatitude)
        else:
            self.latitudeMotor.run_timed(speed_sp=100, time_sp=-self.moveLatitude)

        if self.moveLongitude>0:
            self.longitudeMotor.run_timed(speed_sp=-100, time_sp=self.moveLongitude)
        else:
            self.longitudeMotor.run_timed(speed_sp=100, time_sp=-self.moveLongitude)

        self.lastLongitude = self.longitude
        self.lastLatitude = self.latitude
        


if __name__ == '__main__':

    gadget = MindstormsGadget()

    # Set LCD font and turn off blinking LEDs
    os.system('setfont Lat7-Terminus12x6')
    gadget.leds.set_color("LEFT", "BLACK")
    gadget.leds.set_color("RIGHT", "BLACK")

    # Startup sequence
    gadget.sound.play_song((('C4', 'e'), ('D4', 'e'), ('E5', 'q')))
    gadget.leds.set_color("LEFT", "GREEN")
    gadget.leds.set_color("RIGHT", "GREEN")

    # Gadget main entry point
    gadget.main()

    # Shutdown sequence
    gadget.sound.play_song((('E5', 'e'), ('C4', 'e')))
    gadget.leds.set_color("LEFT", "BLACK")
    gadget.leds.set_color("RIGHT", "BLACK")

Motortest

Python
This program is for calibration and for testing your motors.
import os
import time
from ev3dev2.led import Leds
from ev3dev2.sound import Sound
from ev3dev2.motor import OUTPUT_A, OUTPUT_B, SpeedPercent, MediumMotor
"""
This program is for calibration and for testing your motors.
"""
longitudeMotor = MediumMotor(OUTPUT_B)
latitudeMotor = MediumMotor(OUTPUT_A)
print("ready")

while True:
    n=int(input())
    # You can uncomment/comment the motor which you need / don't need.
    if n>0:
        latitudeMotor.run_timed(speed_sp=-100, time_sp=n)
        #longitudeMotor.run_timed(speed_sp=-100, time_sp=n)
        time.sleep(n/1000)
    else:
        latitudeMotor.run_timed(speed_sp=100, time_sp=-n)
        #longitudeMotor.run_timed(speed_sp=100, time_sp=-n)
        time.sleep((-n)/1000)

model.json

JSON
Main skill code
{
    "interactionModel": {
        "languageModel": {
            "invocationName": "all around the globe",
            "intents": [
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.NavigateHomeIntent",
                    "samples": []
                },
                {
                    "name": "FindLocation",
                    "slots": [
                        {
                            "name": "Location",
                            "type": "AMAZON.Country"
                        }
                    ],
                    "samples": [
                        "{Location}",
                        "Show me {Location}",
                        "Where is {Location} ",
                        "Find {Location}"
                    ]
                }
            ],
            "types": []
        }
    }
}

Credits

Agnes Biborka

Agnes Biborka

1 project • 1 follower
Soma Fekete

Soma Fekete

0 projects • 1 follower

Comments