Have you and your friends sat around a table, playing cards, and then when it comes to dealing, no one wants to do it, if you answered yes, then this might just be the project for you. Using Amazon's Alexa, and Lego's MindStorms you can build a voice activated Lego card dealer.
With this build you will be able to say 'Alexa, deal five cards for four players', or 'Alexa, deal poker for 6 players' or 'Alexa, deal again' where the Mindstorm dealer will deal the last deal again. You can also ask to deal cards to a certain player again.
For this project, I used Visual Studio Code, the skill uses Node.js and the gadget file is python. For the skill to remember the previous deal commands, the session state values are saved in a dynamoDB table.
The steps to setup your environment is documented here: Lego MINDSTORMS Voice Challenge: Setup. And Here: LEGO MINDSTORMS Voice Challenge: Mission 1.
Going through all the missions on that page is a great place to learn and understand how Alexa and gadgets work.
Here are direct links to the necessary sections needed for this project to setup your environment.
Set up your EV3 development environment
Register an Alexa Gadget in the Alexa Developer Console
Step 2: Building the Mindstorm dealerAttached file card_dealer_build_instructions_v1.pdf is the build instructions to build the Lego Mindstorms dealer, the 'deal motor' is connected to port A and the 'rotate motor' is connected to port B
Step 3: The CodeThere are 3 main directories, gadget, Skill and CloudformationScripts.
In the gadget directory there are 2 files, a initialization (ini) file and a python (py) file, these 2 files should have the same file name, this is for the gadget to know which ini file matches with with the py file.
The initialization file.
The follow explanation of the ini file is from here: Registration and capabilities
[GadgetSettings]
amazonId = YOUR_GADGET_AMAZON_ID
alexaGadgetSecret = YOUR_GADGET_SECRET
[GadgetCapabilities]
Custom.Card.Dealer.Gadget = 1.0
The INI (or initialization) file defines parameters for how your EV3 Brick should work as a gadget:
Gadget Settings: Specifies the Amazon ID and Alexa Gadget Secret that you received when you created your gadget in the Amazon Developer Console. It authenticates your EV3 Brick, and allows it to connect to your Echo device and Alexa.
Gadget Capabilities: Specifies what Alexa Gadget functionality your EV3 Brick supports. For this mission, your EV3 Brick is responding to the wake word, which is a part of the StateListener
capability defined within the Alexa Gadgets Toolkit. There are more capabilities you can explore in the documentation.
You need to update this file with information tied to the Alexa Gadget you registered in the Amazon Developer Console:
ReplaceYOUR_GADGET_AMAZON_ID
andYOUR_GADGET_SECRET
with the ID and Secret tied to the Alexa Gadget you registered in the Amazon Developer Console.
With those changes, your EV3 Brick will be able to connect to your Echo device as an Alexa Gadget. Now, let’s take a look at the Python 3 code that will cause your EV3 Brick to connect to your Echo device and react to the wake word.
The python file.
The python files contains the code to connect the ev3 to the echo device using bluetooth and all the funtions the ev3 brick needs to do.
The following text was adapted from Establishing a Bluetooth connection with the Echo device
In order for the echo devices to use the ev3 brick as a gadget, the EV3 Brick needs to establish a Bluetooth connection with the Echo device. Fortunately, we can leverage the AlexaGadget
class provided by the Alexa Gadgets Toolkit API to accomplish this easily.
Within the carddealer.py file, you will see a MindstormsCardDealerGadget class that extends the AlexaGadget
class. The AlexaGadget
class is invoked using the initialization method:
from agt import AlexaGadget
class MindstormsCardDealerGadget(AlexaGadget):
# Enabled Alexa device communication by extending from AlexaGadget
def __init__(self):
# Performs Alexa Gadget initialization routines and ev3dev resource allocation.
super().__init__()
On bluetooth connection, we need to detect the custom calls from alexa, the mindstorm will listen for the following functions in the carddealer.py file
on_custom_card_dealer_gadget_reset - this will reset the current card dealer
on_custom_card_dealer_gadget_deal - this will deal the cards, it receives 2 parameters, cardCount, number of cards per player and count, number of players
on_custom_card_dealer_gadget_playercard - deals a number of cards to a specific player
on_custom_card_dealer_gadget_pickup52 - when the user askes to play pickup 52, the dealer will spit out all the cards in the deck, for the user to pick up
The Skill Code
All the code for the skill is in the Skill directory.
The important part of the skill is in the lambda\custom\handlers\ folder, this here where all the intents for the skill is coded.
I have grouped the intents together per file
commonHandler.js - here are all the default alexa intents and intents that I can use across different skills without changing them, for example the help intent.
const HelpIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speakOutput = 'You can say hello to me! How can I help?';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
launchRequetHandler.js - this is the first intent that is called, this intent will open the skill and wait for more commands from the user
cardDealHandler.js - this is the intent that deal the cards
dealAgainHandler.js - this intent gets the stored data from dynamoDB and deal that hand again. In the helpers folder there is a dbHelper.js file, this is where the skill accesses the dynamoDB to store and retrieve the session data from dynamoDB.
playerCardHandler.js - this intent deals cards to a specific player.
DynamoDB setup
For the skill to remember the state between sessions, I save the session values in a dynamoDB table, read more about dynamoDB here.
In the CloudFormationScripts directory is one file, this is yaml file, and will create the dynamoDB table that is needed for this skill to save the session values between sessions.
Read more about cloudfromation Scripts here.
Step 4: Deploying your Skill to AmazonI used the ASK CLI to publish my skill to the amazon skill developer portal.
After you have installed and configured the ask cli, you can run the following command in the project folder to publish the skill and necessary lambda functions.
ask deploy
After the skill is deployed successfully, ask alexa: 'Alexa, open mindstorm dealer'
BONUS START YOUR GADGET CODE ON BOOTThis works better if your ev3 brick boots up and imediatly runs your gadget python file. To do that we will create a service file.
When the ev3 brick is connected and you can SSH into it, go to the system directory
cd /etc/systemd/system/
Now we need to create the service file, we will use nano, run the following command to create open a empty file, you can name the file anything, as long as the extension is service
sudo nano gadget.service
In the editor that opens, past the following code
[Service]
WorkingDirectory=DIR_TO_YOUR_PYTHON_FILE
ExecStart=/usr/bin/python3 PATH_TO_THE_PYTHON_FILE
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=YOUR_APP_NAME_HERE
User=root
Group=root
Environment=PYTHON_ENV=production
[Install]
WantedBy=multi-user.target
Replace DIR_TO_YOUR_PYTHON_FILE with the directory where your gadget python file is, ex /home/gadget
Replace the PATH_TO_THE_PYTHON_FILE with the path to the gadget python file, ex /home/gadget/gadgetfile.py
Replace YOUR_APP_NAME_HERE with a name for your application, this will help with the log files
Now Press ctrl + x and then Y to exit and save
After the file is saved, run this command to make the service start at boot
sudo systemctl enable gadget.service
Now if you reboot your ev3 it will run your gadget python file automatically.
To reboot
sudo reboot
Comments