this is the function which called from Alexa intent and control the 3 motors to rotate and return back to their original position after folding the tshirt
copy the 2 files main.py and main.ini with the id and secret created in alexa voice service in the first step to the ev3 block and run the code
Lego Design
the ev3 comes with 3 motors one of them is medium motor which have less power than the other 2 , in my first design i used the 2 strong motors on the sides and in the middle the medium one but it couldn't lift the t-shirt efficiently so i switched their places as this picture and it worked
{"interactionModel":{"languageModel":{"invocationName":"tshirt folder","intents":[{"name":"AMAZON.CancelIntent","samples":[]},{"name":"AMAZON.HelpIntent","samples":[]},{"name":"AMAZON.StopIntent","samples":[]},{"name":"AMAZON.NavigateHomeIntent","samples":[]},{"name":"FoldIntent","slots":[],"samples":["fold the t-shirt","fold my tshirt","fold my t-shirt","fold the tshirt","fold","start","start folding"]}],"types":[]}}}
Alexa code
JavaScript
index.js
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* You may not use this file except in compliance with the terms and conditions
* set forth in the accompanying LICENSE.TXT file.
*
* THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
* RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
*/
// This skill sample demonstrates how to send directives and receive events from an Echo connected gadget.
// This skill uses the Alexa Skills Kit SDK (v2). Please visit https://alexa.design/cookbook for additional
// examples on implementing slots, dialog management, session persistence, api calls, and more.
const Alexa= require('ask-sdk-core');const Util= require('./util');const Common= require('./common');// The namespace of the custom directive to be sent by this skill
const NAMESPACE='Custom.Mindstorms.Gadget';// The name of the custom directive to be sent this skill
const NAME_CONTROL='control';const LaunchRequestHandler={ canHandle(handlerInput){return Alexa.getRequestType(handlerInput.requestEnvelope)==='LaunchRequest';},
handle: async function(handlerInput){ const request= handlerInput.requestEnvelope; const { apiEndpoint, apiAccessToken }= request.context.System; const 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 const endpointId = apiResponse.endpoints[0].endpointId || []; Util.putSessionAttribute(handlerInput, 'endpointId', endpointId); // Set skill duration to 5 minutes (ten 30-seconds interval) Util.putSessionAttribute(handlerInput, 'duration', 10); // Set the token to track the event handler const token = handlerInput.requestEnvelope.request.requestId; Util.putSessionAttribute(handlerInput, 'token', token); let speechOutput = "Welcome to The T-Shirt Folding Machine"; return handlerInput.responseBuilder .speak(speechOutput ) .addDirective(Util.buildStartEventHandler(token,60000, {})) .getResponse(); }};const FoldIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'FoldIntent'; }, handle: function (handlerInput) { const attributesManager = handlerInput.attributesManager; const endpointId = attributesManager.getSessionAttributes().endpointId || []; // Construct the directive with the payload containing the fold command const directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL, { type: 'fold' }); return handlerInput.responseBuilder .speak("Folding your T-shirt") .addDirective(directive) .getResponse(); }};const ExpiredRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'CustomInterfaceController.Expired' }, handle(handlerInput) { console.log("== Custom Event Expiration Input =="); // Set the token to track the event handler const token = handlerInput.requestEnvelope.request.requestId; Util.putSessionAttribute(handlerInput, 'token', token); const attributesManager = handlerInput.attributesManager; let duration = attributesManager.getSessionAttributes().duration || 0; if (duration > 0) { Util.putSessionAttribute(handlerInput, 'duration', --duration); // Extends skill session } else { // End skill session return handlerInput.responseBuilder .speak("Skill duration expired. Goodbye.") .withShouldEndSession(true) .getResponse(); } }};// The SkillBuilder acts as the entry point for your skill, routing all request and response// payloads to the handlers above. Make sure any new handlers or interceptors you've
// defined are included below. The order matters - they're processed top to bottom.exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( LaunchRequestHandler, FoldIntentHandler, ExpiredRequestHandler, Common.HelpIntentHandler, Common.CancelAndStopIntentHandler, Common.SessionEndedRequestHandler, Common.IntentReflectorHandler, // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers
) .addRequestInterceptors(Common.RequestInterceptor) .addErrorHandlers( Common.ErrorHandler,
) .lambda();
Alexa code
JavaScript
common.js
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* You may not use this file except in compliance with the terms and conditions
* set forth in the accompanying LICENSE.TXT file.
*
* THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
* RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
*/
'use strict'const Alexa= require('ask-sdk-core');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();}};const CancelAndStopIntentHandler={ canHandle(handlerInput){return Alexa.getRequestType(handlerInput.requestEnvelope)==='IntentRequest'&&(Alexa.getIntentName(handlerInput.requestEnvelope)==='AMAZON.CancelIntent'|| Alexa.getIntentName(handlerInput.requestEnvelope)==='AMAZON.StopIntent');},
handle(handlerInput){ const speakOutput='Goodbye!';return handlerInput.responseBuilder
.speak(speakOutput) .getResponse();}};const SessionEndedRequestHandler={ canHandle(handlerInput){return Alexa.getRequestType(handlerInput.requestEnvelope)==='SessionEndedRequest';},
handle(handlerInput){ // Any cleanup logic goes here.
return handlerInput.responseBuilder.getResponse();}};// The intent reflector is used for interaction model testing and debugging.
// It will simply repeat the intent the user said. You can create custom handlers
// for your intents by defining them above, then also adding them to the request
// handler chain below.
const IntentReflectorHandler={ canHandle(handlerInput){return Alexa.getRequestType(handlerInput.requestEnvelope)==='IntentRequest';},
handle(handlerInput){ const intentName= Alexa.getIntentName(handlerInput.requestEnvelope); const speakOutput=`You just triggered ${intentName}`;return handlerInput.responseBuilder
.speak(speakOutput) .reprompt("I don't understand this command, try again") .getResponse();}};// Generic error handling to capture any syntax or routing errors. If you receive an error
// stating the request handler chain is not found, you have not implemented a handler for// the intent being invoked or included it in the skill builder below.
const ErrorHandler={ canHandle(){return true;},
handle(handlerInput, error){ console.log(`~~~~ Error handled: ${error.stack}`); const speakOutput=`Sorry, I had trouble doing what you asked. Please try again.`;return handlerInput.responseBuilder
.speak(speakOutput) .reprompt(speakOutput) .getResponse();}};// The request interceptor is used for request handling testing and debugging.
// It will simply log the request in raw json format before any processing is performed.
const RequestInterceptor={ process(handlerInput){let{ attributesManager, requestEnvelope }= handlerInput;letsessionAttributes= attributesManager.getSessionAttributes(); // Log the request for debug purposes.
console.log(`=====Request==${JSON.stringify(requestEnvelope)}`); console.log(`=========SessionAttributes==${JSON.stringify(sessionAttributes, null, 2)}`);}};module.exports ={ HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
IntentReflectorHandler,
ErrorHandler,
RequestInterceptor
};
Alexa code
JSON
package.json
{"name":"agt-mindstorms","version":"1.1.0","description":"A sample skill demonstrating how to use AGT with Lego Mindstorms","main":"index.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"author":"Amazon Alexa","license":"ISC","dependencies":{"ask-sdk-core":"^2.6.0","ask-sdk-model":"^1.18.0","aws-sdk":"^2.326.0","request":"^2.81.0"}}
Alexa code
JavaScript
utils.js
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* You may not use this file except in compliance with the terms and conditions
* set forth in the accompanying LICENSE.TXT file.
*
* THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH
* RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
*/
'use strict';const Https= require('https');/**
* Build a custom directive payload to the gadget with the specified endpointId
* @param {string} endpointId - the gadget endpoint Id
* @param {string} namespace - the namespace of the skill
* @param {string} name - the name of the skill within the scope of this namespace
* @param {object} payload - the payload data
* @see {@link https://developer.amazon.com/docs/alexa-gadgets-toolkit/send-gadget-custom-directive-from-skill.html#respond} */
exports.build =function(endpointId, namespace, name, payload){ // Construct the custom directive that needs to be sent
// Gadget should declare the capabilities in the discovery response to
// receive the directives under the following namespace.
return{ type: 'CustomInterfaceController.SendDirective',
header: { name: name,
namespace: namespace
},
endpoint: { endpointId: endpointId
},
payload
};};/**
* A convenience routine to add the a key-value pair to the session attribute.
* @param handlerInput - the context from Alexa Service
* @param key - the key to be added
* @param value - the value be added
*/
exports.putSessionAttribute =function(handlerInput, key, value){ const attributesManager= handlerInput.attributesManager;letsessionAttributes= attributesManager.getSessionAttributes(); sessionAttributes[key]= value; attributesManager.setSessionAttributes(sessionAttributes);};/**
* To get a list of all the gadgets that meet these conditions,
* Call the Endpoint Enumeration API with the apiEndpoint and apiAccessToken to
* retrieve the list of all connected gadgets.
*
* @param {string} apiEndpoint - the Endpoint API url
* @param {string} apiAccessToken - the token from the session object in the Alexa request
* @see {@link https://developer.amazon.com/docs/alexa-gadgets-toolkit/send-gadget-custom-directive-from-skill.html#call-endpoint-enumeration-api} */
exports.getConnectedEndpoints =function(apiEndpoint, apiAccessToken){ // The preceding https:// need to be stripped off before making the call
apiEndpoint=(apiEndpoint ||'').replace('https://', '');return new Promise(((resolve, reject)=> { const options={ host: apiEndpoint,
path: '/v1/endpoints',
method: 'GET',
headers: {'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiAccessToken
}}; const request= Https.request(options, (response)=> { response.setEncoding('utf8');letreturnData=''; response.on('data', (chunk)=> {returnData+= chunk;}); response.on('end', ()=> { resolve(JSON.parse(returnData));}); response.on('error', (error)=> { reject(error);});}); request.end();}));};
ev3 code
Python
main.py
ppppppp
ev3 code
INI
main.ini
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.# # You may not use this file except in compliance with the terms and conditions # set forth in the accompanying LICENSE.TXT file.## THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH # RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING # THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.[GadgetSettings]amazonId=YOURamazonIdHEREalexaGadgetSecret=YOURalexaGadgetSecretHere[GadgetCapabilities]Custom.Mindstorms.Gadget=1.0
Comments
Please log in or sign up to comment.