Skip to content

Commit

Permalink
today
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreaCensi committed Mar 12, 2019
1 parent 7b73f88 commit ab9d7fb
Show file tree
Hide file tree
Showing 23 changed files with 784 additions and 281 deletions.
3 changes: 3 additions & 0 deletions minimal-nodes-stubs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@
build:
make -C dummy_image_source build
make -C dummy_image_filter build
make -C dummy_simulator build
make -C random_agent build

build-no-cache:
make -C dummy_image_source build-no-cache
make -C dummy_image_filter build-no-cache
make -C dummy_simulator build-no-cache
make -C random_agent build-no-cache


push:
make -C dummy_image_source push
make -C dummy_image_filter push
make -C dummy_simulator push
make -C random_agent push

test-all_connected:
Expand Down
1 change: 1 addition & 0 deletions minimal-nodes-stubs/dummy_image_filter/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM python:3.7
WORKDIR /project

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
Expand Down
1 change: 1 addition & 0 deletions minimal-nodes-stubs/dummy_image_source/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM python:3.7
WORKDIR /project

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
Expand Down
3 changes: 3 additions & 0 deletions minimal-nodes-stubs/dummy_simulator/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**
!*.py
!requirements.txt
11 changes: 11 additions & 0 deletions minimal-nodes-stubs/dummy_simulator/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM python:3.7
WORKDIR /project

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt



COPY . .

ENTRYPOINT ["python3", "dummy_simulator.py"]
20 changes: 20 additions & 0 deletions minimal-nodes-stubs/dummy_simulator/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
repo=aidonode-dummy_simulator
# repo=$(shell basename -s .git `git config --get remote.origin.url`)
branch=$(shell git rev-parse --abbrev-ref HEAD)
tag=duckietown/$(repo):$(branch)

build:
docker build -t $(tag) .

build-no-cache:
docker build -t $(tag) --no-cache .

push: build
docker push $(tag)

test-data1-direct:
./dummy_simulator.py < test_data/in1.json > test_data/out1.json

test-data1-docker:
docker run -i $(tag) < test_data/in1.json > test_data/out1.json

114 changes: 114 additions & 0 deletions minimal-nodes-stubs/dummy_simulator/dummy_simulator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env python3
from dataclasses import dataclass

import numpy as np

from aido_node_wrapper import wrap_direct, Context
from aido_schemas import JPGImage, Duckiebot1Observations, Duckiebot1Commands
from aido_schemas.protocol_simulator import SetMap, SpawnRobot, RobotName, StateDump, Step, RobotInterfaceDescription, \
RobotObservations, RobotState, protocol_simulator, SetRobotCommands, RobotPerformance, Metric, PerformanceMetrics


# Specialize to our datatype
@dataclass
class MySetRobotCommands(SetRobotCommands):
robot_name: RobotName
t_effective: float
commands: Duckiebot1Commands


@dataclass
class MyRobotObservations(RobotObservations):
observations: Duckiebot1Observations


class DummySimulator:
""" A dummy simulator implementation. """
current_time: float
robot_name: str

def init(self, context: Context):
context.log('init()')

def on_received_seed(self, context, data: int):
context.log(f'seed({data})')

def on_received_clear(self, context):
context.log(f'clear()')

def on_received_set_map(self, context, data: SetMap):
context.log(f'set_map({data})')
# TODO: load map

def on_received_spawn_robot(self, data: SpawnRobot):
self.robot_name = data.robot_name
# TODO: set pose of robot

def on_received_get_robot_interface_description(self, context, data: RobotName):
rid = RobotInterfaceDescription(robot_name=data, observations=Duckiebot1Observations,
commands=Duckiebot1Commands)
context.write('robot_interface_description', rid)

def on_received_get_robot_performance(self, context, data: RobotName):
context.log(f'get_robot_interface_description()')
metrics = {}
metrics['reward'] = Metric(higher_is_better=True, cumulative_value=self.current_time,
description="Dummy reward equal to survival time.")
pm = PerformanceMetrics(metrics)
rid = RobotPerformance(robot_name=data, t_effective=self.current_time, performance=pm)
context.write('robot_performance', rid)

