| # Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Provide interfaces to initialize and read Whale color sensor.""" |
| |
| import ast |
| import logging |
| |
| import factory_common # pylint: disable=W0611 |
| import cros.factory.test.fixture.bft_fixture as bft |
| |
| # shortcut |
| BFT = bft.BFTFixture |
| |
| |
| class ColorSensor(object): |
| """Whale color sensor.""" |
| |
| # mapping from color names in bft.conf to BFTFixture.LEDColor |
| _COLOR_NAMES = { |
| 'red': BFT.LEDColor.RED, |
| 'green': BFT.LEDColor.GREEN, |
| 'yellow': BFT.LEDColor.YELLOW, |
| 'blue': BFT.LEDColor.BLUE |
| } |
| |
| # config names |
| _CONFIG_TIMING = 'color_sensor_timing' |
| _CONFIG_GAIN = 'color_sensor_gain' |
| _CONFIG_COLOR = 'color_sensor_color' |
| _REQUIRED_PARAMS = (_CONFIG_TIMING, _CONFIG_GAIN, _CONFIG_COLOR) |
| |
| def __init__(self, servo, sensor_index, params): |
| """Constructor. |
| |
| Args: |
| servo: ServoClient object. |
| sensor_index: Index of color sensor (starting from 1). |
| params: Parameters loaded from bft.conf. |
| """ |
| # Verify parameters first because it's easy to make mistakes. |
| for config in self._REQUIRED_PARAMS: |
| if config not in params: |
| raise ValueError('Missing parameter %s' % config) |
| if sensor_index not in params[config]: |
| raise ValueError('Parameter %s does not contain sensor index %d' % |
| (config, sensor_index)) |
| for color_name in params[self._CONFIG_COLOR][sensor_index]: |
| if color_name not in self._COLOR_NAMES: |
| raise ValueError('Unsupport color name %s in parameters' % color_name) |
| |
| # Initialize the color sensor hardware. |
| if sensor_index == 1: |
| servo.whale_color1_timing = ( |
| params[self._CONFIG_TIMING][sensor_index]) |
| servo.whale_color1_gain = params[self._CONFIG_GAIN][sensor_index] |
| else: |
| raise ValueError('Sensor index %s is unsupported' % sensor_index) |
| |
| self._servo = servo |
| self._sensor_index = sensor_index |
| self._color_params = params[self._CONFIG_COLOR][sensor_index] |
| |
| @classmethod |
| def HasRequiredParams(cls, params): |
| """Checks if params has required parameters. |
| |
| Args: |
| params: a dict contains parameters |
| |
| Returns: |
| True if params contains all required parameters. |
| """ |
| return all(p in params for p in cls._REQUIRED_PARAMS) |
| |
| @staticmethod |
| def _CompareHue(hue1, hue2, tolerance): |
| """Compares hue values. |
| |
| Because hue value is cyclic from 0.0 to 1.0. It treats values close to 0.0 |
| in similar way to values close to 1.0. |
| |
| Args: |
| hue1: First hue value. |
| hue2: Second hue value. |
| tolerance: Allowed difference between hue[12]. |
| |
| Returns: |
| Whether hue1 and hue2 are close enough. |
| """ |
| return (abs(hue1 - hue2) <= tolerance or |
| abs(hue1 - hue2 - 1.0) <= tolerance or |
| abs(hue1 - hue2 + 1.0) <= tolerance) |
| |
| def ReadColor(self): |
| """Reads color value from sensor. |
| |
| Returns: |
| BFTFixture.LEDColor; BFTFixture.LEDColor.OFF if no color is detected. |
| """ |
| if self._sensor_index == 1: |
| # Servo returns a string containing list expression. |
| read_h, read_s, read_v = ast.literal_eval(self._servo.whale_color1_HSV) |
| else: |
| raise ValueError('Sensor index %s is unsupported' % self._sensor_index) |
| logging.info('Read Hue=%.3f, Saturation=%.3f, Lightness=%.3f', |
| read_h, read_s, read_v) |
| |
| for color_name in self._color_params: |
| thresholds = self._color_params[color_name] |
| color_hue = thresholds['hue'] |
| hue_tolerance = thresholds['hue_tolerance'] |
| min_saturation = thresholds['min_saturation'] |
| min_lightness = thresholds['min_lightness'] |
| if (self._CompareHue(read_h, color_hue, hue_tolerance) and |
| read_s >= min_saturation and read_v >= min_lightness): |
| logging.info('Match color %s with HSV criteria ' |
| '(%.3f +/- %.3f, >= %.3f, >= %.3f)', color_name, |
| color_hue, hue_tolerance, min_saturation, min_lightness) |
| return self._COLOR_NAMES[color_name] |
| |
| logging.info('Do not match any color') |
| return BFT.LEDColor.OFF |