×

GRIPP3R助手机器人开源分享

消耗积分:0 | 格式:zip | 大小:68.97 MB | 2022-12-16

张鑫

分享资料个

描述

介绍:

根据美国国立卫生研究院的说法,“健忘可能是衰老的正常部分。” 最重要的是,老年人也经常随着年龄的增长而面临身体衰退。这些问题会导致一些问题,从忘记物品在哪里,到在获取药品或手杖等基本物品时体力消耗。

到目前为止,机器人护理已经作为宠物产品进入老年人市场,以类似的硬件和成本,我们实际上可以构建机器人来为老年人做更多的事情。在本文中,我们将讨论如何使用Lego Mindstorm EV3机器人帮助老年人存储和取物。

第 1 步:构建 GRIPP3R

pYYBAGOYmCCALSmPAAQSanugeDk703.png
GRIPP3R 机器人
 

MindStorm EV3 的 GRIPP3R 似乎是处理此类任务的最理想机器人,因为我们可以构建机器人并用它来抓取物体。使用乐高 MindStorm 套装搭建机器人大约需要 2-3 小时,但实际上只需要说明书的前 68 页,因为其他所有内容都非常美观。

机器人完全建成后,我们首先需要测试一些基础知识以确保其正常运行。我们可以在https://www.lego.com/en-us/themes/mindstorms/downloads下载 MindStorms Home并使用基本功能。我们的第一个测试是看看我们正在尝试做的事情是否可能,下面是我们编写的一个简单的小程序,用来抓取东西,转身走开。

poYBAGOYmCOAZzVHAADItJCT9MQ527.png
乐高程序
 

运行此程序时,您应该看到下图,计算机运行程序需要接线,我们最终产品不需要接线。现在完成了,我们可以进入下一步。

GRIPP3R 夹持

第 2 步:准备好开发环境

Alexa gadget 编写了有关如何将 Alexa 与 Mindstorm 连接的完整设置指南,我们将只强调这一步的主要部分,强烈建议您通过那里设置环境。

设置GRIPP3R 端

在这一步中,我们使用 Visual Studio Code 和 EV3DEV 环境设置乐高头脑风暴环境。具体要了解的东西很少。

如果砖面朝下,USB 端口和 sd 卡位于积木的左侧,如果面向您,则位于机器人的左侧。这花了一点时间来弄清楚。

pYYBAGOYmCWAcoVaAAClngMkOuQ069.jpg
SD 卡和 USB 端口
 

我们现在可以插入 SD 卡并启动 EV3,我们可以从 ev3dev 菜单设置 WiFi 网络。

pYYBAGOYmCeAfriCAAAeXiw-a7M827.png
 

这将允许我们将 Visual Studio Code 直接连接到 ev3,而不是使用 USB 线。连接后请记住我们稍后可能需要的 ip,确保您的计算机与 ev3 砖在同一网络上。

在 Mac/PC 端设置

我们需要可以在下载的 Microsoft VS Code。 您可以打开alexa-gadgets-mindstorms文件夹以安装ev3dev-browser扩展,如AlexaGadget的环境设置指南中所述

pYYBAGOYmCmAEDZeAAA73K221XA793.png
扩展推荐
 

单击显示推荐后,它应显示在左侧,如下所示。

pYYBAGOYmC6AJVvAAABjOvzjA8s963.png
VS 代码
 

我们可以启动一个名为grapp3r helper 的新工作区,并有一些空文件,或者只是从源代码下载我的代码。现在我们将做GRIPP3R端,我们可以连接到wifi而不是做USB编程。单击此处连接我的设备后,应该会显示 ev3dev,如果没有,您可以通过“我没有看到我的设备”手动输入 ip

poYBAGOYmDOAOZJKAAKRH4mRWGk166.png
VS Code 连接到 ev3
 

单击浏览器上的下载按钮以测试它是否有效。如果它正常工作,所有东西都应该加载到 ev3 砖中,我们都准备好进行环境设置了。

poYBAGOYmDWAOSoLAAAzew-QaVk532.png
下载按钮
 

