Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:iot-open:practical:hardware:sut:esp32:emb9b_1 [2024/02/28 21:21] – [Steps] pczekalskien:iot-open:practical:hardware:sut:esp32:emb9b_1 [2025/04/28 20:34] (current) – [FAQ] pczekalski
Line 1: Line 1:
-====== EMB9B: Use of RGB LEDs ===== +====== EMB9B: Reading colour sensor ===== 
-This scenario presents how to handle the brightness control of the tri-coloured LEDsOne is observable via cameraas presented in the figure (component 9A), while another is hidden inside the black enclosure and lights a colour sensor (component 9B)Both LEDs are electrically bound and cannot be controlled independently. Those LEDs have 3 colour channels, controlled independentlyR (Red), G (Green) and B (Blue)Mixing of those colours creates other ones, such as pink and violet. Each R G B channel can be controlled with a separate GPIO to switch it on or off or control brightness using a PWM signal, as presented in this tutorial.+A colour sensor (TCS 34725) can detect the brightness and colour of the light emittedIt works with the I2C; in our laboratoryeach sensor has a fixed 0x29 address in the I2C bus. The sensor is in the black enclosure, ensuring no ambient light impacts readingsThe only light source is an RGB LED, controlled as described in the scenario [[en:iot-open:practical:hardware:sut:esp32:emb9a_1|]]This is another LED connected parallel to the one you can observe in the camera.
  
 ===== Prerequisites ===== ===== Prerequisites =====
-A good understanding of the PWM signal and duty cycle is necessary. We also use built-in timers to control the PWM hardware channels of the ESP32 chip. In this casewe do not use an external library; insteadwe use built-in tools in the Arduino framework for ESP32 so that no additional libraries will be included in the project.+To implement this scenario, it is necessary to get familiar with at least one of the following scenarios first: 
 +  * [[en:iot-open:practical:hardware:sut:esp32:emb5_1|]], 
 +  * [[en:iot-open:practical:hardware:sut:esp32:emb6_1|]], 
 +  * [[en:iot-open:practical:hardware:sut:esp32:emb7_1|]], 
 +and obligatory: 
 +  * [[en:iot-open:practical:hardware:sut:esp32:emb9a_1|]].
  
 +A good understanding of the hardware timers is essential if you plan to use asynchronous programming (see note below). Consider getting familiar with the following:
 +  * [[en:iot-open:practical:hardware:sut:esp32:adv1_1|]].
 +
 +To simplify TCS sensor use, we will use a dedicated library:
 +<code bash>
 +lib_deps = adafruit/Adafruit TCS34725@^1.4.2
 +</code>
 +<note important>Also, remember to add the LCD handling library, as present in the EMB9 scenario, unless you decide to use another output device.</note>
 ===== Suggested Readings and Knowledge Resources ===== ===== Suggested Readings and Knowledge Resources =====
   * [[en:iot-open:introductiontoembeddedprogramming2:cppfundamentals]]   * [[en:iot-open:introductiontoembeddedprogramming2:cppfundamentals]]
   * [[en:iot-open:hardware2:esp32|]]   * [[en:iot-open:hardware2:esp32|]]
-  * [[en:iot-open:hardware2:actuators_light|]] 
   * [[en:iot-open:practical:hardware:sut:esp32|]]   * [[en:iot-open:practical:hardware:sut:esp32|]]
