Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LED Indicator组件的led_indicator_start和led_indicator_set_brightness亮度值过渡不连续 (AEGHB-697) #376

Closed
3 tasks done
wnylei opened this issue Jun 19, 2024 · 8 comments

Comments

@wnylei
Copy link

wnylei commented Jun 19, 2024

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

General issue report

环境版本

ESP-IDF v5.1.3
LED Indicator : 0.9.2
芯片:ESP32

问题步骤:

  • 使用led_indicator_start 开始一个呼吸模式A。
  • 当呼吸模式A停止后,通过 led_indicator_set_brightness 设置一个亮度。
  • 随后,再次使用 led_indicator_start 开始呼吸模式A的时候,led会先闪灭一下,而不是从当前的亮度开始呼吸。

问题:

  1. 请问这是一个正常的逻辑吗?
  2. 如果我想让呼吸模式的执行从led从当前亮度开始呼吸,而不是闪灭一下再开始。这目前是可以实现的吗?
  3. 当前组件是否可以实现自由设置亮度值亮度渐变过渡时间的函数,类似现在 已有的函数led_indicator_set_brightness。不过,需要在此函数的基础上增加一个 亮度渐变过渡时间 的入参。

复现代码如下:

#include "unity.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "led_indicator.h"

static led_indicator_handle_t led_handle = NULL;

enum
{
    BLINK_BRIGHT_COMMON = 0,
    BLINK_MAX,
};


static const blink_step_t blink_bright_common[] = {
    {LED_BLINK_BREATHE, LED_STATE_ON, 1000},
    {LED_BLINK_STOP, 0, 0},
};

blink_step_t const *led_mode[] = {
    [BLINK_BRIGHT_COMMON] = blink_bright_common,
    [BLINK_MAX] = NULL,
};
static void u_led_test_init(void)
{
    led_indicator_ledc_config_t ledc_config = {
        .is_active_level_high = true,
        .timer_inited = false,
        .timer_num = LEDC_TIMER_0,
        .gpio_num = 2,
        .channel = LEDC_CHANNEL_0,
    };

    const led_indicator_config_t config = {
        .mode = LED_LEDC_MODE,
        .led_indicator_ledc_config = &ledc_config,
        .blink_lists = led_mode,
        .blink_list_num = BLINK_MAX,
    };

    led_handle = led_indicator_create(&config);
    assert(led_handle != NULL);
}

//使用unit-test-app 进行测试
TEST_CASE("u_led_indicator_set_breath_brightness", "[u_common_led]")
{
    u_led_test_init();

    led_indicator_start(led_handle, BLINK_BRIGHT_COMMON);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_set_brightness(led_handle, LED_STATE_50_PERCENT);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_start(led_handle, BLINK_BRIGHT_COMMON); //执行它的时候LED会先闪灭一下,而不是从当前亮度50开始
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_set_brightness(led_handle, LED_STATE_50_PERCENT);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_start(led_handle, BLINK_BRIGHT_COMMON); //执行它的时候LED会先闪灭一下,而不是从当前亮度50开始
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_delete(led_handle);
}

现象和尝试

现象:

  1. LED灯渐亮到100%,
  2. LED瞬亮到50%,
  3. LED先瞬灭到0%,随后,渐亮到100%。 (正常逻辑不应该是从50% 逐渐 亮到 100% 吗?)

我尝试把呼吸模式改成如下:

static const blink_step_t blink_bright_common[] = {
    {LED_BLINK_BRIGHTNESS, LED_STATE_50_PERCENT, 0},
    {LED_BLINK_BREATHE, LED_STATE_ON, 1000},
    {LED_BLINK_STOP, 0, 0},
};

但对实际结果,并没有什么影响。

请求指教,万分感激!

@github-actions github-actions bot changed the title LED Indicator组件的led_indicator_start和led_indicator_set_brightness亮度值过渡不连续 LED Indicator组件的led_indicator_start和led_indicator_set_brightness亮度值过渡不连续 (AEGHB-697) Jun 19, 2024
@lijunru-hub
Copy link
Contributor

lijunru-hub commented Jun 19, 2024

这不是 bug,我试了一下,这个并不是闪灭一下,而是亮度突然掉了一下,原因是 breathe 这个调光默认开了 gamma 调光。128 的亮度会被校准成 52,而 led_indicator_set_brightness(led_handle, LED_STATE_50_PERCENT); 不会进行 gamma 调光。所以亮度会从 128 瞬间到 52,再回到 255。

你可以直接关掉宏: CONFIG_USE_GAMMA_CORRECTION。但是不加 gamma 调光,亮度的明暗变化不明显。

