Nadine Gaertner
Published © Apache-2.0

Anki Cozmo meets SAP Cloud Platform (part 1)

Connect the Anki Cozmo toy robot to the SAP Cloud Platform: send sensor data to the cloud and remote control the robot from the cloud

BeginnerFull instructions provided3 hours1,495
Anki Cozmo meets SAP Cloud Platform (part 1)

Things used in this project

Hardware components

Anki Cozmo
×1

Software apps and online services

SAP Cloud Platform IoT for the Neo environment
SAP Cloud Platform IoT for the Neo environment

Story

Read more

Code

Code snippet #1

Plain text
#!/usr/bin/env python3
import cozmo
from cozmo.util import degrees, distance_mm, speed_mmps

keep_running = None
cozmo_instance = None

def cozmo_program(robot: cozmo.robot.Robot):
    global cozmo_instance, keep_running
    cozmo_instance = robot
    keep_running = True
    while True:
        run_cozmo()

def run_cozmo():
    global keep_running
    while (keep_running):
        cozmo_instance.drive_straight(distance_mm(200), 
speed_mmps(50), 
in_parallel=True).wait_for_completed()
        cozmo_instance.turn_in_place(degrees(90), in_parallel=True).wait_for_completed()

if __name__ == "__main__":
    cozmo.run_program(cozmo_program)

Code snippet #2

Plain text
#!/usr/bin/env python3
import cozmo
from cozmo.util import degrees, distance_mm, speed_mmps

keep_running = None
cozmo_instance = None

def cozmo_program(robot: cozmo.robot.Robot):
    global cozmo_instance, keep_running
    cozmo_instance = robot
    keep_running = True
    while True:
        run_cozmo()

def run_cozmo():
    global keep_running
    while (keep_running):
        cozmo_instance.drive_straight(distance_mm(200), 
speed_mmps(50), 
in_parallel=True).wait_for_completed()
        cozmo_instance.turn_in_place(degrees(90), in_parallel=True).wait_for_completed()

if __name__ == "__main__":
    cozmo.run_program(cozmo_program)

Code snippet #3

Plain text
my_account = "iotmms<your_accountID>trial"
my_token = "<your_OAuth_token_for_the_Cozmo_device>"
my_msg_type = "<technical_ID_of_your_COZMO_POSITION_message>"
my_device = "<technical_ID_of_your_COZMO_device>"

Code snippet #4

Plain text
my_account = "iotmms<your_accountID>trial"
my_token = "<your_OAuth_token_for_the_Cozmo_device>"
my_msg_type = "<technical_ID_of_your_COZMO_POSITION_message>"
my_device = "<technical_ID_of_your_COZMO_device>"

Code snippet #5

Plain text
#!/usr/bin/env python3
import websocket
from websocket import create_connection
import json
from threading import Thread
from config import *

class websocket_scp:

    ws = None
    url = None
    auth = None

    def __init__(self):
        pass

    def on_error(self, ws, error):
        print(error)

    def on_close(self, ws):
        lambda ws: self.on_on_open(self, ws)

    def on_open(self, ws):
        def run(*args):
            pass
        thread = Thread(target=run)
        thread.start()

    def start_listener(self, on_message):
        websocket.enableTrace(True)
        global url, auth, ws
        url = "wss://%s.hanatrial.ondemand.com/com.sap.iotservices.mms/v1/api/ws/data/%s" %(my_account,my_device)
        auth = "Bearer %s" %(my_token)
        ws = websocket.WebSocketApp(url,
                                    on_message = on_message,
                                    on_error = lambda ws, error: self.on_error(ws, error),
                                    on_close = lambda ws: self.on_close(ws),
                                    header   = {"Authorization":auth})
        ws.on_open = lambda ws: self.on_open(ws)
        listenerthread = Thread(target=ws.run_forever)
        listenerthread.start()

    def send_position(self, messages):
        global ws, url, auth
        ws = create_connection(url, header = {"Authorization":auth})
        message = {"mode":"async","messageType":my_msg_type,"messages":messages}
        ws.send(json.dumps(message))

Code snippet #6

Plain text
#!/usr/bin/env python3
import websocket
from websocket import create_connection
import json
from threading import Thread
from config import *