def on_received_start_episode(self, context):
context.log(f'start_episode()')
self.current_time = 0

def on_received_step(self, context, data: Step):
context.log(f'step({data})')
self.current_time = data.until

def on_received_set_robot_commands(self, context, data: MySetRobotCommands):
context.log(f'set_robot_commands({data})')

def on_received_get_robot_observations(self, context, data: RobotName):
context.log(f'get_robot_observation({data!r})')
camera = get_random_image(shape=(200, 300))
obs = Duckiebot1Observations(camera)
ro = MyRobotObservations(obs)
context.write('robot_observations', ro, with_schema=True)

def on_received_get_robot_state(self, context, data: RobotName):
context.log(f'get_robot_state({data!r})')
rs = RobotState(robot_name=data, t_effective=self.current_time, state=None)
context.write('robot_state', rs)

def on_received_dump_state(self, context):
context.log(f'dump_state()')
context.write('dump_state', StateDump(None))


def get_random_image(shape):
H, W = shape
values = (128 + np.random.randn(H, W, 3) * 60).astype('uint8')
jpg_data = bgr2jpg(values)
image = JPGImage(jpg_data)
return image


# noinspection PyUnresolvedReferences
def bgr2jpg(image_cv) -> bytes:
import cv2
compress = cv2.imencode('.jpg', image_cv)[1]
jpg_data = np.array(compress).tostring()
return jpg_data


def main():
node = DummySimulator()
protocol = protocol_simulator
protocol.inputs['set_robot_commands'] = MySetRobotCommands
protocol.outputs['robot_observations'] = MyRobotObservations
wrap_direct(node=node, protocol=protocol)


if __name__ == '__main__':
main()
7 changes: 7 additions & 0 deletions minimal-nodes-stubs/dummy_simulator/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-e git://github.com/duckietown/aido-protocols.git@v4-devel3#egg=aido-protocols
-e git://github.com/AndreaCensi/zuper_utils.git@v4-devel#egg=zuper_utils

numpy==1.16.2


opencv-python==4.0.0.21
4 changes: 4 additions & 0 deletions minimal-nodes-stubs/dummy_simulator/test_data/in1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{"compat": ["aido2"], "topic": "seed", "data": 12}
{"compat": ["aido2"], "topic": "clear"}
{"compat": ["aido2"], "topic": "set_map", "data": {"map_data": "TBD"}}
{"compat": ["aido2"], "topic": "spawn_robot", "data": {"robot_name": "ego", "configuration": {"pose": null, "velocity": null }}}
1 change: 1 addition & 0 deletions minimal-nodes-stubs/random_agent/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM python:3.7
WORKDIR /project

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
Expand Down
15 changes: 10 additions & 5 deletions minimal-nodes-stubs/random_agent/random_agent.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/usr/bin/env python3


import numpy as np

from aido_node_wrapper import wrap_direct, Context
from aido_schemas import PWMCommands, protocol_agent_jpg_pwm, EpisodeStart
from aido_schemas import EpisodeStart, protocol_agent_duckiebot1, PWMCommands, Duckiebot1Commands, LEDSCommands, RGB


class RandomAgent:
Expand All @@ -13,20 +15,23 @@ def init(self, context: Context):
def on_received_episode_start(self, context: Context, data: EpisodeStart):
context.log(f'Starting episode "{data.episode_name}".')

def on_received_camera_image(self, context: Context):
def on_received_observations(self, context: Context):
pwm_left = np.random.uniform(0.0, 1.0)
pwm_right = np.random.uniform(0.0, 1.0)

commands = PWMCommands(motor_left=pwm_left, motor_right=pwm_right)
context.write('pwm_commands', commands)
grey = RGB(0, 0, 0)
led_commands = LEDSCommands(grey, grey, grey, grey, grey)
pwm_commands = PWMCommands(motor_left=pwm_left, motor_right=pwm_right)
commands = Duckiebot1Commands(pwm_commands, led_commands)
context.write('commands', commands)

def finish(self, context: Context):
context.log('finish()')


def main():
node = RandomAgent()
protocol = protocol_agent_jpg_pwm
protocol = protocol_agent_duckiebot1
wrap_direct(node=node, protocol=protocol)


Expand Down
10 changes: 10 additions & 0 deletions src/aido_node_wrapper/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
import logging

from aido_nodes import logger as aido_nodes_logger

logger = aido_nodes_logger.getChild('wrapper')

logger_interaction = logger.getChild("interaction")

logger_interaction.setLevel(logging.CRITICAL)

from .wrapper import *
13 changes: 13 additions & 0 deletions src/aido_node_wrapper/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@


ENV_NAME = 'AIDONODE_NAME'
ENV_DATA_IN = 'AIDONODE_DATA_IN'
ENV_DATA_OUT = 'AIDONODE_DATA_OUT'
ENV_META_IN = 'AIDONODE_META_IN'
ENV_META_OUT = 'AIDONODE_META_OUT'
ENV_TRANSLATE = 'AIDONODE_TRANSLATE'
ENV_ENCODING = 'AIDONODE_ENCODING'
ENV_ENCODING_JSON = 'json'
ENV_ENCODING_CBOR = 'cbor'
ENV_ENCODING_VALID = [ENV_ENCODING_JSON, ENV_ENCODING_CBOR]
KNOWN = [ENV_DATA_IN, ENV_DATA_OUT, ENV_META_IN, ENV_META_OUT, ENV_NAME, ENV_TRANSLATE, ENV_ENCODING]
17 changes: 3 additions & 14 deletions src/aido_node_wrapper/identify.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ def describe_bd(nd: BuildDescription):
def describe_cd(nd: ConfigDescription):
s = []
for f in dataclasses.fields(nd.config):

# for k, v in nd.config.__annotations__.items():
# for k, v in nd.config.__annotations__.items():
s.append('%20s: %s = %s' % (f.name, f.type, f.default))
if not s:
return 'No configuration switches available.'
Expand Down Expand Up @@ -97,15 +96,6 @@ class NodeInfo:


def identify_command(command) -> NodeInfo:
# "describe_config": type(None),
#
# "set_config": SetConfig,
#
# "describe_protocol": type(None),
#
# "describe_node": type(None),
#
# "describe_build": type(None),
d = [{'topic': 'wrapper.describe_protocol'},
{'topic': 'wrapper.describe_config'},
{'topic': 'wrapper.describe_node'},
Expand All @@ -116,10 +106,9 @@ def identify_command(command) -> NodeInfo:
p['compat'] = ['aido2']
to_send += (json.dumps(p) + '\n').encode('utf-8')
cp = subprocess.run(command, input=to_send, capture_output=True)
# f = open('/dev/stderr', 'wb')
s = cp.stderr.decode('utf-8')
# f.write(cp.stderr)
sys.stderr.write(indent(s.strip(), '|', ' stderr: |') +'\n\n')

sys.stderr.write(indent(s.strip(), '|', ' stderr: |') + '\n\n')
# noinspection PyTypeChecker
f = BufferedReader(BytesIO(cp.stdout))
stream = read_cbor_or_json_objects(f)
Expand Down
25 changes: 24 additions & 1 deletion src/aido_node_wrapper/meta_protocol.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import Any, List
from typing import *

from aido_nodes import InteractionProtocol

Expand Down Expand Up @@ -31,6 +31,29 @@ class ProtocolDescription:
data: InteractionProtocol
meta: InteractionProtocol

@dataclass
class CommsHealth:
# ignored because not compatible
ignored: Dict[str, int]
# unexpected topics
unexpected: Dict[str, int]
# malformed data
malformed: Dict[str, int]
# if we are completely lost
unrecoverable_protocol_error: bool


@dataclass
class NodeHealth:
# there is a critical error that makes it useless to continue
critical: bool
# severe problem but we can continue
severe: bool
# a minor problem to report
minor: bool

details: str


LogEntry = str

Expand Down

0 comments on commit ab9d7fb

Please sign in to comment.