至于加一个 set_breath_with_time 的这种 API,会有比较大的结构改动,可能暂时还不是很方便加入进去。目前 led_indicator 意在预设好很多指示灯的情况,然后方便进行指示灯的切换。

如果你有对 led_indicator 的一些建议性意见,欢迎提出。

@wnylei
Copy link
Author

wnylei commented Jun 19, 2024

这不是 bug,我试了一下,这个并不是闪灭一下,而是亮度突然掉了一下,原因是 breathe 这个调光默认开了 gamma 调光。128 的亮度会被校准成 52,而 led_indicator_set_brightness(led_handle, LED_STATE_50_PERCENT); 不会进行 gamma 调光。所以亮度会从 128 瞬间到 52,再回到 255。

你可以直接关掉宏: CONFIG_USE_GAMMA_CORRECTION。但是不加 gamma 调光,亮度的明暗变化不明显。

至于加一个 set_breath_with_time 的这种 API,会有比较大的结构改动,可能暂时还不是很方便加入进去。目前 led_indicator 意在预设好很多指示灯的情况,然后方便进行指示灯的切换。

如果你有对 led_indicator 的一些建议性意见,欢迎提出。

非常感谢!

我验证了一下,它确实是gamma导致的问题,当我禁用掉CONFIG_USE_GAMMA_CORRECTION之后,确实不会再有亮度掉一下的问题,但是这种情况下的 breathe 调光确实也不太理想。

然后,我看到你之前提到的led_indicator_get_gamma_value这个函数,我把它加入了测试用例,同时继续启用了 CONFIG_USE_GAMMA_CORRECTION 并进行了测试,但还是会出现亮度掉一下的问题。

问题:

  1. 请问这是什么原因导致的呢?
  2. 目前有办法在 使能 CONFIG_USE_GAMMA_CORRECTION 的情况下,实现如下测试用例中两个函数之间,亮度值的平滑过度吗?

测试用例代码:

TEST_CASE("u_led_indicator_issue_breath_brightness", "[u_common_led]")
{
    u_led_test_init();

    led_indicator_start(led_handle, BLINK_BRIGHT_COMMON);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    U_LOGI("brightness = %d", led_indicator_get_gamma_value(128));
    led_indicator_set_brightness(led_handle, led_indicator_get_gamma_value(128));
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_start(led_handle, BLINK_BRIGHT_COMMON);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_set_brightness(led_handle, led_indicator_get_gamma_value(128));
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_start(led_handle, BLINK_BRIGHT_COMMON);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_delete(led_handle);
}

@lijunru-hub
Copy link
Contributor

lijunru-hub commented Jun 20, 2024

这个是因为你经过一次 gamma 调光后传入的 128 变成了 52,这时候的亮度其实保存的是 52,然后渐变再用这个 52 去做 gamma 就变成了亮度 2,导致又会变暗一下。如果要解决需要再添加一个 API :led_indicator_set_brightness_with_gamma.

我觉得这是一个 bug,在灯效数组中设置 {LED_BLINK_BRIGHTNESS, LED_STATE_50_PERCENT, 0} 应该存储设定值 128,而不是 gamma 后的值,我会尽快 fix 这个。

你目前可以手动实现一下 led_indicator_set_brightness_with_gamma 在 led_indicator.c 中。

esp_err_t led_indicator_set_brightness_with_gamma(led_indicator_handle_t handle, uint32_t brightness)
{
    LED_INDICATOR_CHECK(handle != NULL, "invalid p_handle", return ESP_ERR_INVALID_ARG);
    _led_indicator_t *p_led_indicator = (_led_indicator_t *)handle;
    if (!p_led_indicator->hal_indicator_set_brightness) {
        ESP_LOGW(TAG, "LED indicator does not have the hal_indicator_set_brightness function");
        return ESP_FAIL;
    }
    xSemaphoreTake(p_led_indicator->mutex, portMAX_DELAY);
    p_led_indicator->hal_indicator_set_brightness(p_led_indicator->hardware_data, led_indicator_get_gamma_value(brightness));
    led_indicator_ihsv_t ihsv = {
        .value = brightness,
    };
    /*!< Just setting index and brightness */
    p_led_indicator->current_fade_value.i = ihsv.i;
    p_led_indicator->current_fade_value.v = ihsv.v;
    p_led_indicator->last_fade_value = p_led_indicator->current_fade_value;
    xSemaphoreGive(p_led_indicator->mutex);
    return ESP_OK;
}

@wnylei
Copy link
Author

wnylei commented Jun 20, 2024

非常感谢!

经过验证,使用 led_indicator_set_brightness_with_gamma 函数, 已经解决了亮度掉一下的问题。

另外