由于我们将使用蓝牙来控制设备,因此我们也在这里启用蓝牙。

pYYBAGOYmDyADQ9hAAB3nObL-68746.png
来自alexagadget任务1的蓝牙连接
 

第 3 步:准备 Alexa 语音服务

这一步紧跟 alexagadget 的使命 1 ,我建议您仔细阅读该指南,让您的积木准备好响应 Alexa 的呼叫。我们将通过总结。

我们首先需要亚马逊开发者账号如果您还没有开发者帐户,请注册一个。我们需要在Alexa Voice Service 中创建一个产品。

pYYBAGOYmD6AHWaEAABUCkf8I1M394.png
亚历克斯服务
 

保持简单,让我们使用与来自 alexagadget 的 Mission 1 相同的产品来创建产品。

  • 名称:头脑风暴 EV3
  • 产品编号:EV3_01
  • 产品类型:Alexa小工具
  • 产品类别:Animatronic 或 Figure
  • 产品描述:随心所欲
  • 跳过上传图片
  • 您是否打算将该产品进行商业销售?:
  • 这是儿童产品还是以其他方式针对 13 岁以下的儿童?:

创建产品后,我们将拥有应用程序 ID 和应用程序密码。

poYBAGOYmECAdH4bAACjCramGUc235.png
应用 ID 和应用机密
 

我们将使用 alexamission-01 作为测试平台,为此我们只需用您自己的方式更改 id 和 secret,请确保不需要引号。

[GadgetSettings]
amazonId = YOUR_GADGET_AMAZON_ID
alexaGadgetSecret = YOUR_GADGET_SECRET

[GadgetCapabilities]
Alexa.Gadget.StateListener = 1.0 - wakeword

我们可以像上一步一样上传代码,完整的代码解释位于任务 01本身。

poYBAGOYmDWAOSoLAAAzew-QaVk532.png
下载
 

为了执行代码,我们将做一些与alexa gadget不同的事情,执行这些代码需要一些时间,有时我们会等待挂起而不知道原因。我们可以通过 shell 终端本身手动完成。

poYBAGOYmEiAdkizAABeFlIhzMo310.png
打开外壳终端
 

之后,我们可以像任何其他 linux 一样执行我们的文件。

pYYBAGOYmEuAY3auAADYFCBXAKU441.png
连接到 Alexa
 

此时我们可以使用 GRIPP3R 本身激活 alexa 唤醒词。

 

第 4 步:构建 Alexa 应用程序

这一步紧密总结了alexagadget的使命3使命4 ,因为我们需要可以构建alexa app的基本功能。

我们需要在 alexa 控制台下创建一个新技能,为了保持一致,我们将其命名为 mindstorms,就像任务一样。

pYYBAGOYmE-AeAguAAHrFvkTaCw177.png
创造技能
 

我们将通过 node js 使用自定义和 Alexa 托管的后端,这只是为了在您执行任务时保持一致性,并使编写不同的程序更容易

pYYBAGOaaAqAMzRhAAJXqIQis0c576.png
创建 Alexa 技能
 

我们可以从任务 4 上传 JSON 文件并从那里构建它。只是不要发射任何大炮,因为 GRIPP3R 电机无法处理。获取 json 复制并粘贴后,单击构建模型继续。

poYBAGOaaA6APmRzAAPyiiyTq3U032.png
JSON文件
 

这给了我们足够的能力来做以下事情,我们稍后会谈到这些。

  • 意图名称(MoveIntent、SetSpeedIntent、SetCommandIntent)
  • 插槽名称(方向、持续时间、速度、命令)
  • 槽值(“前进”、“后退”、“1”、“2”、“100”)

在这些构建完成后,我们将把任务 4 的所有文件上传到 Alexa 代码屏幕中的 lambda 中。详细代码说明可以看这里

pYYBAGOaaBGAfJ3MAASOKTAGBLs203.png
Alexa技能代码
 

之后,我们可以进入测试模式,为“开发”启用技能测试