class websocket_scp:

    ws = None
    url = None
    auth = None

    def __init__(self):
        pass

    def on_error(self, ws, error):
        print(error)

    def on_close(self, ws):
        lambda ws: self.on_on_open(self, ws)

    def on_open(self, ws):
        def run(*args):
            pass
        thread = Thread(target=run)
        thread.start()

    def start_listener(self, on_message):
        websocket.enableTrace(True)
        global url, auth, ws
        url = "wss://%s.hanatrial.ondemand.com/com.sap.iotservices.mms/v1/api/ws/data/%s" %(my_account,my_device)
        auth = "Bearer %s" %(my_token)
        ws = websocket.WebSocketApp(url,
                                    on_message = on_message,
                                    on_error = lambda ws, error: self.on_error(ws, error),
                                    on_close = lambda ws: self.on_close(ws),
                                    header   = {"Authorization":auth})
        ws.on_open = lambda ws: self.on_open(ws)
        listenerthread = Thread(target=ws.run_forever)
        listenerthread.start()

    def send_position(self, messages):
        global ws, url, auth
        ws = create_connection(url, header = {"Authorization":auth})
        message = {"mode":"async","messageType":my_msg_type,"messages":messages}
        ws.send(json.dumps(message))

Code snippet #7

Plain text
#!/usr/bin/env python3
import cozmo
from cozmo.util import degrees, distance_mm, speed_mmps
from cozmo_websocket import websocket_scp
import websocket

keep_running = None
cozmo_instance = None
ws_communicator = None

def on_message(ws, message):
    pass

def cozmo_program(robot: cozmo.robot.Robot):
    global cozmo_instance, ws_communicator, keep_running
    cozmo_instance = robot
    ws_communicator = websocket_scp()
    ws_communicator.start_listener(on_message)
    keep_running = True
    while True:
        run_cozmo()

def run_cozmo():
    global ws_communicator, keep_running
    while (keep_running):
        posX = cozmo_instance.pose.position.x
        posY = cozmo_instance.pose.position.y
        posZ = cozmo_instance.pose.position.z
        # message structure according to the IoT service message type
        messages = [{
                    'POSX': posX,
                    'POSY': posY,
                    'POSZ': posZ
                    }]
        ws_communicator.send_position(messages)
        cozmo_instance.drive_straight(distance_mm(200), speed_mmps(50), in_parallel=True).wait_for_completed()
        cozmo_instance.turn_in_place(degrees(90), in_parallel=True).wait_for_completed()

if __name__ == "__main__":
    cozmo.run_program(cozmo_program)

Code snippet #8

Plain text
#!/usr/bin/env python3
import cozmo
from cozmo.util import degrees, distance_mm, speed_mmps
from cozmo_websocket import websocket_scp
import websocket

keep_running = None
cozmo_instance = None
ws_communicator = None

def on_message(ws, message):
    pass

def cozmo_program(robot: cozmo.robot.Robot):
    global cozmo_instance, ws_communicator, keep_running
    cozmo_instance = robot
    ws_communicator = websocket_scp()
    ws_communicator.start_listener(on_message)
    keep_running = True
    while True:
        run_cozmo()

def run_cozmo():
    global ws_communicator, keep_running
    while (keep_running):
        posX = cozmo_instance.pose.position.x
        posY = cozmo_instance.pose.position.y
        posZ = cozmo_instance.pose.position.z
        # message structure according to the IoT service message type
        messages = [{
                    'POSX': posX,
                    'POSY': posY,
                    'POSZ': posZ
                    }]
        ws_communicator.send_position(messages)
        cozmo_instance.drive_straight(distance_mm(200), speed_mmps(50), in_parallel=True).wait_for_completed()
        cozmo_instance.turn_in_place(degrees(90), in_parallel=True).wait_for_completed()

if __name__ == "__main__":
    cozmo.run_program(cozmo_program)

Code snippet #9

Plain text
    {
      "path": "/iotmms",
      "target": {
        "type": "destination",
        "name": "iotmms"   	
       },
      "description": ""    
    }

Code snippet #10

Plain text
    {
      "path": "/iotmms",
      "target": {
        "type": "destination",
        "name": "iotmms"   	
       },
      "description": ""    
    }

Code snippet #11

Plain text
sap.ui.define([
		"sap/ui/core/mvc/Controller",
		"sap/m/MessageToast"
	],
	function(Controller, MessageToast) {
		"use strict";
		return Controller.extend("<your_project_name>.controller.Cozmo", {
			doHttp: function(sType, sUrl, oData, successHandler, errorHandler) {
				var jsonData;

				if (errorHandler === undefined) {
					errorHandler = function(jqXHR, textStatus, errorThrown) {};
				}

				if (oData !== undefined) {
					jsonData = JSON.stringify(oData);
				}

				jQuery.ajax({
					type: sType,
					dataType: "json",
					contentType: "application/json",
					data: jsonData,
					url: sUrl,
					error: function(jqXHR, textStatus, errorThrown) {
						if (jqXHR.status !== 0) {
							sap.m.MessageToast.show("[".concat(jqXHR.status, "] ",
								jqXHR.statusText, " ", jqXHR.responseText));
						}
						errorHandler.apply(this, [jqXHR, textStatus, errorThrown]);
					},
					statusCode: {
						0: function(jqXHR, textStatus, errorThrown) {
							sap.m.MessageToast.show("Connection refused");
						}
					},
					success: function(oData, textStatus, jqXHR) {
						if (oData === null || oData === undefined) {
							sap.m.MessageToast.show(
								"[WARNING] Received a null or undefined" +
								" response object");
							return;
						}
						successHandler.apply(this, [oData, textStatus, jqXHR]);
					}
				});
			}
		});
	});

Code snippet #12

Plain text
sap.ui.define([
		"sap/ui/core/mvc/Controller",
		"sap/m/MessageToast"
	],
	function(Controller, MessageToast) {
		"use strict";
		return Controller.extend("<your_project_name>.controller.Cozmo", {
			doHttp: function(sType, sUrl, oData, successHandler, errorHandler) {
				var jsonData;

				if (errorHandler === undefined) {
					errorHandler = function(jqXHR, textStatus, errorThrown) {};
				}

				if (oData !== undefined) {
					jsonData = JSON.stringify(oData);
				}

				jQuery.ajax({
					type: sType,
					dataType: "json",
					contentType: "application/json",
					data: jsonData,
					url: sUrl,
					error: function(jqXHR, textStatus, errorThrown) {
						if (jqXHR.status !== 0) {
							sap.m.MessageToast.show("[".concat(jqXHR.status, "] ",
								jqXHR.statusText, " ", jqXHR.responseText));
						}
						errorHandler.apply(this, [jqXHR, textStatus, errorThrown]);
					},
					statusCode: {
						0: function(jqXHR, textStatus, errorThrown) {
							sap.m.MessageToast.show("Connection refused");
						}
					},
					success: function(oData, textStatus, jqXHR) {
						if (oData === null || oData === undefined) {
							sap.m.MessageToast.show(
								"[WARNING] Received a null or undefined" +
								" response object");
							return;
						}
						successHandler.apply(this, [oData, textStatus, jqXHR]);
					}
				});
			}
		});
	});

Code snippet #13

Plain text
<mvc:View controllerName="<your_project_name>.controller.Cozmo" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true">
	<App>
		<Page title="Cozmo in the Internet of Things">
			<Panel class="sapUiResponsiveMargin" width="auto">
				<Button text="Move fork" press="onMoveFork" class="sapUiSmallMarginEnd"/>
			</Panel>
		</Page>
	</App>
</mvc:View>

Code snippet #14

Plain text
<mvc:View controllerName="<your_project_name>.controller.Cozmo" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" displayBlock="true">
	<App>
		<Page title="Cozmo in the Internet of Things">
			<Panel class="sapUiResponsiveMargin" width="auto">
				<Button text="Move fork" press="onMoveFork" class="sapUiSmallMarginEnd"/>
			</Panel>
		</Page>
	</App>
</mvc:View>

Code snippet #15

Plain text
onMoveFork: function() {
	var pushServiceUrl = "/iotmms/v1/api/http/push/<technical_ID_of_your_COZMO_device>";
	var messageObject = {
		"sender": "IoT application",
		"method": "ws",
		"messageType": "<technical_ID_of_your_TO_COZMO_message>",
		"messages": [{
			"ACTION": "1"
		}]
	};

	var successHandler = function(oData, textStatus, jqXHR) {
		sap.m.MessageToast.show("Success");
	};

	this.doHttp("POST", pushServiceUrl, messageObject, successHandler);
}

Code snippet #16

Plain text
onMoveFork: function() {
	var pushServiceUrl = "/iotmms/v1/api/http/push/<technical_ID_of_your_COZMO_device>";
	var messageObject = {
		"sender": "IoT application",
		"method": "ws",
		"messageType": "<technical_ID_of_your_TO_COZMO_message>",
		"messages": [{
			"ACTION": "1"
		}]
	};

	var successHandler = function(oData, textStatus, jqXHR) {
		sap.m.MessageToast.show("Success");
	};

	this.doHttp("POST", pushServiceUrl, messageObject, successHandler);
}

Code snippet #17

Plain text
import json

def on_message(ws, message):
    data = json.loads(message)
    action = data["messages"][0]["ACTION"]
    if action == "1":
        cozmo_instance.set_lift_height(1.0, in_parallel=True)
        cozmo_instance.set_lift_height(0.0, in_parallel=True)

Code snippet #18

Plain text
import json

def on_message(ws, message):
    data = json.loads(message)
    action = data["messages"][0]["ACTION"]
    if action == "1":
        cozmo_instance.set_lift_height(1.0, in_parallel=True)
        cozmo_instance.set_lift_height(0.0, in_parallel=True)

Github file

https://github.com/SAP/iot-starterkit/tree/master/src/apps/xs/consumption

Credits

Nadine Gaertner

Nadine Gaertner

0 projects • 8 followers

Comments