之前提到的 u_led_indicator_set_brightness_with_time 这种函数,我想了一个方案,并经过了测试和验证,是可以正常工作的,但违反了组件部分数据结构的要求(组件要求: const blink_step_t **::blink_lists 而我使用了 blink_step_t **::blink_lists )。

问题

请问这种操作后期组件更新会有什么隐患吗?或者是否有更好的修改建议。

建议

官方是否可以考虑按这种思路,为此组件增加这种类型的API接口,以实现组件更大的灵活度。(它的实际应用场景是:带有光照度传感器和人体感应器的指示灯,感应到有人时可以渐亮到某个不固定的亮度(根据当前的光照度确定亮度),无人时渐灭到另一个亮度)。

实现代码如下


enum
{
    BLINK_BRIGHT_COMMON = 0,
    BLINK_MAX,
};

static blink_step_t blink_bright_common[] = {
    {LED_BLINK_BREATHE, LED_STATE_ON, 1000},
    {LED_BLINK_STOP, 0, 0},
};

static blink_step_t *led_mode[] = {
    [BLINK_BRIGHT_COMMON] = blink_bright_common,
    [BLINK_MAX] = NULL,
};
static void u_led_test_init(void)
{
    led_indicator_ledc_config_t ledc_config = {
        .is_active_level_high = true,
        .timer_inited = false,
        .timer_num = LEDC_TIMER_0,
        .gpio_num = 2,
        .channel = LEDC_CHANNEL_0,
    };

    const led_indicator_config_t config = {
        .mode = LED_LEDC_MODE,
        .led_indicator_ledc_config = &ledc_config,
        .blink_lists = (const blink_step_t **)led_mode,
        .blink_list_num = BLINK_MAX,
    };

    led_handle = led_indicator_create(&config);
    assert(led_handle != NULL);
}

static void u_led_indicator_set_brightness_with_time(led_indicator_handle_t handle, uint32_t value, uint32_t hold_time_ms)
{

    led_mode[BLINK_BRIGHT_COMMON][0].hold_time_ms = hold_time_ms;
    led_mode[BLINK_BRIGHT_COMMON][0].value = value;
    led_indicator_start(handle, BLINK_BRIGHT_COMMON);
}

TEST_CASE("u_led_indicator_set_brightness_with_time", "[u_common_led]")
{
    u_led_test_init();

    u_led_indicator_set_brightness_with_time(led_handle, 128, 1000);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    u_led_indicator_set_brightness_with_time(led_handle, 255, 1000);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    u_led_indicator_set_brightness_with_time(led_handle, 128, 1000);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    u_led_indicator_set_brightness_with_time(led_handle, 255, 1000);
    vTaskDelay(2000 / portTICK_PERIOD_MS);

    led_indicator_delete(led_handle);
}

@lijunru-hub
Copy link
Contributor

lijunru-hub commented Jun 20, 2024

动态修改数组的值达到更灵活的方式是被允许的(传入的 led_mode 是 const * 即可,不对下层的数组里的内容要求 const),我觉得你这个调光的 API 写的很好。我觉得后续可以在示例中体现这种用法,进行一些引导。

此外新的组件已经 Fix 你之前提的亮度不统一的问题了,请试一下:https://github.com/lijunru-hub/esp-iot-solution/tree/fix/led_indicator_set_brightness_with_gamma

如何使用:
1. 将 led_indicator:0.9.3 组件直接复制到工程目录下的 components 中

修复内容:

  1. 解决了错误的亮度保存,现在只会保存设置的亮度
    
  2. 所有的 HSV 和 亮度的设置都会默认的进行 gamma 转化,不增加 led_indicator_set_brightness_with_gamma API,而是默认都开启 gamma
    

如果有任何新问题,欢迎留言。如果没有问题,请关闭这个 issue,再次感谢你的测试。

@wnylei
Copy link
Author

wnylei commented Jun 20, 2024

点个赞👍🏻

经过测试,led_indicator:0.9.3 组件,已经解决了亮度不统一的问题。

另外

  1. 这里 组件库,大概何时可以更新到0.9.3 这个版本?
  2. 我是通过idf_component.yml引入的这个组件,引入组件后,代码中使用了几个brightness函数。随后,经过编译测试,大概用掉了6K的IRAM。 项目中的IRAM空间本来就很紧缺,这种情况针对此组件还有办法优化吗?

@lijunru-hub
Copy link
Contributor

  1. 这个组件会尽快合入进去
  2. 这个组件本身没有创建独立的任务,只有一个 freertos 的 timer,占用 6K 确实有点太多了,我会再优化一下这个

@wnylei
Copy link
Author

wnylei commented Jun 20, 2024

非常感谢!

@wnylei wnylei closed this as completed Jun 20, 2024
zhanzhaocheng pushed a commit that referenced this issue Jun 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants