You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lights.py 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. # Copyright (c) 2016 Anki, Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License in the file LICENSE.txt or at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. '''Helper routines for dealing with Cozmo's lights and colors.'''
  15. # __all__ should order by constants, event classes, other classes, functions.
  16. __all__ = ['green', 'red', 'blue', 'white', 'off',
  17. 'green_light', 'red_light', 'blue_light', 'white_light', 'off_light',
  18. 'Color', 'Light']
  19. import copy
  20. from . import logger
  21. class Color:
  22. '''A Color to be used with a Light.
  23. Either int_color or rgb may be used to specify the actual color.
  24. Any alpha components (from int_color) are ignored - all colors are fully opaque.
  25. Args:
  26. int_color (int): A 32 bit value holding the binary RGBA value (where A
  27. is ignored and forced to be fully opaque).
  28. rgb (tuple): A tuple holding the integer values from 0-255 for (red, green, blue)
  29. name (str): A name to assign to this color
  30. '''
  31. def __init__(self, int_color=None, rgb=None, name=None):
  32. self.name = name
  33. self._int_color = 0
  34. if int_color is not None:
  35. self._int_color = int_color | 0xff
  36. elif rgb is not None:
  37. self._int_color = (rgb[0] << 24) | (rgb[1] << 16) | (rgb[2] << 8) | 0xff
  38. @property
  39. def int_color(self):
  40. '''int: The encoded integer value of the color.'''
  41. return self._int_color
  42. #: :class:`Color`: Green color instance.
  43. green = Color(name="green", int_color=0x00ff00ff)
  44. #: :class:`Color`: Red color instance.
  45. red = Color(name="red", int_color=0xff0000ff)
  46. #: :class:`Color`: Blue color instance.
  47. blue = Color(name="blue", int_color=0x0000ffff)
  48. #: :class:`Color`: White color instance.
  49. white = Color(name="white", int_color=0xffffffff)
  50. #: :class:`Color`: instance representing no color (LEDs off).
  51. off = Color(name="off")
  52. class Light:
  53. '''Lights are used with LightCubes and Cozmo's backpack.
  54. Lights may either be "on" or "off", though in practice any colors may be
  55. assigned to either state (including no color/light).
  56. '''
  57. def __init__(self, on_color=off, off_color=off, on_period_ms=250,
  58. off_period_ms=0, transition_on_period_ms=0, transition_off_period_ms=0):
  59. self._on_color = on_color
  60. self._off_color = off_color
  61. self._on_period_ms = on_period_ms
  62. self._off_period_ms = off_period_ms
  63. self._transition_on_period_ms = transition_on_period_ms
  64. self._transition_off_period_ms = transition_off_period_ms
  65. @property
  66. def on_color(self):
  67. ''':class:`Color`: The Color shown when the light is on.'''
  68. return self._on_color
  69. @on_color.setter
  70. def on_color(self, color):
  71. if not isinstance(color, Color):
  72. raise TypeError("Must specify a Color")
  73. self._on_color = color
  74. @property
  75. def off_color(self):
  76. ''':class:`Color`: The Color shown when the light is off.'''
  77. return self._off_color
  78. @off_color.setter
  79. def off_color(self, color):
  80. if not isinstance(color, Color):
  81. raise TypeError("Must specify a Color")
  82. self._off_color = color
  83. @property
  84. def on_period_ms(self):
  85. '''int: The number of milliseconds the light should be "on" for for each cycle.'''
  86. return self._on_period_ms
  87. @on_period_ms.setter
  88. def on_period_ms(self, ms):
  89. if not 0 < ms < 2**32:
  90. raise ValueError("Invalid value")
  91. self._on_period_ms = ms
  92. @property
  93. def off_period_ms(self):
  94. '''int: The number of milliseconds the light should be "off" for for each cycle.'''
  95. return self._off_period_ms
  96. @off_period_ms.setter
  97. def off_period_ms(self, ms):
  98. if not 0 < ms < 2**32:
  99. raise ValueError("Invalid value")
  100. self._off_period_ms = ms
  101. @property
  102. def transition_on_period_ms(self):
  103. '''int: The number of milliseconds to take to transition the light to the on color.'''
  104. return self._transition_on_period_ms
  105. @transition_on_period_ms.setter
  106. def transition_on_period_ms(self, ms):
  107. if not 0 < ms < 2**32:
  108. raise ValueError("Invalid value")
  109. self._transition_on_period_ms = ms
  110. @property
  111. def transition_off_period_ms(self):
  112. '''int: The number of milliseconds to take to transition the light to the off color.'''
  113. return self._transition_off_period_ms
  114. @transition_off_period_ms.setter
  115. def transition_off_period_ms(self, ms):
  116. if not 0 < ms < 2**32:
  117. raise ValueError("Invalid value")
  118. self._transition_off_period_ms = ms
  119. def flash(self, on_period_ms=250, off_period_ms=250, off_color=off):
  120. '''Convenience function to make a flashing version of an existing Light instance.
  121. Args:
  122. on_period_ms (int): The number of milliseconds the light should be "on" for for each cycle.
  123. off_period_ms (int): The number of milliseconds the light should be "off" for for each cycle.
  124. off_color (:class:`Color`): The color to flash to for the off state.
  125. Returns:
  126. :class:`Color` instance.
  127. '''
  128. flasher = copy.copy(self)
  129. flasher.on_period_ms = on_period_ms
  130. flasher.off_period_ms = off_period_ms
  131. flasher.off_color=off_color
  132. return flasher
  133. def _set_light(msg, idx, light):
  134. # For use with clad light messages specifically.
  135. if not isinstance(light, Light):
  136. raise TypeError("Expected a lights.Light")
  137. msg.onColor[idx] = light.on_color.int_color
  138. msg.offColor[idx] = light.off_color.int_color
  139. msg.onPeriod_ms[idx] = light.on_period_ms
  140. msg.offPeriod_ms[idx] = light.off_period_ms
  141. msg.transitionOnPeriod_ms[idx] = light.transition_on_period_ms
  142. msg.transitionOffPeriod_ms[idx] = light.transition_off_period_ms
  143. #There is a glitch so it will always flash unless on_color==off_color
  144. #ticket is COZMO-3319
  145. #: :class:`Light`: A steady green colored LED light.
  146. green_light = Light(on_color=green, off_color=green)
  147. #: :class:`Light`: A steady red colored LED light.
  148. red_light = Light(on_color=red, off_color=red)
  149. #: :class:`Light`: A steady blue colored LED light.
  150. blue_light = Light(on_color=blue, off_color=blue)
  151. #: :class:`Light`: A steady white colored LED light.
  152. white_light = Light(on_color=white, off_color=white)
  153. #: :class:`Light`: A steady off (non-illuminated LED light).
  154. off_light = Light(on_color=off, off_color=off)