The build consists of three main components: 1. Mounting the Medium Servo Motor, 2. Mounting the Color Sensor, and 3. Securing the EV3 Intelligent Brick
1. Mounting the Medium Servo Motor
2. Mounting the Color Sensor
3. Mounting the EV3 Intelligent Brick
This section of the walkthrough assumes you have completed Setup, Mission 1, and Mission 2 outlined here: https://www.hackster.io/alexagadgets/lego-mindstorms-voice-challenge-setup-17300f
We won't be covering every code artifact here, but all of the code necessary to run the gadget can be found at https://github.com/ehartye/roller-coaster-gadget.
The code consists of three main components: 1. The Skill Interaction Model, 2. The Node JS Skill Lambda code and 3. The Python3 Gadget code
1. The Skill Interaction Model
The following json, from model.json
, defines the intent, slot, and sample utterances for the roller coaster:
{
"name": "SetLapIntent",
"slots": [
{
"name": "LapCount",
"type": "AMAZON.NUMBER"
}
],
"samples": [
"Go for {LapCount}",
"Stop after {LapCount}",
"{LapCount} time",
"{LapCount} times",
"{LapCount} ride",
"{LapCount} rides",
"{LapCount} lap",
"{LapCount} laps",
"{LapCount} please"
]
}
2. The NodeJS Skill Lambda
The following handlers, from index.js
, contain the primary skill logic for the roller coaster.
LaunchRequestHandler
This handler responds to the initial skill invocation and prompts the user with a hint if necessary.
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle: async function(handlerInput) {
let request = handlerInput.requestEnvelope;
let { apiEndpoint, apiAccessToken } = request.context.System;
let apiResponse = await Util.getConnectedEndpoints(apiEndpoint, apiAccessToken);
if ((apiResponse.endpoints || []).length === 0) {
return handlerInput.responseBuilder
.speak(`I couldn't find an EV3 Brick connected to this Echo device. Please check to make sure your EV3 Brick is connected, and try again.`)
.getResponse();
}
// Store the gadget endpointId to be used in this skill session
let endpointId = apiResponse.endpoints[0].endpointId || [];
Util.putSessionAttribute(handlerInput, 'endpointId', endpointId);
return handlerInput.responseBuilder
.speak("Welcome! To ride the Lego Roller Coaster, you must be less than two inches tall! How many times would you like to ride?")
.reprompt("If you're not sure what to do, try saying 3 rides please.")
.getResponse();
}
};
SetLapintentHandler
This handler pulls the lap count value from the intent slot, validates the lap count to be a positive integer, then passes it to the EV3 gadget.
// Get the lap count
const SetLapIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'SetLapIntent';
},
handle: function (handlerInput) {
let lapCount = Alexa.getSlotValue(handlerInput.requestEnvelope, 'LapCount');
lapCount = Math.max(1, parseInt(lapCount));
if (!Number.isInteger(lapCount)) {
return handlerInput.responseBuilder
.speak("Can you repeat that?")
.reprompt("What was that again?").getResponse();
}
Util.putSessionAttribute(handlerInput, 'lapCount', lapCount);
const attributesManager = handlerInput.attributesManager;
const endpointId = attributesManager.getSessionAttributes().endpointId || [];
const directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
{
type: 'rideStart',
lapCount: lapCount
}
);
return handlerInput.responseBuilder
.speak(`Hold on to your studs, and enjoy your ${lapCount} lap ride!`)
.addDirective(directive)
.getResponse();
}
};
3. The Python3 Gadget code
The following function, from roller-coaster.py
, actually controls the movement of the roller coaster gadget
_startRide
After the lapCount value has been received from the skill in on_custom_mindstorms_gadget_control
, it's passed to _startRide
, and controls the number of loops that are executed.
def _startRide(self,lapCount):
lapsLeft = lapCount
while lapsLeft > 0:
#Cars passing light sensor at base of chain lift hill
#signal beginning of lap
if self.color.reflected_light_intensity > 10:
#SpeedPercent(100), 35 required to get cars up chain lift hill
#and around track bend at top
self.chainLift.on_for_rotations(SpeedPercent(100), 35)
lapsLeft = lapsLeft - 1
time.sleep(2)
time.sleep(.5)
Comments