poYBAGOaaBWAEIXLAAE9VARIAPQ003.png
开发技能测试
 

至于代码,您可以上传代码库,也可以按照任务 4 中的代码立即进行测试。

#!/usr/bin/env python3
# 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.
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, OUTPUT_C, MoveTank, SpeedPercent, MediumMotor
from ev3dev2.sensor.lego import InfraredSensor
# 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 Direction(Enum):
"""
The list of directional commands and their variations.
These variations correspond to the skill slot values.
"""
FORWARD = ['forward', 'forwards', 'go forward']
BACKWARD = ['back', 'backward', 'backwards', 'go backward']
LEFT = ['left', 'go left']
RIGHT = ['right', 'go right']
STOP = ['stop', 'brake', 'halt']
class Command(Enum):
"""
The list of preset commands and their invocation variation.
These variations correspond to the skill slot values.
"""
MOVE_CIRCLE = ['circle', 'move around']
MOVE_SQUARE = ['square']
SENTRY = ['guard', 'guard mode', 'sentry', 'sentry mode']
PATROL = ['patrol', 'patrol mode']
FIRE_ONE = ['cannon', '1 shot', 'one shot']
FIRE_ALL = ['all shots', 'all shot']
class EventName(Enum):
"""
The list of custom event name sent from this gadget
"""
SENTRY = "Sentry"
PROXIMITY = "Proximity"
SPEECH = "Speech"
class MindstormsGadget(AlexaGadget):
"""
A Mindstorms gadget that can perform bi-directional interaction with an Alexa skill.
"""
def __init__(self):
"""
Performs Alexa Gadget initialization routines and ev3dev resource allocation.
"""
super().__init__()
# Robot state
self.sentry_mode = False
self.patrol_mode = False
# Connect two large motors on output ports B and C
self.drive = MoveTank(OUTPUT_B, OUTPUT_C)
self.weapon = MediumMotor(OUTPUT_A)
self.sound = Sound()
self.leds = Leds()
self.ir = InfraredSensor()
# Start threads
threading.Thread(target=self._patrol_thread, daemon=True).start()
threading.Thread(target=self._proximity_thread, daemon=True).start()
def on_connected(self, device_addr):
"""
Gadget connected to the paired Echo device.
:param device_addr: the address of the device we connected to
"""
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.
:param device_addr: the address of the device we disconnected from
"""
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), file=sys.stderr)
control_type = payload["type"]
if control_type == "move":
# Expected params: [direction, duration, speed]
self._move(payload["direction"], int(payload["duration"]), int(payload["speed"]))
if control_type == "command":
# Expected params: [command]
self._activate(payload["command"])
except KeyError:
print("Missing expected parameters: {}".format(directive), file=sys.stderr)
def _move(self, direction, duration: int, speed: int, is_blocking=False):
"""
Handles move commands from the directive.
Right and left movement can under or over turn depending on the surface type.
:param direction: the move direction
:param duration: the duration in seconds
:param speed: the speed percentage as an integer
:param is_blocking: if set, motor run until duration expired before accepting another command
"""
print("Move command: ({}, {}, {}, {})".format(direction, speed, duration, is_blocking), file=sys.stderr)
if direction in Direction.FORWARD.value:
self.drive.on_for_seconds(SpeedPercent(speed), SpeedPercent(speed), duration, block=is_blocking)
if direction in Direction.BACKWARD.value:
self.drive.on_for_seconds(SpeedPercent(-speed), SpeedPercent(-speed), duration, block=is_blocking)
if direction in (Direction.RIGHT.value + Direction.LEFT.value):
self._turn(direction, speed)
self.drive.on_for_seconds(SpeedPercent(speed), SpeedPercent(speed), duration, block=is_blocking)
if direction in Direction.STOP.value:
self.drive.off()
self.patrol_mode = False
def _activate(self, command, speed=50):
"""
Handles preset commands.
:param command: the preset command
:param speed: the speed if applicable
"""
print("Activate command: ({}, {})".format(command, speed), file=sys.stderr)
if command in Command.MOVE_CIRCLE.value:
self.drive.on_for_seconds(SpeedPercent(int(speed)), SpeedPercent(5), 12)
if command in Command.MOVE_SQUARE.value:
for i in range(4):
self._move("right", 2, speed, is_blocking=True)
if command in Command.PATROL.value:
# Set patrol mode to resume patrol thread processing
self.patrol_mode = True
if command in Command.SENTRY.value:
self.sentry_mode = True
self._send_event(EventName.SPEECH, {'speechOut': "Sentry mode activated"})
# Perform Shuffle posture
self.drive.on_for_seconds(SpeedPercent(80), SpeedPercent(-80), 0.2)
time.sleep(0.3)
self.drive.on_for_seconds(SpeedPercent(-40), SpeedPercent(40), 0.2)
self.leds.set_color("LEFT", "YELLOW", 1)
self.leds.set_color("RIGHT", "YELLOW", 1)
if command in Command.FIRE_ONE.value:
print("Fire one", file=sys.stderr)
self.weapon.on_for_rotations(SpeedPercent(100), 3)
self._send_event(EventName.SENTRY, {'fire': 1})
self.sentry_mode = False
print("Sent sentry event - 1 shot, alarm reset", file=sys.stderr)
self.leds.set_color("LEFT", "GREEN", 1)
self.leds.set_color("RIGHT", "GREEN", 1)
if command in Command.FIRE_ALL.value:
print("Fire all", file=sys.stderr)
self.weapon.on_for_rotations(SpeedPercent(100), 10)
self._send_event(EventName.SENTRY, {'fire': 3})
self.sentry_mode = False
print("sent sentry event - 3 shots, alarm reset", file=sys.stderr)
self.leds.set_color("LEFT", "GREEN", 1)
self.leds.set_color("RIGHT", "GREEN", 1)
def _turn(self, direction, speed):
"""
Turns based on the specified direction and speed.
Calibrated for hard smooth surface.
:param direction: the turn direction
:param speed: the turn speed
"""
if direction in Direction.LEFT.value:
self.drive.on_for_seconds(SpeedPercent(0), SpeedPercent(speed), 2)
if direction in Direction.RIGHT.value:
self.drive.on_for_seconds(SpeedPercent(speed), SpeedPercent(0), 2)
def _send_event(self, name: EventName, payload):
"""
Sends a custom event to trigger a sentry action.
:param name: the name of the custom event
:param payload: the sentry JSON payload
"""
self.send_custom_event('Custom.Mindstorms.Gadget', name.value, payload)
def _proximity_thread(self):
"""
Monitors the distance between the robot and an obstacle when sentry mode is activated.
If the minimum distance is breached, send a custom event to trigger action on
the Alexa skill.
"""
count = 0
while True:
while self.sentry_mode:
distance = self.ir.proximity
print("Proximity: {}".format(distance), file=sys.stderr)
count = count + 1 if distance < 10 else 0
if count > 3:
print("Proximity breached. Sending event to skill", file=sys.stderr)
self.leds.set_color("LEFT", "RED", 1)
self.leds.set_color("RIGHT", "RED", 1)
self._send_event(EventName.PROXIMITY, {'distance': distance})
self.sentry_mode = False
time.sleep(0.2)
time.sleep(1)
def _patrol_thread(self):
"""
Performs random movement when patrol mode is activated.
"""
while True:
while self.patrol_mode:
print("Patrol mode activated randomly picks a path", file=sys.stderr)
direction = random.choice(list(Direction))
duration = random.randint(1, 5)
speed = random.randint(1, 4) * 25
while direction == Direction.STOP:
direction = random.choice(list(Direction))
# direction: all except stop, duration: 1-5s, speed: 25, 50, 75, 100
self._move(direction.value[0], duration, speed)
time.sleep(duration)
time.sleep(1)
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")

和ini文件

[GadgetSettings]
amazonId = amazonid
alexaGadgetSecret = secret
[GadgetCapabilities]
Custom.Mindstorms.Gadget = 1.0

这应该使我们能够控制机器人。我们将通过与下面相同的 shell 运行。完成后,您应该能够控制机器人。

 

第 5 步:设置 Gripper Bot Alexa 端

现在是时候编写机器人逻辑了。为了完成这个项目,我们需要机器人做 3 件事,来,拿东西,拿东西,按照从最简单到最难的顺序。这转化为 ComeIntent、TakeIntent、BringIntent

在这一步中,我们将更改整个项目,因此以前的任务现在不是很有用。我们可以使用下面的json文件。其中一个重要的变化是“invocationName”:“gripper bot” ,所以我们可以调用gripper bot来帮助我们在Alexa中

{
"interactionModel": {
"languageModel": {
"invocationName": "gripper bot",
"intents": [
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "HelloWorldIntent",
"slots": [],
"samples": [
"hello",
"how are you",
"say hi world",
"say hi",
"hi",
"say hello world",
"say hello"
]
},
{
"name": "ComeIntent",
"slots": [],
"samples": [
"Come",
"Come to me",
"Come here"
]
},
{
"name": "TakeIntent",
"slots": [
{
"name": "Item",
"type": "ItemType"
}
],
"samples": [
"Take this",
"Take it",
"Take this item",
"Take this {Item}",
"Take the {Item}"
]
},
{
"name": "BringIntent",
"slots": [
{
"name": "Item",
"type": "ItemType"
}
],
"samples": [
"Bring me the stuff",
"Bring me my item",
"Fetch my stuff",
"Bring me my {Item}"
]
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
}
],
"types": [
{
"name": "ItemType",
"values": [
{
"name": {
"value": "bottle"
}
},
{
"name": {
"value": "cane"
}
},
{
"name": {
"value": "medicine"
}
},
{
"name": {
"value": "cup"
}
}
]
}
]
}
}
}

至于lamdba 中的index.js ,我们基于任务 4 添加了额外的 3 个 Intent,这很重要,因为我们将这些意图传递给了抓取机器人本身。

// Construct and send a custom directive to the connected gadget with data from
// the ComeIntent.
const ComeIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'ComeIntent';
},
handle: function (handlerInput) {
const attributesManager = handlerInput.attributesManager;
let endpointId = attributesManager.getSessionAttributes().endpointId || [];
let speed = "50";
// Construct the directive with the payload containing the move parameters
let directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
{
type: 'come',
command: 'come',
speed: speed
});
let speechOutput = 'Gripper Bot is coming to you';
return handlerInput.responseBuilder
.speak(speechOutput + BG_MUSIC)
.addDirective(directive)
.getResponse();
}
};
// Construct and send a custom directive to the connected gadget with data from
// the BringIntent.
const BringIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'BringIntent';
},
handle: function (handlerInput) {
let command = Alexa.getSlotValue(handlerInput.requestEnvelope, 'Item');
if (command === "" || command === null)
command = "it to you";
else{
command = command + " to you"
}
const attributesManager = handlerInput.attributesManager;
let endpointId = attributesManager.getSessionAttributes().endpointId || [];
let speed = attributesManager.getSessionAttributes().speed || "50";
// Construct the directive with the payload containing the move parameters
let directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
{
type: 'bring',
command: command,
speed: speed
});
let speechOutput = 'bringing ' + command;
return handlerInput.responseBuilder
.speak(speechOutput + BG_MUSIC)
.addDirective(directive)
.getResponse();
}
};
// Construct and send a custom directive to the connected gadget with data from
// the BringIntent.
const TakeIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'TakeIntent';
},
handle: function (handlerInput) {
let command = Alexa.getSlotValue(handlerInput.requestEnvelope, 'Item');
if (command === "" || command === null)
command = "the item";
const attributesManager = handlerInput.attributesManager;
let endpointId = attributesManager.getSessionAttributes().endpointId || [];
let speed = attributesManager.getSessionAttributes().speed || "50";
// Construct the directive with the payload containing the move parameters
let directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
{
type: 'take',
command: command,
speed: speed
});
let speechOutput = 'taking ' + command;
return handlerInput.responseBuilder
.speak(speechOutput + BG_MUSIC)
.addDirective(directive)
.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,
ComeIntentHandler,
TakeIntentHandler,
BringIntentHandler,
EventsReceivedRequestHandler,
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();

完整代码可以在代码上传端看到

第 6 步:编写 GRIPP3R 辅助机器人逻辑

我们需要套件不附带的陀螺仪传感器(如果您有它,它包含在核心教育套件中)。我们可以在没有它的情况下做到这一点,但是没有它来计时 180 度转弯是相当不准确的。

from ev3dev2.sensor.lego import GyroSensor
self.gyro = GyroSensor()
pYYBAGOaaBiABAY4AABEoNOwaac473.png
乐高陀螺
 

这里有 4 个主要的代码审查,首先来。下面的代码很简单。

当 ComeIntent 让 Robot 来找我们时,它会启动 _come 向前移动。并且当红外传感器检测到任何低于55的东西时,它会停止,当机器人停止时,它会打开把手,等待物品。

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), file=sys.stderr)
control_type = payload["type"]
if control_type == "move":
# Expected params: [direction, duration, speed]
self._move(payload["direction"], int(payload["duration"]), int(payload["speed"]))
elif control_type == "come":
self._come()
elif control_type == "take":
self._take()
elif control_type == "bring":
self._bring()
except KeyError:
print("Missing expected parameters: {}".format(directive), file=sys.stderr)
def _come(self, duration=10, speed=50):
self.leds.set_color("LEFT", "GREEN", 1)
self.leds.set_color("RIGHT", "GREEN", 1)
self.isComing = True
self._move(Direction.FORWARD.value[0], duration, speed)

def _proximity_thread(self):
"""
Monitors the distance between the robot and an obstacle when sentry mode is activated.
If the minimum distance is breached, send a custom event to trigger action on
the Alexa skill.
"""
if distance <= 55:
"""
When the bot is coming, it will stop and open up it's arm
"""
if self.isComing == True:
self.isComing = False
print("Proximity breached, stopping")
self._move(Direction.STOP.value[0], 0, 0,)
self.leds.set_color("LEFT", "RED", 1)
self.leds.set_color("RIGHT", "RED", 1)
while not self.touch.is_pressed:
self.grip.on_for_degrees(SpeedPercent(10), -90)
print("Lowered the grip")
 

对于接下来的 2 个部分,我们需要转动,在红外距离传感器的同一线程下,我们还将检测转动,我们将电机移动得非常慢,以便我们可以检测到准确的角度,每当它达到 180 度时,机器人就会停止,继续执行下一个状态。

self.gyro.reset()
self.isTurning = True
self.gyro.mode = 'GYRO-RATE'
self.gyro.mode = 'GYRO-ANG'
self.drive.on_for_seconds(SpeedPercent(4), SpeedPercent(-4), 40, block=False)

if self.isTurning == True:
print("angle: {}".format(angle), file=sys.stderr)
self.leds.set_color("LEFT", "YELLOW", 1)
self.leds.set_color("RIGHT", "YELLOW", 1)
if abs(angle) >= 179 or abs(angle) <= -181:
self.isTurning = False
self._move(Direction.STOP.value[0], 0, 0,)
self.gyro.reset()
self.gyro.mode = 'GYRO-RATE'
self.gyro.mode = 'GYRO-ANG'
self.leds.set_color("LEFT", "GREEN", 1)
self.leds.set_color("RIGHT", "GREEN", 1)

当 TakeIntent 从服务器被命中时,我们将命中 _take 函数。它将抓住物品,转动 180 度,然后前往基地。当红外传感器击中时,它会掉落物品,后退一秒钟并转回 180 度。

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), file=sys.stderr)
control_type = payload["type"]
if control_type == "move":
# Expected params: [direction, duration, speed]
self._move(payload["direction"], int(payload["duration"]), int(payload["speed"]))
elif control_type == "come":
self._come()
elif control_type == "take":
self._take()

def _take(self, duration=10, speed=50):
self.grip.on_for_rotations(SpeedPercent(100), 1)
self.leds.set_color("LEFT", "GREEN", 1)
self.leds.set_color("RIGHT", "GREEN", 1)
self.gyro.reset()
self.gyro.mode = 'GYRO-RATE'
self.gyro.mode = 'GYRO-ANG'
self.isTurning = True
self.drive.on_for_seconds(SpeedPercent(4), SpeedPercent(-4), 40)
self.isTaking = True
self.drive.on_for_seconds(SpeedPercent(50), SpeedPercent(50), duration)

elif self.isTaking ==True:
self.isTaking = False
print("Proximity breached, stopping")
self._move(Direction.STOP.value[0], 0, 0,)
self.leds.set_color("LEFT", "RED", 1)
self.leds.set_color("RIGHT", "RED", 1)
while not self.touch.is_pressed:
self.grip.on_for_degrees(SpeedPercent(10), -90)
print("Dropping Item")
self.drive.on_for_seconds(SpeedPercent(-50), SpeedPercent(-50), 1)
self.gyro.reset()
self.isTurning = True
self.gyro.mode = 'GYRO-RATE'
self.gyro.mode = 'GYRO-ANG'
self.drive.on_for_seconds(SpeedPercent(4), SpeedPercent(-4), 40, block=False)
self.leds.set_color("LEFT", "GREEN", 1)
self.leds.set_color("RIGHT", "GREEN", 1)
 

BringIntent 是最复杂的一个。一旦将控制权传递给机器人,我们首先调用_bring函数,它会转180度,步行1秒并抓住物品,然后它会转180度,来到我们身边,一旦通过红外传感器检测到我们,它就会下降物品和走回来的时间与它走到我们身边的时间相同。

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), file=sys.stderr)
control_type = payload["type"]
if control_type == "move":
# Expected params: [direction, duration, speed]
self._move(payload["direction"], int(payload["duration"]), int(payload["speed"]))
elif control_type == "come":
self._come()
elif control_type == "take":
self._take()
elif control_type == "bring":
self._bring()

def _bring(self, duration=10):
self.isTurning = True
self.gyro.mode = 'GYRO-RATE'
self.gyro.mode = 'GYRO-ANG'
self.drive.on_for_seconds(SpeedPercent(4), SpeedPercent(-4), 40)
self.drive.on_for_seconds(SpeedPercent(50), SpeedPercent(50), 1)
self.grip.on_for_rotations(SpeedPercent(100), 1)
self.isTurning = True
self.gyro.mode = 'GYRO-RATE'
self.gyro.mode = 'GYRO-ANG'
self.drive.on_for_seconds(SpeedPercent(4), SpeedPercent(-4), 40)
self.isBringing = True
self.now = time.time()
self.drive.on_for_seconds(SpeedPercent(50), SpeedPercent(50), duration)
self.leds.set_color("LEFT", "GREEN", 1)
self.leds.set_color("RIGHT", "GREEN", 1)

def _proximity_thread(self):
if distance <= 55:
elif self.isBringing ==True:
self.isBringing = False
print("Proximity breached, stopping")
self._move(Direction.STOP.value[0], 0, 0)
self.later = time.time()
self.leds.set_color("LEFT", "RED", 1)
self.leds.set_color("RIGHT", "RED", 1)
while not self.touch.is_pressed:
self.grip.on_for_degrees(SpeedPercent(10), -90)
print("Dropping Item")
difference = int(self.later - self.now)
self.drive.on_for_seconds(SpeedPercent(-50), SpeedPercent(-50), difference)\
 

第 7 步:演示!

通过这 3 个功能,我们基本上可以让机器人为我们存储物品,并在我们需要时获取物品。该机器人能够存储从药瓶到奶瓶的任何东西。这些功能对行动不便的老年人特别有帮助。

 

我们在 300 美元以下构建了所有这些,您绝对可以按照指南在 20 小时内完成。这是一个开源项目,我们可以改进这些功能并在未来帮助老年人。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !