From 116921117776e3b756cd48eb0fe20ce909fa83fb Mon Sep 17 00:00:00 2001 From: Bond Keevil Date: Fri, 25 Oct 2019 04:24:21 -0400 Subject: [PATCH] Feature: Control a LED Illuminator or Flash from Camera_Web_Server Web Page (#104) * Feature: Control a LED Illuminator or Flash from Camera_Web_Server Add a "LED Illuminator" menu to menuconfig Through menuconfig you can select a LEDC pin, LEDC Timer, LEDC Channel, and LEDC Speed Mode The defaults work for the AIThinker ESPCAM-32 board There is an option to limit LED intensity while streaming to prevent overheating LED intensity is not limited when taking a still image photo The LED intensity controls are hidden on the web page if the LED feature is not enabled LED intensity can be adjusted while streaming and the LED will respond right away Tested on an ESPCAM-32 board with an OV2460 sensor * app_httpd.c: move isStreaming into macro * app_httpd.c: Change commit re: 150ms LED delay --- .../camera_web_server/main/Kconfig.projbuild | 53 +++++++++++++++++ .../camera_web_server/main/app_camera.c | 31 ++++++++++ .../camera_web_server/main/app_httpd.c | 54 +++++++++++++++++- .../main/www/index_ov2640.html | 9 +++ .../main/www/index_ov2640.html.gz | Bin 4679 -> 4763 bytes .../main/www/index_ov3660.html | 9 +++ .../main/www/index_ov3660.html.gz | Bin 4776 -> 4847 bytes 7 files changed, 155 insertions(+), 1 deletion(-) diff --git a/examples/single_chip/camera_web_server/main/Kconfig.projbuild b/examples/single_chip/camera_web_server/main/Kconfig.projbuild index 738788e..0d62338 100644 --- a/examples/single_chip/camera_web_server/main/Kconfig.projbuild +++ b/examples/single_chip/camera_web_server/main/Kconfig.projbuild @@ -38,6 +38,59 @@ config ESP_MAXIMUM_RETRY Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. endmenu +menu "LED Illuminator" +config LED_ILLUMINATOR_ENABLED + bool "LED Illuminator Enabled" + default n + help + Enable an LED Flash or IR Illuminator + +config LED_LEDC_PIN + depends on LED_ILLUMINATOR_ENABLED + int "LED Illuminator GPIO Pin" + range 0 33 + default 4 + help + Set a pin to illuminate an onboard LED or IR Illuminator when streaming or taking snapshots. + +config LED_MAX_INTENSITY + depends on LED_ILLUMINATOR_ENABLED + int "LED Maximum Intensity (0-255)" + range 0 255 + default 255 + help + Limit the maximum intensity of the LED while streaming to prevent overheating (0-255). + +choice LED_LEDC_SPEED_MODE + depends on LED_ILLUMINATOR_ENABLED + bool "Select LEDC Timer Speed Mode" + default LED_LEDC_LOW_SPEED_MODE + help + Select a speed mode for the LEDC channel + +config LED_LEDC_LOW_SPEED_MODE + bool "LOW_SPEED_MODE" +config LED_LEDC_HIGH_SPEED_MODE + bool "HIGH_SPEED_MODE" +endchoice + +config LED_LEDC_TIMER + depends on LED_ILLUMINATOR_ENABLED + int "LEDC Timer" + range 0 3 + default 1 + help + Select the LEDC Timer (0-3) + +config LED_LEDC_CHANNEL + depends on LED_ILLUMINATOR_ENABLED + int "LEDC Channel" + range 0 7 + default 1 + help + Select the LEDC Channel (0-7) +endmenu + menu "Camera Pins" choice CAMERA_MODEL bool "Select Camera Pinout" diff --git a/examples/single_chip/camera_web_server/main/app_camera.c b/examples/single_chip/camera_web_server/main/app_camera.c index 6682487..0c03df5 100755 --- a/examples/single_chip/camera_web_server/main/app_camera.c +++ b/examples/single_chip/camera_web_server/main/app_camera.c @@ -20,6 +20,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "esp_log.h" +#include "driver/ledc.h" #include "esp_camera.h" #include "app_camera.h" #include "sdkconfig.h" @@ -44,6 +45,36 @@ void app_camera_main () gpio_config(&conf); #endif +#ifdef CONFIG_LED_ILLUMINATOR_ENABLED + gpio_set_direction(CONFIG_LED_LEDC_PIN,GPIO_MODE_OUTPUT); + ledc_timer_config_t ledc_timer = { + .duty_resolution = LEDC_TIMER_8_BIT, // resolution of PWM duty + .freq_hz = 1000, // frequency of PWM signal + .speed_mode = LEDC_LOW_SPEED_MODE, // timer mode + .timer_num = CONFIG_LED_LEDC_TIMER // timer index + }; + ledc_channel_config_t ledc_channel = { + .channel = CONFIG_LED_LEDC_CHANNEL, + .duty = 0, + .gpio_num = CONFIG_LED_LEDC_PIN, + .speed_mode = LEDC_LOW_SPEED_MODE, + .hpoint = 0, + .timer_sel = CONFIG_LED_LEDC_TIMER + }; + #ifdef CONFIG_LED_LEDC_HIGH_SPEED_MODE + ledc_timer.speed_mode = ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; + #endif + switch (ledc_timer_config(&ledc_timer)) { + case ESP_ERR_INVALID_ARG: ESP_LOGE(TAG, "ledc_timer_config() parameter error"); break; + case ESP_FAIL: ESP_LOGE(TAG, "ledc_timer_config() Can not find a proper pre-divider number base on the given frequency and the current duty_resolution"); break; + case ESP_OK: if (ledc_channel_config(&ledc_channel) == ESP_ERR_INVALID_ARG) { + ESP_LOGE(TAG, "ledc_channel_config() parameter error"); + } + break; + default: break; + } +#endif + camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; diff --git a/examples/single_chip/camera_web_server/main/app_httpd.c b/examples/single_chip/camera_web_server/main/app_httpd.c index 59dc7b8..c4797e9 100644 --- a/examples/single_chip/camera_web_server/main/app_httpd.c +++ b/examples/single_chip/camera_web_server/main/app_httpd.c @@ -17,6 +17,7 @@ #include "esp_camera.h" #include "img_converters.h" #include "fb_gfx.h" +#include "driver/ledc.h" //#include "camera_index.h" #include "sdkconfig.h" @@ -47,6 +48,16 @@ static const char* TAG = "camera_httpd"; #define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED) #endif +#ifdef CONFIG_LED_ILLUMINATOR_ENABLED +int led_duty = 0; +bool isStreaming = false; +#ifdef CONFIG_LED_LEDC_LOW_SPEED_MODE +#define CONFIG_LED_LEDC_SPEED_MODE LEDC_LOW_SPEED_MODE +#else +#define CONFIG_LED_LEDC_SPEED_MODE LEDC_HIGH_SPEED_MODE +#endif +#endif + typedef struct { httpd_req_t *req; size_t len; @@ -59,6 +70,7 @@ static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: % httpd_handle_t stream_httpd = NULL; httpd_handle_t camera_httpd = NULL; + #if CONFIG_ESP_FACE_DETECT_ENABLED static mtmn_config_t mtmn_config = {0}; static int8_t detection_enabled = 0; @@ -225,6 +237,19 @@ static int run_face_recognition(dl_matrix3du_t *image_matrix, box_array_t *net_b } #endif #endif + +#ifdef CONFIG_LED_ILLUMINATOR_ENABLED +void enable_led(bool en) { // Turn LED On or Off + int duty = en ? led_duty : 0; + if (en && isStreaming && (led_duty > CONFIG_LED_MAX_INTENSITY)) { + duty = CONFIG_LED_MAX_INTENSITY; + } + ledc_set_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL, duty); + ledc_update_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL); + ESP_LOGI(TAG, "Set LED intensity to %d", duty); +} +#endif + static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){ jpg_chunking_t *j = (jpg_chunking_t *)arg; if(!index){ @@ -242,7 +267,15 @@ static esp_err_t capture_handler(httpd_req_t *req){ esp_err_t res = ESP_OK; int64_t fr_start = esp_timer_get_time(); + #ifdef CONFIG_LED_ILLUMINATOR_ENABLED + enable_led(true); + vTaskDelay(150 / portTICK_PERIOD_MS); // The LED needs to be turned on ~150ms before the call to esp_camera_fb_get() + fb = esp_camera_fb_get(); // or it won't be visible in the frame. A better way to do this is needed. + enable_led(false); + #else fb = esp_camera_fb_get(); + #endif + if (!fb) { ESP_LOGE(TAG, "Camera capture failed"); httpd_resp_send_500(req); @@ -359,11 +392,17 @@ static esp_err_t stream_handler(httpd_req_t *req){ httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); +#ifdef CONFIG_LED_ILLUMINATOR_ENABLED + enable_led(true); + isStreaming = true; +#endif + while(true){ #if CONFIG_ESP_FACE_DETECT_ENABLED detected = false; face_id = 0; #endif + fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAG, "Camera capture failed"); @@ -489,6 +528,12 @@ static esp_err_t stream_handler(httpd_req_t *req){ ); } + +#ifdef CONFIG_LED_ILLUMINATOR_ENABLED + isStreaming = false; + enable_led(false); +#endif + last_frame = 0; return res; } @@ -556,6 +601,9 @@ static esp_err_t cmd_handler(httpd_req_t *req){ else if(!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val); else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val); else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val); +#ifdef CONFIG_LED_ILLUMINATOR_ENABLED + else if(!strcmp(variable, "led_intensity")) { led_duty = val; if (isStreaming) enable_led(true); } +#endif #if CONFIG_ESP_FACE_DETECT_ENABLED else if(!strcmp(variable, "face_detect")) { @@ -619,7 +667,11 @@ static esp_err_t status_handler(httpd_req_t *req){ p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror); p+=sprintf(p, "\"dcw\":%u,", s->status.dcw); p+=sprintf(p, "\"colorbar\":%u", s->status.colorbar); - +#ifdef CONFIG_LED_ILLUMINATOR_ENABLED + p+= sprintf(p, ",\"led_intensity\":%u", led_duty); +#else + p+= sprintf(p, ",\"led_intensity\":%d", -1); +#endif #if CONFIG_ESP_FACE_DETECT_ENABLED p+=sprintf(p, ",\"face_detect\":%u", detection_enabled); #if CONFIG_ESP_FACE_RECOGNITION_ENABLED diff --git a/examples/single_chip/camera_web_server/main/www/index_ov2640.html b/examples/single_chip/camera_web_server/main/www/index_ov2640.html index 8460f32..3477ebb 100644 --- a/examples/single_chip/camera_web_server/main/www/index_ov2640.html +++ b/examples/single_chip/camera_web_server/main/www/index_ov2640.html @@ -531,6 +531,12 @@ +
+ +
0
+ +
255
+
@@ -612,6 +618,8 @@ document.addEventListener('DOMContentLoaded', function (event) { value ? show(wb) : hide(wb) } else if(el.id === "face_recognize"){ value ? enable(enrollButton) : disable(enrollButton) + } else if(el.id == "led_intensity"){ + value > -1 ? show(ledGroup) : hide(ledGroup) } } } @@ -670,6 +678,7 @@ document.addEventListener('DOMContentLoaded', function (event) { const enrollButton = document.getElementById('face_enroll') const closeButton = document.getElementById('close-stream') const saveButton = document.getElementById('save-still') + const ledGroup = document.getElementById('led-group') const stopStream = () => { window.stop(); diff --git a/examples/single_chip/camera_web_server/main/www/index_ov2640.html.gz b/examples/single_chip/camera_web_server/main/www/index_ov2640.html.gz index 4d8c535114e958efdf87b84cf4e3be91649c2fe2..60cd5e6a09eaed7b69389dedfcc2f920affa0cc3 100644 GIT binary patch literal 4763 zcmV;M5@hWkiwFowUr${C18Ht#Wq4n2b}}|JFfM3xZEOJL9ch!(M)o_uLWnG57h{j@ zIhYJ%XJHtQDhLUakZf&jL0f9u3bN!#Eqf-^{Eq!W`^Wb6sg~S2Y=h0RrV4cQd;RXC zB{k=F-OwR7Gi*)B)F0eA=l@vnJD*_W@eLEqe)~TJp9iS=h+j9>u zW?@8Z%LxO50~o&WTr%mqc4t zoFDLO>6n<@=;!n|4BZ>+Q|1!=jev;O2u(fz=FEB=!JPXqus_GdbI^W_g18mq$QwOc z0vsae<2VYFz&*3>bx-M^YmK5Gxu-rWKJi&BI*VF zX*qn19pZ&Sdy2fkfXVgZnU6pQBOjOIxi`f@vR{FXB5Ao^#7CV`IV97d5^Wh>K^S0z z0O>@F2+imK`tS0PsTXjgIMi_bE2#AFnAFe>+nBk^@DA_c_2&86})1Ph>E3j*3HH{tokI9BO zCxuaj{_01P6j^07F(59EC`)*YyxV}aoP@g3#eleshRP^If44R2jeEm{kT8fhN>N3A z_D2#EZ*@fW4tFk(Qrq)U};*&(skxcu=5eS4=T&Bs`9Yy1+#>-XgM|eB06UV zDOv3G%8H8P*>$-PbYcfS8e+eUWZ?`2VOPYe;@XW-mL{*GhkvUrM|QlQxfEj`9IUAH zhA|7Ep>%=>1!D}c;Cf#kmNy2q*r%cTxV#bJ0b$>2^Mf_25>3CQgmjJ8!3z_k=VWcm zSm;-V2HEnBMpaGYXmr>)JgTgmj9lg#M?>gPVWrdvVl+1v?P2Wk&J7J?=-r5+^%92O zGt$ROI-?6n@tVobXuv!~Q?Rk9B>0-NTs3Huwx0`q(YWW-cC~#3vP2i8}O8*^Dd<{gbW>^;zKfmtjs> zYM|K+BN*l2B0bb+1<2#cgi+zu|e-Z>#qb(8v zn}&(%32vwA!>B?JNt+5 zm!Y32H!dOG0?W&V=;~#qqF`UCi~63FU0>?9EAnuGNw02*25VVW#nbSw7B52n@2y=E z#W!u~E6XL`wQY2YwcZj{A5a)T4;n!;T38usW7d$t$n*V{A1-}wcobGmAb}yiDC_V+-#y+ro=13^0sH;5ofYS>zOu25%v+S;MZEAsBGVK@H(6@ z(S1FuOKn~|6vt|_Syz<%SZonk2sb4u)NHCU`rI3L9iS78w;)?v-T`W_cy6)Y!c#g0h#I zD*}ur{nasdZH={i(y5rz@xyq-1+e1vFXNqBsk_vt%H1(1^KQo&X-iir*$NtaetBj& z*c?W)3w3ptN=x-H@mv>|t_9PcH-|zVogZlL`>g3Gsq)e15=?<_I|eN(yKb0o_EN91=r}8luQBgbm~60;{xa7TAX2b)Eyp zl!$s_6n2Xc0vH3QkBQRKIm~NfaxlEyT>Gf*^)2oG}BNBR>Jrc02aq*WaH%Za^UFTz7k&PV@YL4_O)4_x9k5 zq3WFis!s1{eN?CRfMEh8*AGul*GKdaXnF^jPJz3VO_)2e2NVx@#r4tY26&EbkrJuN z$|HMl@$y;Y2x#nmf3iOABYW^OCGxNbh>kWO^3WcSSJp@hY7d^M<4yF^>TRGGjU29; zR!^v=XQv+VITcey?IwDmNjyR^Sy?L*5W<=`+L=ZaDc^uTVnh=D#CT zqLK40=w*f-5Bcx$Xap&1b=_pZK|lQ5x@6}o*N8cEpQ}*pnCq4wLq+GB6+#z~;4$lz z*T&Ja2hSsP!#>5>r098zUF#QU1vja{o<|tk#Eq~VLo$Pd&5%IBdWB~m`Wgx@v>2}J z764-p9{=`ad#TwpdrsYk)4-P`kS)*I8k_Za{BjWthf+PxOlN}YT`LXE&@k!c8*ERT2a@ zo1~QsKTO>9F+fgvGa7l$`dJAw%8PJX6aEWFaqO%fAg}{kyu7fkE`Pjw^L9JY0p{FM zV4&RYIwk-Sy>;}|l}Sntx)7&QZeH-^3Is% zo#z+Z31#D*C7kh26OP3niYhg&*+d9H=$+STAoNA`>rGrol9BbC!_;q%KdaXqR#Ll( z(@;(v?D_PAuT>SI!E&8g7yN7!-SjrmjZRTkJtto%({y{MUs658+3GP3VC=z@pSBaz z=wvlx+C~wKF}3SbY_Wzm7L@Scwxo?keQkW^472ze^b?`Q`|%X5tRn$u58k4M_5AhY zt>{Wlx*L5dmUpc)9|x;D6$P>fuW%4s7hxne=h=$Z*vz|88E1Oe`kG9=C<>#MRVLu< z!Hd>wcC;0B$ys-!F~#$)l{O#w-fU%+F(`ZRuJsK5-HN*SjJr{m;C9!la-GG>iUJsW z@buz0tMN2k1oXu}>+;9uRy0PZ-i^K()4SFdd;55ZRu6{~kiPo@N7fUxoq(w3-A2)# zGP!F#`Pi+YqHKxbzNc?{(+^y3pw_s2YQ2=FHMm)O&911m&C-)?ZhObao3*z^%c#f4 zUr;9_{7WZWr!fPQ`uAcMFI zv~bS11S~+MK5$`@NIw=+Y~?>96N~62#3S+6!1qb%onW%;6p;GgI{#|98bYsX=0JarJPTvMfqcD!c$Qyfw zN-#_Nz$EV6V1s_oV<+-vWN^m~on(pw(nhX(IfsK+UJUsbM~%IwZ(d*UPnBMQys*2s zZ;g_GyH*3!v3!HhIf|?yit&puCRX2482!*;ud%i{Ut%O@{MX2bp$h7OwRd*f-J@TX zf$HG`s2#%q2rB)7_^b^3Z6jk$8BSeeqwp6Amd56D1(gfG@Rocu!0sIR5`Wu zw7sSrpmuQTTO>+w7A+2{uu8H@5s#1`=P)NT7ZLo9mO(I}f&G166YYyTZvijC&2(1% zGC*Wc`&N)Z*!Y35V4Y>|GH4$nqS)M<&B-o$BRX-LZ8hEp9D6dO?4>)n>Of2mZP5>j z`*U&Q?%lbDHJYZXV z4J=6VMvc1}!7Ca^R79T31jOEjX{KLGa{7K?R^PzlDR~p*PmMXfAjYRt=@`cujFhn) z-So%s(dR|tnU(%^GMgOG&}Uld^_-~Hzyc&}f@LJ7l*<r0mA8Cb2Zq#lMor?sNuL0ype@5sNIQK}HD+ZpvQ zsY&XBsUeFEB&7eP>UJQuYMywOBT;ujAhm1hTS5#WM1RcSVf~Rp!mshy=~`ic&DeD( zG~wiFIgd0MPCa5kxCiOMgi92wDL{lFs|UK5^GNw;f}fF>DdB`oeEWf;7}5Qo8w`ciTboR9(1>t61N1lzuyV%G$B+WYjSmq9I3R$8 z)_0#6id$<0Q6`>XcOUX0BJ@k|?>71Kf(J@);^9{(U- zBJ;Fk!<){_p4hhgCOp7W6=jAoW_9)bKe-{9!S(8W13ZBjB04nWGtm7$XBi0*{J z#gvgSXGZYCWtLVElI7HFx%Mn2i$CHpXf*FAF)ZVt6KDuBA}SJ7w!_&=BUORS=ugYE zEX}fc|H(||U;8{YYZ0%hiHqAG{hu@R@(B8jOCQt2CpRylq~L`Sqa_8nP=##?*9UTbbNXlBUOzRe?8PsyU(qP1H;Q}NQjhHpZk&NyN*g)} z9^F)hO`VS(e&BP`Y?QI7W+g4*EKdr!{$oPGLoDt)F%4^?$-ZOh_Er#OQZWg)&JwSM zX5OCt@ZK3hG=2)s)((J!=4}}}TwJN`)Fpz&Ju|k9e9Y){hq(-7wO%CH{<3I!!InXg zMzkejb2XV}7jl54UH8EP+Oy?suKwWyP|j3Fu zvyD<{VNPv;on&tF4NByFe#Qr=S?CraZMwN;;9g8T-)(SEF%6@P_ORC!i@*xre8I0Z z_Il80J(4=4m)dTG7BA@{1T%;Ibb~k&rT+mD#S3CXzrKBy;w9lzeyOp?Rxu9#nBnoB z+AT;EBVC}NqT<6J=}6&n0C|F%d&2}OmoF$d<>VRkYyZF~0)0HN8g|Ei&|ueJ13QyO z^Fg=Sq+1?2xY6p#A@C0y!zU@e{~}DHxNN{{FGvV39dZTLc;GG#vDvDNY@Hm$Ygny% z6$KQgkCNfWBW2ghIMNbDG|x-=&jl=z^ewuB%!JmnB81hctBeIhX@SLOkdBgX8neaJ zMFKuPl@XO+qaBnA{m@aB$=UpcNgZ&~gwj8r5knVX4un}WqQh~1k%~7foY`E9q7P6k zWyUB6;qXOdR+55z96|p7$;Y(87oSO9ynJSbk;Qi&jnt-3me`h$Ez{5#L?&JgT_xQT z0pGP%Labzuw~>0*$cU4}q_Vs#cw7oZWeYyk80t8XP5 prHjzUC||48v3-3=YRRp`HrOm{sz67-*Y7@B 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 diff --git a/examples/single_chip/camera_web_server/main/www/index_ov3660.html b/examples/single_chip/camera_web_server/main/www/index_ov3660.html index e7fa8e3..37f2dfd 100644 --- a/examples/single_chip/camera_web_server/main/www/index_ov3660.html +++ b/examples/single_chip/camera_web_server/main/www/index_ov3660.html @@ -560,6 +560,12 @@
+
+ +
0
+ +
255
+
@@ -639,6 +645,8 @@ document.addEventListener('DOMContentLoaded', function (event) { value ? show(wb) : hide(wb) } else if(el.id === "face_recognize"){ value ? enable(enrollButton) : disable(enrollButton) + } else if(el.id == "led_intensity"){ + value > -1 ? show(ledGroup) : hide(ledGroup) } } } @@ -697,6 +705,7 @@ document.addEventListener('DOMContentLoaded', function (event) { const enrollButton = document.getElementById('face_enroll') const closeButton = document.getElementById('close-stream') const saveButton = document.getElementById('save-still') + const ledGroup = document.getElementById('led-group') const stopStream = () => { window.stop(); diff --git a/examples/single_chip/camera_web_server/main/www/index_ov3660.html.gz b/examples/single_chip/camera_web_server/main/www/index_ov3660.html.gz index 411189c4d218441b4bc7e63b809c6283550b1827..db85d562eef4e4e72d597a29c8b2807505c6f86c 100644 GIT binary patch literal 4847 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 V;$Ka?IOhL(_rL5a6oHX<001QST$um> literal 4776 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