-  * [[en:iot-open:embeddedcommunicationprotocols2:pwm|]]+  * [[en:iot-open:embeddedcommunicationprotocols2:twi|]] 
 +  * [[en:iot-open:hardware2:sensors_optical|]] 
 +  * [[https://cdn-shop.adafruit.com/datasheets/TCS34725.pdf|TCS sensor documentation]]
 ===== Hands-on Lab Scenario ===== ===== Hands-on Lab Scenario =====
  
 ==== Task to be implemented ==== ==== Task to be implemented ====
-Implement program that will light LEDs consecutively with R, G, and BUse 50% of the maximum brightnessUse a PWM signal to control each GPIO for R, G and B, each colour separately to let you easily observe it.+Create solution where you control an RGB LED and read its colour and brightness using a TCS sensorPresent results on the LCD, e.g. in the form of "Colour: <value>" where "value" refers to the colour intensity. You should change LED brightness at least 10 times (10 different brightness) for each colour while continuously reading the TCS sensor and presenting data in the LCD. Experiment with mixing colours and check either the sensor can distinguish brightness separately, when i.e. both RGD LED's colours are on: Red+Green or Red+Blue (or any other combination you wish). 
 + 
 +<note tip>There are at least two ways to handle this task: 
 +  * simple: a dummy loop where you set RGB LED values, read from TCS and display on LCD, 
 +  * advanced: where the data is read and presented on the LCD in one or two asynchronous routines run by timers. 
 +</note> 
  
 ==== Start ==== ==== Start ====
-Assuming you will use 8-bit PWM resolution, the minimum value is 0, and the max (full brightness) is 255Note that full brightness may be too bright for the observation camera, so consider using a range between 0 and 60 (eventually up to 100).+Check if you can see the LCD and RGB LED in the camera view 
 +<note important>Remember not to use the full brightness of the RGB LED because you won'be able to observe other elements due to the camera's low dynamics. Assuming you use 8-bit PWM to control LEDwe suggest a range between 0 and 60 (eventually 0 and 100), but never up to 255.</note>
  
 ==== Steps ==== ==== Steps ====
-To use PWM in ESP32it is best to use built-in ''ledc*'' functions [[https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/ledc.html|LEDC documentation on the ESP32 manufacturer's page]]. +In the steps belowwe present only the part for reading from the TCS sensorControl of RGB LED with PWM and handling LCD is presented in the other lab scenarios that you need to follow accordingly and merge with the code below. 
-The ''leds'' use timers and have channels attached to the timerWe will use 1 channel per colour (R, G and B, so 3 in total). A PWM frequency is controlled with the timer to be shared for all 3 R, G and B channels. Channels control the PWM duty cycle.+
 === Step 1 === === Step 1 ===
-Define some parameters, including channel numbers, PWM resolution (here 8-bit) and PWM frequency (5000Hz):+Included necessary libraries:
 <code c> <code c>
-#define RGBLED_B_PIN 26 +#include <Wire.h> 
-#define RGBLED_G_PIN 21 +#include "Adafruit_TCS34725.h"
-#define RGBLED_R_PIN 33 +
- +
-#define PWM1_Ch    5 +
-#define PWM2_Ch    6 +
-#define PWM3_Ch    7 +
- +
-#define PWM_Res   8 +
-#define PWM_Freq  5000+
 </code> </code>
-GPIO pins controlling  LEDS are 33 (Red), 21 (Green) and 26 (Blue), respectively. 
  
 === Step 2 === === Step 2 ===
-Initialise 3 channels for PWM and make them dark:+Declare and instantiate the TCS controller class and related variables for readings:
 <code c> <code c>
-    ledcSetup(PWM1_Ch, PWM_Freq, PWM_Res); +#define SCL 4 
-    ledcSetup(PWM2_Ch, PWM_Freq, PWM_Res); +#define SDA 5 
-    ledcSetup(PWM3_Ch, PWM_Freq, PWM_Res); + 
-    ledcAttachPin(RGBLED_R_PINPWM1_Ch); +static Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_300MSTCS34725_GAIN_1X); 
-    ledcAttachPin(RGBLED_G_PINPWM2_Ch); +uint16_t rgbccolorTemp, lux
-    ledcAttachPin(RGBLED_B_PINPWM3_Ch); +static bool isTCSOk = false;
-    delay(100); +
-    ledcWrite(PWM1_Ch,0); +
-    ledcWrite(PWM2_Ch,0)+
-    ledcWrite(PWM3_Ch,0);+
 </code> </code>
-To control the LED (via PWM), use ''ledcWrite(PWM_Channelduty_cycle_value);''.+A word of explanation regarding the parameters:  
 +  * ''TCS34725_INTEGRATIONTIME_300MS'' is the time in ms while the TCS sensor is exposed for the light to grab readings, 
 +  * ''TCS34725_GAIN_1X'' is the sensor's gain - it helps reading in low light, but that is not true in our lab as our RGB LED light sensor is very bright, even in low duty cycle. 
 + 
 +Refer to the Q&A section for the ranges 
 === Step 3 === === Step 3 ===
-Write a loop for each colour (R, G, then B) to light the colour from dark to max value (60 or 100, give it a test). +Initialise the sensor (in ''void Setup()'') and check it is OK:
-<note important> Full duty cycle (255will be too bright for the remote access video camera to handle it. Use some reasonable range such as 0..60 or 0..100 is strongly advised.</note> +
-Mind to compose code to increase and decrease each colour. A hint is below (PWM Channel 3 so that controls Blue):+
 <code c> <code c>
-  // Increase brightness +  Wire.begin(SDA,SCL);
-  for (int dutyCycle = 0; dutyCycle <= 100; dutyCycle++) { +
-    // Gradually increase duty cycle for Red LED +
-    ledcWrite(PWM3_ChdutyCycle); +
-    delay(20); // Delay for smooth transition +
-  } +
   delay(100);   delay(100);
 +  ...
  
-  // Decrease brightness +  isTCSOk = tcs.begin()
-  for (int dutyCycle = 100dutyCycle >= 0; dutyCycle--) { +</code> 
-    // Gradually decrease duty cycle for Red LED +You communicate with the TCS sensor via the I2C interface. In standard and typical configurationsthere is no need to instantiate the ''Wire'' I2C communication stack explicitly, nor provide a default I2C address of the TCS sensor (0x29), so ''begin'' is parameterless. Other overloaded functions for the ''begin'' let you provide all technical parameters.
-    ledcWrite(PWM3_ChdutyCycle); +
-    delay(20); // Delay for smooth transition +
-  }+
  
 +<note important>You need to initialise the I2C bus only once. If you're using other I2C devices in parallel, do not call ''Wire.begin(...)'' multiple times.</note>
 +
 +=== Step 4 ===
 +Besides reading raw values for channels R, G, B and C, the ''tcs'' controller class provides additional functions to calculate colour temperature (in K) and colour intensity in Luxes.
 +
 +To read, use the following code:
 +<code c>
 +  if(isTCSOk)
 +  {
 +    tcs.getRawData(&r, &g, &b, &c);
 +    colorTemp = tcs.calculateColorTemperature_dn40(r, g, b, c);
 +    lux = tcs.calculateLux(r, g, b);
 +  }
 </code> </code>
 +R, G, and B reflect filtered values for Red, Green and Blue, respectively, while C (clear) is a non-filtered read that reflects brightness. Please be aware that there is no straightforward relation between R, G, B and C channels. 
  
-<note>There is a number of handy functions in the ''ledc'' library, including (among others): 
-  * ''analogWrite(pin,value);'' to keep compatibility with genuine Arduino, 
-  * ''ledcFade(pin, start_dutycycle, end_dutycycle, fade_time_ms);'' that you can use instead of the loop above, 
-  * ''ledcDetach(pin);'' to detach a pin from the channel (and thus release the PWM channel), 
-  * ''ledcWriteNote(pin, note, octave);'' where ''note'' is one of the values: NOTE_C, NOTE_Cs, ... (and so on, music notes, up to NOTE_B) - it is useful when PWM controls a speaker, to generate a perfect musical note. 
-</note> 
 ==== Result validation ==== ==== Result validation ====
-You should be able to observe the pulsing colours of the RGB LEDincreasing and decreasing brightness linearly.+Driving R, G and B channels for RGB LED that lights the sensors, you should be able to observe changes in the readingsaccordingly.
  
 ===== FAQ ===== ===== FAQ =====
 +**What is the range of the values for the //integration time// of the TCS sensor?**:
 +<code c>
 +#define TCS34725_INTEGRATIONTIME_2_4MS                                         \
 +  (0xFF) /**< 2.4ms - 1 cycle - Max Count: 1024 */
 +#define TCS34725_INTEGRATIONTIME_24MS                                          \
 +  (0xF6) /**< 24.0ms - 10 cycles - Max Count: 10240 */
 +#define TCS34725_INTEGRATIONTIME_50MS                                          \
 +  (0xEB) /**< 50.4ms - 21 cycles - Max Count: 21504 */
 +#define TCS34725_INTEGRATIONTIME_60MS                                          \
 +  (0xE7) /**< 60.0ms - 25 cycles - Max Count: 25700 */
 +#define TCS34725_INTEGRATIONTIME_101MS                                         \
 +  (0xD6) /**< 100.8ms - 42 cycles - Max Count: 43008 */
 +#define TCS34725_INTEGRATIONTIME_120MS                                         \
 +  (0xCE) /**< 120.0ms - 50 cycles - Max Count: 51200 */
 +#define TCS34725_INTEGRATIONTIME_154MS                                         \
 +  (0xC0) /**< 153.6ms - 64 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_180MS                                         \
 +  (0xB5) /**< 180.0ms - 75 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_199MS                                         \
 +  (0xAD) /**< 199.2ms - 83 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_240MS                                         \
 +  (0x9C) /**< 240.0ms - 100 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_300MS                                         \
 +  (0x83) /**< 300.0ms - 125 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_360MS                                         \
 +  (0x6A) /**< 360.0ms - 150 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_401MS                                         \
 +  (0x59) /**< 400.8ms - 167 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_420MS                                         \
 +  (0x51) /**< 420.0ms - 175 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_480MS                                         \
 +  (0x38) /**< 480.0ms - 200 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_499MS                                         \
 +  (0x30) /**< 499.2ms - 208 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_540MS                                         \
 +  (0x1F) /**< 540.0ms - 225 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_600MS                                         \
 +  (0x06) /**< 600.0ms - 250 cycles - Max Count: 65535 */
 +#define TCS34725_INTEGRATIONTIME_614MS                                         \
 +  (0x00) /**< 614.4ms - 256 cycles - Max Count: 65535 */
 +</code>
  
-**What if I bind a PWM channel to more than one GPIO?**: As you control the duty cycle writing to the channel rather than the GPIOyou will control those GPIOs simultaneously (in parallel) with the same signal. That can be handy to control parallelly separate devices that should behave the same wayi.e. servos. +**What is the range of the values for the //gain// of the TCS sensor?**: 
-\\ +<code c> 
-**What is the maximum number of channels?**: the MCU we use here is ESP32-S3so it has 8 PWM channels. You can use timers and software implementation of the PWM signal if you need morebut that is a bit tricky and may not be as precise as hardware PWM implementation. +typedef enum { 
-\\ +  TCS34725_GAIN_1X = 0x00 / No gain  */ 
-**What is the maximum bit resolution for PWM?**: it is between 1 and 14 bits in this particular MCU.+  TCS34725_GAIN_4X = 0x01 / 4x gain  */ 
 +  TCS34725_GAIN_16X = 0x02, /*  16x gain */ 
 +  TCS34725_GAIN_60X = 0x03  / 60x gain *
 +} tcs34725Gain_t; 
 +</code> 
 + 
 +**C channel reading is 0, and RG or B readings are unreasonable.** It is possibly because of overdriving the sensor with a light source (too bright). Consider lowering the RGB LED's intensity or changing the sensor's integration time and gain (shorter time, lower gain).
  
 +<WRAP noprint>
 ===== Project information ===== ===== Project information =====
 {{:en:iot-open:logo_iot_200_px.png?200|}}\\ {{:en:iot-open:logo_iot_200_px.png?200|}}\\
Line 109: Line 167:
 {{:en:iot-open:ccbync.png?100|}} {{:en:iot-open:ccbync.png?100|}}
 </figure> </figure>
- +</WRAP>
- +
en/iot-open/practical/hardware/sut/esp32/emb9b_1.1709155280.txt.gz · Last modified: 2024/02/28 21:21 by pczekalski
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0