Блог компании Microsoft

Как Avatarion использует роботов и IoT-решения, чтобы не дать заскучать детям вдали от дома

Рассказываем о том, как наша облачная платформа улучшила огромных человекоподобных роботов Avatarion, помогающих больным детям оставаться на связи с родными и близкими.

Зачем AI бизнесу?
Avatarion Technology AG — швейцарский стартап, специализирующийся на создании человекоподобных роботов на базе вертикальных решений. Основные сферы использования: здравоохранение, образование, розничная торговля и специальные мероприятия. Компания работает с двумя типами роботов от SoftBank Robotics: Нао и Пеппер (подробные описания роботов вы найдете ниже).
Самый успешный проект Avatarion — Avatar Kids — помогает детям от 4 до 18 лет, вынужденным длительное время находиться в больнице, оставаться в контакте с друзьями и семьей. Робот Avatar Hao функционирует как связующее звено между юным пациентом, школой и семьей. Проект в настоящее время включает в себя шесть больниц и 25 роботов, и эти цифры растут с каждым днем.
Что мы сделали
Чтобы понимать, насколько эффективно роботы взаимодействуют с детьми, необходимо собирать и анализировать данные. Компания нуждалась в решении, способном в режиме реального времени отображать данные:
  • об использовании робота,
  • возможных ошибках взаимодействия,
  • состоянии батареи,
  • местоположении,
  • качестве обратной связи (взаимодействия с ребенком),
  • ...и многом другом.
Для этих целей отлично подходят IoT-решения для сбора и анализа данных — оставался вопрос выбора и возможностей.
В прошлом году мы анонсировали Azure IoT Hub — облачную платформу для управления умной электроникой. Она позволяет легко взаимодействовать с устройствами и интегрируется с другими сервисами Azure. При этом можно легко ограничиться небольшим программным кодом.
Во время трехдневнего хакфеста с Avatarion мы придумали архитектуру и первую реализацию, начиная с приема данных и заканчивая их анализом в облаке. Нужно было обеспечить безопасную двухстороннюю связь с роботами, которая позволит собирать данные телеметрии, а также удаленно отправлять команды простым и эффективным способом.
Для этого мы задействовали облачное хранилище Azure SQL Database и систему Azure Stream Analytics. Обо всем по порядку.
Этапы и решения
1. Что внутри роботов
Нао
Нао — маленький робот высотой всего 58 см с приятными округлыми чертами «лица». Он дружелюбен, мил и всегда готов помочь в деле научного и технического образования. Робот пригодится для обучения и проведения исследований как школьникам, так и студентам вузов, и даже ученым.
В голове, руках и ногах Нао расположены многочисленные сенсоры и локаторы, позволяющие ему ориентироваться в пространстве. Благодаря четырем направленным микрофонам и динамикам Нао взаимодействует с людьми через диалог, он слушает и разговаривает. Робот оснащен двумя камерами, которые производят съемку в высоком разрешении, что позволяет ему распознавать фигуры и объекты.
Пеппер
Пеппер — первый персональный человекоподобный робот с эмоциями, разработанный SoftBank Robotics. Он умеет распознавать основные человеческие эмоции и адаптировать собственное поведение к настроению собеседника. Пеппер — социальный робот, способный общаться, узнавать лица, реагировать на эмоции и двигаться автономно.
Пеппер оснащен полным комплектом сенсоров: двумя ультразвуковыми передатчиками и приемниками, шестью лазерными датчиками и тремя детекторами препятствий, расположенными в его ногах. Эти датчики предоставляют ему информацию о расстоянии до ближайших объектов (диапазон 3 метра) - в дополнение к трем камерам (две камеры RGB и одна 3D-камера в голове). Датчик внутри аккумулятора определяет уровень заряда и температуру. Тактильные датчики в руках робота используются, когда он играет в игры или взаимодействует с людьми.
Оба робота работают на одной и той же ОС (NAOqi), основанной на Linux. Она обеспечивает подключение Wi-Fi, позволяя использовать код Python для отправки сообщений от робота в облако. Роботы также оснащены планшетами и мобильными телефонами, а специальное приложение-компаньон предоставляет дополнительные услуги роботу и пользователю. В нашем случае эти приложения создаются с использованием Xamarin.
2. Как обеспечить безопасность и скорость
Хотя данные телеметрии не считаются критичными, нам все же хотелось избежать возможности любого несанкционированного доступа к ним. А сообщения, отправленные из облака к роботу, как раз наоборот, должны быть защищены, чтобы избежать перехвата управления. IoT Hub обеспечивает необходимые механизмы безопасности для надежной и простой в использовании двухсторонней связи между облаком и удаленными устройствами.
Роботы подключаются к корпоративным сетям, которые обычно защищены брандмауэром, поэтому мы не можем использовать такие протоколы, как MQTT или AMQP. Для связи с роботами из облака и обратно используется протокол HTTP. В нашей версии - HTTPS-шифрование, работающее через IoT Hub.
Основное условие безопасности — роботы должны получать сообщения только от Avatarion IoT Hub, и сообщения должны быть адресованы только им. Для этого применяется механизм аутентификации и авторизации IoT Hub, по которому роботу предоставляется уникальный первичный ключ. Он хранится в самом роботе и используется для создания токенов SAS при каждом сеансе связи между роботом и хабом IoT. Наряду с уникальным URL-адресом и HTTPS-шифрованием IoT Hub гарантирует, что робот является единственным получателем сообщения, и никто не сможет отправить ему вредоносное послание. Решение также позволяет IoT Hub безошибочно идентифицировать конкретного робота, отправившего телеметрическое сообщение.
Отправка сообщения роботу через Device Explorer
3. Отправка сообщений
Для передачи данных мы решили использовать идеально подходящий под наши нужды Azure IoT Hub. Главное в этом решении — безопасная двухсторонняя связь, легкость конфигурации и обслуживания.
Через IoT Hub легко отделять процесс приема сообщений от хранения и анализа. Это упрощает обслуживание, а также позволяет развивать различные компоненты проекта независимо друг от друга. Благодаря функции хранения сообщений IoT мы можем вносить изменения без прерывания производственной среды и без риска потери данных.
IoT Hub получает первые сообщения
Для первой реализации мы решили использовать три разных типа сообщений.
Первое, содержащее информацию об ошибке, будет отправляться роботом каждый раз, когда возникает проблема.
Ошибки JSON, в частности статус приводов
09 / 02 / 2017 13: 35: 27 > Device: [python - test - device], Data: [{
   "diagnosis": "[0L, ['HeadPitch', 'HeadYaw', 'LAnklePitch', 'LAnkleRoll', 'LElbowRoll', 'LElbowYaw', 'LHipPitch', 'LHipRoll', 'LHipYawPitch', 'LKneePitch', 'LShoulderPitch', 'LShoulderRoll', 'LWristYaw', 'RAnklePitch', 'RAnkleRoll', 'RElbowRoll', 'RElbowYaw', 'RHipPitch', 'RHipRoll', 'RKneePitch', 'RShoulderPitch', 'RShoulderRoll', 'RWristYaw']]",
   "msg_type": "error",
   "datetime": "2017-02-09T13:35:28.925774"
}]
09 / 02 / 2017 13: 35: 36 > Device: [python - test - device], Data: [{
   "life_state": "disabled",
   "focused_activity": "",
   "msg_type": "state",
   "system_version": "2.1.4.13",
   "ip_address": "192.168.8.1",
   "battery_charging": false,
   "battery_charge": 88,
   "cpu": "25.7904",
   "wifi_name": "wifiname",
   "datetime": "2017-02-09T13:35:37.256762"
}]
Второе, содержащее статус робота, отправляется раз в минуту. Сообщение содержит информацию о состоянии батареи, использовании CPU и выполняемых в настоящее время действиях.
Телеметрическое сообщение JSON
09 / 02 / 2017 13: 35: 18 > Device: [python - test - device], Data: [{
   "life_state": "disabled",
   "focused_activity": "",
   "msg_type": "state",
   "system_version": "2.1.4.13",
   "ip_address": "192.168.8.1",
   "battery_charging": false,
   "battery_charge": 88,
   "cpu": "25.7645",
   "wifi_name": "wifiname",
   "datetime": "2017-02-09T13:35:19.369717"
}]
09 / 02 / 2017 13: 35: 22 > Device: [python - test - device], Data: [{
   "life_state": "disabled",
   "focused_activity": "",
   "msg_type": "state",
   "system_version": "2.1.4.13",
   "ip_address": "192.168.8.1",
   "battery_charging": false,
   "battery_charge": 88,
   "cpu": "25.7723",
   "wifi_name": "wifiname",
   "datetime": "2017-02-09T13:35:23.499632"
}]
Третье сообщение генерируется мобильными устройствами робота. Оно содержит информацию об успешном или неудачном взаимодействии с пользователем. В этом конкретном примере мы использовали QnA Maker (службу генерации ЧАВО на основе имеющегося содержимого), чтобы речь роботов была более похожа на человеческую. Беседа робота и человека ведется по наиболее часто задаваемым вопросам.
Мы отправляем вопрос, предлагаемый ответ и оценку, поступающую от движка QnA Maker. Это сообщение отправляется каждый раз, когда происходит взаимодействие.
Диалоговое сообщение
09/02/2017 13:29:49 > Device: [tablet], Data: [{
   "question": "What can you never eat for breakfast?",
   "answer": "Dinner.",
   "msg_type": "qna",
   "score": 1.0,
   "datetime": "2017-02-09T13:29:48.541994+01:00"
}]
09/02/2017 13:29:49 > Device: [tablet], Data: [{
   "question": "How can you lift an elephant with one hand?",
   "answer": "It is not a problem, since you will never find an elephant with one hand.",
   "msg_type": "qna",
   "score": 1.0,
   "datetime": "2017-02-09T13:29:48.53919+01:00"
}]
09/02/2017 13:29:49 > Device: [tablet], Data: [{
   "question": "If it took eight men ten hours to build a wall, how long would it take four men to build it?",
   "answer": "No time at all it is already built.",
   "msg_type": "qna",
   "score": 1.0,
   "datetime": "2017-02-09T13:29:46.503404+01:00"
}]
Командное сообщение, включая уведомление о доставке
Sent to Device ID: [python-test-device], Message:"rest", message Id: 752b2aae-299f-4289-bf95-6fcc3d660a80
Message Feedback status: "Success", Description: "Success", Original Message Id: 752b2aae-299f-4289-bf95-6fcc3d660a80
Нам нужно использовать механизм опроса HTTP, предлагаемый IoT Hub. Он не предназначен для использования тысячами устройств каждую минуту, потому что после этого сработало бы ограничение защиты HTTP от IoT Hub. Но в нашем случае роботов далеко не так много, поэтому с уверенностью можем использовать этот механизм опроса каждую минуту.
Чтобы иметь возможность принимать несколько команд, не дожидаясь 1-минутного интервала опроса, после получения первого сообщения мы меняем интервал опроса на роботе с 1 минуты до 5 секунд в течение последующих 10 минут.
4. Какие SDK и языки использовать?
Возможности наших роботов могут быть расширены через Python. Существует Python SDK для Azure IoT, но для использования этого решения потребовалась бы установка модулей на роботе. Мы хотим избежать дополнительных модулей в целях экономии и простоты использования. Поэтому было решено использовать API IoT REST непосредственно из нашего решения на Python. Мы изменили образец кода Microsoft, добавив в него функцию приема сообщений.
Следующий код содержит все функции отправки, приема и подтверждения сообщений:
Все функции отправки, приема и подтверждения сообщений
""" 
Module Name: d2cMsgSender.py 
Project: IoTHubRestSample 
Copyright (c) Microsoft Corporation. 
This source is subject to the Microsoft Public License. 
See http://www.microsoft.com/en-us/openness/licenses.aspx#MPL 
All other rights reserved. 
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 
"""
	
	import base64
	import hmac
	import hashlib
	import time
	import requests
	import urllib
	
	class D2CMsgSender:
	
	API_VERSION = '2016-02-03'
	TOKEN_VALID_SECS = 10
	TOKEN_FORMAT = 'SharedAccessSignature sig=%s&se=%s&sr=%s'
	
	def __init__(self, connectionString=None):
    	if connectionString != None:
        	iotHost, keyName, keyValue = [sub[sub.index('=') + 1:] for sub in connectionString.split(";")]
        	self.iotHost = iotHost
        	self.keyName = keyName
        	self.keyValue = keyValue
        	
	def _buildExpiryOn(self):
    	return '%d' % (time.time() + self.TOKEN_VALID_SECS)
	
	def _buildIoTHubSasToken(self, deviceId):
    	resourceUri = '%s/devices/%s' % (self.iotHost, deviceId)
    	targetUri = resourceUri.lower()
    	expiryTime = self._buildExpiryOn()
    	toSign = '%s\n%s' % (targetUri, expiryTime)
    	key = base64.b64decode(self.keyValue.encode('utf-8'))
    	signature = urllib.quote(
        	base64.b64encode(
            	hmac.HMAC(key, toSign.encode('utf-8'), hashlib.sha256).digest()
        	)
    	).replace('/', '%2F')
    	return self.TOKEN_FORMAT % (signature, expiryTime, targetUri)
	
	def sendD2CMsg(self, deviceId, message):
    	sasToken = self._buildIoTHubSasToken(deviceId)
    	global log
    	log.info("SAS TOKEN " + str(sasToken))
    	url = 'https://%s/devices/%s/messages/events?api-version=%s' % (self.iotHost, deviceId, self.API_VERSION)
    	r = requests.post(url, headers={'Authorization': sasToken}, data=message)
    	return r.text, r.status_code
    	
	def getD2CMsg(self, deviceId):
    	sasToken = self._buildIoTHubSasToken(deviceId)
    	url = 'https://%s/devices/%s/messages/devicebound?api-version=%s' % (self.iotHost, deviceId, self.API_VERSION)
    	r = requests.get(url, headers={'Authorization': sasToken})
    	#return r.text, r.status_code
    	return r
    	
	def completeD2CMsg(self, etag):
    	sasToken = self._buildIoTHubSasToken(deviceId)
    	url = 'https://%s/devices/%s/messages/devicebound/%s?api-version=%s' % (self.iotHost, deviceId, etag, self.API_VERSION)
    	global log
    	log.info(url)
    	r = requests.delete(url, headers={'Authorization': sasToken})
    	return r
    	
	def rejectD2CMsg(self, etag):
    	sasToken = self._buildIoTHubSasToken(deviceId)
    	url = 'https://%s/devices/%s/messages/devicebound/%s?reject&api-version=%s' % (self.iotHost, deviceId, etag, self.API_VERSION)
    	global log
    	log.info(url)
    	r = requests.delete(url, headers={'Authorization': sasToken})
    	return r
	d2cMsgSender = None
	connectionString = "HostName=xxxxxxx.azure-devices.net;DeviceId=python-test-device;SharedAccessKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
	deviceId = 'python-test-device'
	log = None
	
	def init(logger):
	global d2cMsgSender
	global log
	d2cMsgSender = D2CMsgSender(connectionString)
	log = logger
	#print d2cMsgSender.getD2CMsg(deviceId)
	
	def send(message):
	return d2cMsgSender.sendD2CMsg(deviceId, message)
	
	def get():
	return d2cMsgSender.getD2CMsg(deviceId)
	
	def complete(etag):
	return d2cMsgSender.completeD2CMsg(etag)
	
	def reject(etag):
	return d2cMsgSender.rejectD2CMsg(etag)
Для кода Xamarin на планшете мы используем мастер от Visual Studio (функция «Добавить подключенные сервисы»), который находит необходимые библиотеки и генерирует код для взаимодействия с хабом IoT.
Модифицированный код, созданный мастером
using System;
	using System.Text;
	using System.Threading.Tasks;
	using Microsoft.Azure.Devices.Client;
	using IotTest;
	
	static class AzureIoTHub
	{
   	
		const string deviceConnectionString = "HostName=xxxxx.azure-devices.net;DeviceId=tablet;SharedAccessKey=xxxxxxxxxxxxxxxxxxxxxxxxx";
	    	
		public static async Task SendDeviceToCloudMessageAsync(IotPayload pl)
		{
			var deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Http1);
			
			var str = Newtonsoft.Json.JsonConvert.SerializeObject(pl);
			var message = new Message(Encoding.ASCII.GetBytes(str));
			
			await deviceClient.SendEventAsync(message);
		}
	
	
	}
	public class IotPayload
	{
		public String question { get; set; }
		public String answer{ get; set; }
		public String msg_type { get; set; }
		public double score{ get; set; }
		public DateTime datetime { get; set; }
	}
Для быстрого анализа сообщений JSON и сохранения их в нескольких таблицах SQL Database мы решили использовать Azure Stream Analytics. Это позволило расширить схему и обработку сообщений. Кроме того, с помощью Stream Analytics мы можем практически в реальном времени обнаруживать аномалии, связанные с повторяющимися движениями роботов, что чревато их перегревом. Такая задача решается очень просто: в запросе используем функцию Tumbling Windows.
В следующем примере показано, как мы извлекаем идентификатор устройства из сообщения IoT Hub и определяем тип сообщения:
SELECT
IoTHub.ConnectionDeviceId as device_id,
ip_address,
datetime,
life_state,
focused_activity,
system_version,
battery_charging,
battery_charge,
CAST(cpu as bigint) as cpu,
wifi_name
INTO
[RobotStatus]
FROM
[RobotIOTHub]
WHERE msg_type = 'state';
SELECT
IoTHub.ConnectionDeviceId as device_id,
diagnosis,
datetime
INTO
[RobotError]
FROM
[RobotIOTHub]
WHERE msg_type = 'error';
SELECT
IoTHub.ConnectionDeviceId as device_id,
question,
answer,
score,
datetime
INTO
[RobotQNA]
FROM
[RobotIOTHub]
WHERE msg_type = 'qna';
Чтобы быстро создавать отчеты для Avatarion и пользователей, мы решили использовать Power BI. Благодаря ему мы можем генерировать комплексные интерактивные информационные табло с жизненно важными данными роботов. Функция «Опубликовать в Web» позволяет интегрировать панель в клиентские порталы.
Преодолеваем сложности
Благодаря REST API можно использовать IoT Hub с любой платформы. Мы хотели избежать необходимости установки или компиляции дополнительных модулей. В случае отправки сообщений пользоваться REST API из Python легко. Но принимать сообщения оказалось несколько сложнее из-за реализации шаблона поиска. Приходилось выполнять поиск сообщений, а также подтверждать завершение, отклонение или отказ.
Идентификатор блокировки сообщения (представленный заголовком etag полученного сообщения) необходимо отправить в ответ на запрос о завершении, отклонении или отказе, как указано в записи блога Complete/Reject/Abandon — Part 2 of MKR1000 Azure IoT Hub Interface Using HTTP.
Далее показано, как код Python передается роботу:
Возможности развития
Роботы работают несколько часов в день, поэтому подвержены аппаратным проблемам — особенно перегреву моторов. Именно здесь пригодятся полученные данные — их можно использовать в модели машинного обучения для того, чтобы спрогнозировать необходимость обслуживания. Это позволит избежать возможного сбоя оборудования.
Это первый проект предполагаемой модели машинного обучения:
Во время хакфеста мы изучали возможности по улучшению функциональности роботов через Cognitive Services, Language Understanding и ботов. К примеру, в случае использования робота для сценариев продаж он должен уметь отвечать на часто задаваемые вопросы. С помощью функций speech-to-text и text-to-speech мы можем зафиксировать проходящие через QnA Maker вопросы конечных пользователей и подготовить наилучшие ответы.
Вызов «шуточного» QnA Maker
Вот первый пример реализации QnA Maker:
protected async Task<QnAMakerResult> PostQNAQueryAsync(string customerquery)
	{
		string responseString;
var query = customerquery; //User Query 		
var knowledgebaseId = "xxxxxxxxxxxxxx"; // Use knowledge base id created. 	var qnamakerSubscriptionKey = "xxxxxxxxxxxxxxxxxxxxxxxxxx"; //Use subscription key assigned to you. 																	
		Uri qnamakerUriBase = new Uri("https://westus.api.cognitive.microsoft.com/qnamaker/v1.0");
		var builder = new UriBuilder($"{qnamakerUriBase}/knowledgebases/{knowledgebaseId}/generateAnswer");
		//Add the question as part of the body 		
var postBody = $"{{\"question\": \"{query}\"}}";
		//Set the encoding to UTF8 		
var content = new StringContent(postBody, Encoding.UTF8, "application/json");		
		//Send the POST request 		
HttpClient client = new HttpClient();
		client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", qnamakerSubscriptionKey);
		HttpResponseMessage response = await client.PostAsync(builder.ToString(), content);
		if(response.IsSuccessStatusCode)
		{
			responseString = await response.Content.ReadAsStringAsync();
			return JsonConvert.DeserializeObject<QnAMakerResult>(responseString);
		}
		return null;
	}
И это только начало. Использование Language Understanding Intelligent Service (LUIS) позволило бы нам улучшить диалоговые возможности робота. А такие функции, как узнавание собеседника, анализ настроения, распознавание лиц и эмоций — способны вывести возможности роботов на новый уровень.
Заключение
В ходе трехдневного хакфеста мы заложили основы решения и выработали концепцию, которая охватывает внедрение данных, их хранение и анализ, безопасную двунаправленную связь. Эти основы станут фундаментом для разработки новых функциональных возможностей роботов. Решение можно развить для приема новых типов сообщений, реализовать дополнительные функции мониторинга и статистики.
IoT Hub оказался простым в использовании сервисом, который позволил нам создать масштабируемую и безопасную двунаправленную связь между роботами и облаком. И все это без огромных дополнительных вложений на кодирование, аппаратное и программное обеспечение. Простое техническое обслуживание этого PaaS-решения также было ключевым фактором при выборе технологии.
Теперь Avatarion может постоянно наблюдать за своими роботами, получать информацию об их использовании и дистанционно управлять ими, как в случае необходимости устранения неполадок, так и для регулярного обслуживания.
Мощная комбинация IoT Hub, Stream Analytics, SQL Database и Power BI позволяет Avatarion поддерживать активно расширяющийся парк роботов, экономя при этом время и деньги. А клиенты, к примеру, персонал больницы, может следить за использованием роботов, которые помогают больным детям оставаться на связи со школой и семьями.
Ключевые технологии
Основная команда
Avatarion:
  • Жан Кристоф Гостанян — генеральный директор
  • Тобиас Кифер — технический директор
  • Джессика Айхберг — разработчик
Microsoft Switzerland:
  • Ронни Сауренманн — технический евангелист
  • Кен Казада — технический евангелист
Комментарии 0

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.