/examples/tutorials/05_async_python/02_cube_blinker.py

https://github.com/anki/cozmo-python-sdk · Python · 104 lines · 75 code · 2 blank · 27 comment · 3 complexity · 4f6d2de7ef54b766511be1e276684f14 MD5 · raw file

  1. #!/usr/bin/env python3
  2. # Copyright (c) 2016 Anki, Inc.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License in the file LICENSE.txt or at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. '''Cube Blinker asynchronous example
  16. Cozmo first looks around for a cube. Once a cube is found,
  17. the cube's lights blink green in a circular fashion. The
  18. script then waits for the cube to be tapped.
  19. '''
  20. import asyncio
  21. import sys
  22. import cozmo
  23. class BlinkyCube(cozmo.objects.LightCube):
  24. '''Subclass LightCube and add a light-chaser effect.'''
  25. def __init__(self, *a, **kw):
  26. super().__init__(*a, **kw)
  27. self._chaser = None
  28. def start_light_chaser(self):
  29. '''Cycles the lights around the cube with 1 corner lit up green,
  30. changing to the next corner every 0.1 seconds.
  31. '''
  32. if self._chaser:
  33. raise ValueError("Light chaser already running")
  34. async def _chaser():
  35. while True:
  36. for i in range(4):
  37. cols = [cozmo.lights.off_light] * 4
  38. cols[i] = cozmo.lights.green_light
  39. self.set_light_corners(*cols)
  40. await asyncio.sleep(0.1, loop=self._loop)
  41. self._chaser = asyncio.ensure_future(_chaser(), loop=self._loop)
  42. def stop_light_chaser(self):
  43. if self._chaser:
  44. self._chaser.cancel()
  45. self._chaser = None
  46. # Make sure World knows how to instantiate the subclass
  47. cozmo.world.World.light_cube_factory = BlinkyCube
  48. async def cozmo_program(robot: cozmo.robot.Robot):
  49. '''The async equivalent of 01_cube_blinker_sync.
  50. The usage of ``async def`` makes the cozmo_program method a coroutine.
  51. Within a coroutine, ``await`` can be used. With ``await``, the statement
  52. blocks until the request being waited for has completed. Meanwhile
  53. the event loop continues in the background.
  54. For instance, the statement
  55. ``await robot.world.wait_for_observed_light_cube(timeout=60)``
  56. blocks until Cozmo discovers a light cube or the 60 second timeout
  57. elapses, whichever occurs first.
  58. Likewise, the statement ``await cube.wait_for_tap(timeout=10)``
  59. blocks until the tap event is received or the 10 second timeout occurs,
  60. whichever occurs first.
  61. For more information, see
  62. https://docs.python.org/3/library/asyncio-task.html
  63. '''
  64. cube = None
  65. look_around = robot.start_behavior(cozmo.behavior.BehaviorTypes.LookAroundInPlace)
  66. try:
  67. cube = await robot.world.wait_for_observed_light_cube(timeout=60)
  68. except asyncio.TimeoutError:
  69. print("Didn't find a cube :-(")
  70. return
  71. finally:
  72. look_around.stop()
  73. cube.start_light_chaser()
  74. try:
  75. print("Waiting for cube to be tapped")
  76. await cube.wait_for_tap(timeout=10)
  77. print("Cube tapped")
  78. except asyncio.TimeoutError:
  79. print("No-one tapped our cube :-(")
  80. finally:
  81. cube.stop_light_chaser()
  82. cube.set_lights_off()
  83. cozmo.run_program(cozmo_program)