Servo-CAM with M5CAMERA or ESP32CAM and two SG90 servos

Place your projects here
Post Reply
User avatar
PeterN
Posts: 366
Joined: Mon Feb 08, 2021 7:56 pm
Location: Krefeld, Germany
Has thanked: 171 times
Been thanked: 203 times
Contact:

Servo-CAM with M5CAMERA or ESP32CAM and two SG90 servos

Post by PeterN »

A bit of ANNEX-code to controll an ESP32 based pan/tilt servo CAM.
My intention for HW and SW was "Keep it simple":
turn_left.GIF
.

So I stacked two SG90-servos to carry a M5CAMERA001.
The webinterface was derived from CiccioCB's sample code. Horizontal and vertical position are manualy set by sliders that are integrated in the live-picture. An auto pan can slowly turn the cam.
All possible resolutions can be selected.
Some pictures can be stored in the internal flash ( or better on SD-card if inserted in an ESP32CAM).
3860C928-BB81-4FDB-BDBC-2D794821010F.jpeg
AF4569A4-B302-40CE-B674-C32934112FAD.jpeg
54B20915-9FAF-45E8-B16F-B5050CCCA471.jpeg

Next thing I want to try is
# to implement face detection and face recognition, which are unhappily only available in the 320x240 mode. This worked fundamentally well for me in a separate code snippet - except that I now need to "find" some javascript to draw a frame at the returned Face-position in the browser window and perhaps to print an apropriate name for one of the seven recognizable stored faces.

# A mode to follow a face with the servos then seems to be the next simple step ... BUT: the max resolution for face detection is 320x240 - not really nice to look at.

# A mode to automatically regularly take a picture and store it on a FTP-server may be handy


This is my current ANNEX-code for the described functions:
If you do use only a horizontal PAN servo, or even no servo ... the code is prepared to simply set some
variables to (de)activate the servo functions and the sliders.
If running on an ESPCAM the onboard white flash LED can be switched ON/OFF by an additional button.
If the camera or the mount is turned or mounted over the top: Look at the variables to invert/mirror the movements or the picture. I have tried to explain the purpose by the names and with some comment-lines.

Code: [Local Link Removed for Guests]


' A N N E X 3 2 C A M - p r o g r a m  
'  - to show a life camera picture in browser in some resolutions 
'  - to controll the pan/tilt servos (manually or auto-pan)
'  - to take some still pictures in NV-RAM or on SD-Card
'  - to controll the onboard white LED (ESP32CAM only)
'  - to set some camera parameters  
' Hardware: 
'   ESP32CAM  or M5CAM version "B"  with or without two servos
'     ESP32CAM : H-Servo at Pin GPIO12; V-Servo at Pin GPIO3 = RX
'     M5CAM    : H-Servo at Pin GPIO4;  V-Servo at Pin GPIO13; pins at grove-port
' DB9JG@ME:COM   2021/06

VERSION$    = "V9.1"
CALL$       = "DB9JG"

'Save snapshots in local NVRAM or SD (if ANNEX runs on the SD)?
'PIC_NUM    = 0 ' => do not save or show  pics
PIC_NUM     = 5 ' number of  pics to save  <<ATTENTION: NEEDS SUFFICIENT FLASH-RAM OR SD-CARD
MIN_SPACE   = 100000    'take pictures only if some space is left on flash or SD-card

'set camera lense orientation according to HW-setup
PIC_V_FLIP  = 1    'Vertical orientation   0 = normal, 1 = flipped
PIC_H_MIRROR= 1    'Horizontal orientation 0 = normal, 1 = flipped

'Set servo orientation according to construction of servo mount
SERVO_H_FLIP= 1    'PAN  servo  0 = normal, 1 = inverted
SERVO_V_FLIP= 0    'TILT servo  0 = normal, 1 = inverted

'----------------------------------------------
'SERVO range  (my settings for two SG90 servos)
SERVO_H_POS = 280  '<<<initial slider position,  if 0 then no servo and no slider 
SERVO_V_POS = 230  '<<<initial slider position,  if 0 then no servo and no slider
SERVO_H_MIN = 100  'horizontal leftmost position
SERVO_H_MAX = 470  'horizontal rightmost position
SERVO_V_MIN = 160  'vertical leftmost position
SERVO_V_MAX = 420  'vertical rightmost position
HSTEP       = 12   'STEP width for automatic panning

SHOW_PARAMS = 0   '0 = starts with CLOSED parameter-menue
ms_per_pic  = 100 '<< 100ms/pic = 10pics/sec at HTML-page <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

M5CAM            = 202 'HW-device-numbers returned by BAS.DEVICE
ESP32CAM         = 201
BUT_OFF$         = "butgreen"
BUT_ON$          = "butred"
SHOW_PARAMS_TXT$ = "SETTINGS=OFF"
MAKE_FOTO_COL$   = BUT_OFF$
MAKE_FOTO_TXT$   = "make FOTO"
ret              = file.mkdir("/images")   'ensure folder for saving pics
FOTO$            = "/images/PIC_1.jpg"
RES_NEW$         = ""
MAKE_UNIQUE$     = str$(millis)
T$               = ""
L                = 0
FOTO_LOCKED      = 0
DateTime$        = ""
SHOW_PARAMS_COL$ = BUT_OFF$
SHOW_PARAMS_TXT$ = "SETTINGS=OFF"
LED_ON_OFF_COL$  = BUT_OFF$
LED_ON_OFF_TXT$  = "LED=OFF"
AUTO_PAN_TXT$    = "AUTO_PAN=OFF"
AUTO_PAN_COL$    = BUT_OFF$
INFO$            = CALL$ + "-CAM " + VERSION$

option.wdt  10000  'watchdog timer 10seconds  
wifi.power  20     'maximize wifi-power

'SERVO-setup if used with pan/tilt servos 
If SERVO_H_POS then gosub SERVO_H_INIT
If SERVO_V_POS then gosub SERVO_V_INIT

'use onboard LEDs only at ESP32CAM not with M5CAM
if BAS.DEVICE = ESP32CAM then
  pin.mode 33, output  'red LED
  pin.mode 4, output   'white LED
  pin(33)        = 0  'rote LED AUS
  pin(4)         = 1  'WHITE LED ON
  pause 100
  pin(4)         = 0   'WHITE LED OFF
endif

gosub        CAM_INIT
if (file.exists(FOTO$) = 0) and (PIC_NUM > 0) then 
 print CAMERA.PICTURE(FOTO$) ' save the first picture
endif
gosub        MAIN
onHtmlReload setpage
gosub        setpage
onHtmlChange paramchange

timer0 250,  MAIN
wait

'#########################################################
'#########################################################
'#########################################################
MAIN:
'#########
if T$ <> time$ then
  L = 1-L  'toggle for LED
  T$ = time$
  DateTime$ = "20" + date$(2) + "_" + T$
  DateTime$ = replace$(DateTime$,"/","-")
  'DateTime$ = replace$(DateTime$,":","-")
  option.wdtreset
  if flashfree <  MIN_SPACE then
    MAKE_FOTO_TXT$ = "NO SPACE FOR FOTO!"
    MAKE_FOTO_COL$ = BUT_ON$
  else
    MAKE_FOTO_TXT$ = "make Foto"
    MAKE_FOTO_COL$ = BUT_OFF$
  endif
endif
IF SERVO_H_POS gosub SERVO_H_SET
IF SERVO_V_POS gosub SERVO_V_SET

'Set new resolution
IF RES_NEW$ <> RES$ goto "res_" + RES_NEW$

if BAS.DEVICE = ESP32CAM pin(33)=1-pin(33)   'toggles the red LED only at ESP32CAM

return

'############################################
setpage:
'#########
A$ = ""
A$ = A$ + |<table><td>| + textbox$(INFO$, "tbox_top") +  textbox$(DateTime$, "tbox_top")
A$ = A$ + |<img id='camera' src="picture" alt="NO PIC from AnnexCam" style="width:112%;">|
A$ = A$ + |<br>|
IF SERVO_H_POS then A$ = A$ + slider$(SERVO_H_POS, SERVO_H_MIN, SERVO_H_MAX, "slider_hor" )
A$ = A$ + |<td>|
IF SERVO_V_POS then A$ = A$ + slider$(SERVO_V_POS, SERVO_V_MIN, SERVO_V_MAX, "slider_vert" )
A$ = A$ + |</table>|
A$ = A$ + "<center>"
'''''A$ = A$ + textbox$(INFO$, "tbox") + LED$(L)+  textbox$(DateTime$, "tbox") + "<br>"
if BAS.DEVICE = ESP32CAM then A$ = A$ + button$(LED_ON_OFF_TXT$, LED_ON_OFF, LED_ON_OFF_COL$)+ " "
A$ = A$ + listbox$(RES_NEW$,"320x240,640x480,800x600,1024x768,1280x1024,1600x1200","lbox")
A$ = A$ + button$(SHOW_PARAMS_TXT$, SHOW_PARAMS_ON_OFF, SHOW_PARAMS_COL$)+ " "
A$ = A$ + button$(MAKE_FOTO_TXT$, MAKE_FOTO, MAKE_FOTO_COL$) + " "
IF SERVO_H_POS then A$ = A$ + button$(AUTO_PAN_TXT$, AUTO_PAN, AUTO_PAN_COL$)
A$ = A$ + "<br></center>"

if SHOW_PARAMS = 1 then
  A$ = A$ + |<center><table>|
  '''A$ = A$ + slider$(quality, 10, 63, "slider") + "<td>jpg-Compression"
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(brightness, -2, 2, "slider2") + "<td>Brightness"
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(contrast, -2, 2, "slider") + "<td>Contrast"
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(saturation, -2, 2, "slider2") + "<td>Saturation"
  A$ = A$ + |<tr><td>|
  'A$ = A$ + checkbox$(awb) + "AWB"
  'A$ = A$ + |<tr><td>|
  'A$ = A$ + checkbox$(awb_gain) + "<td>AWB gain"
  ' this is a checkbox using the variable 'awb_gain' (data-var='awb_gain')
  A$ = A$ + |<div class="onoffswitch">|
  A$ = A$ + |    <input type="checkbox" data-var='awb_gain' onchange='cmdChange(event)' class="onoffswitch-checkbox" id="mycheck1" checked>|
  A$ = A$ + |    <label class="onoffswitch-label" for="mycheck1">|
  A$ = A$ + |        <span class="onoffswitch-inner"></span>|
  A$ = A$ + |        <span class="onoffswitch-switch"></span>|
  A$ = A$ + |    </label>|
  A$ = A$ + |</div>|
  A$ = A$ + |<td> AWB gain|
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(wb_mode, 0, 4, "slider") + "<td>WB mode"
  A$ = A$ + |<tr><td>|
  'A$ = A$ + checkbox$(aec) + "AEC "
  'A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(ae_level, -2, 2, "slider2" ) + "<td>AE Level"
  A$ = A$ + |<tr><td>|
  ' this is a checkbox using the variable 'aec2' (data-var='aec2')
  A$ = A$ + |<div class="onoffswitch">|
  A$ = A$ + |    <input type="checkbox" data-var='aec2' onchange='cmdChange(event)' class="onoffswitch-checkbox" id="mycheck2" checked>|
  A$ = A$ + |    <label class="onoffswitch-label" for="mycheck2">|
  A$ = A$ + |        <span class="onoffswitch-inner2"></span>|
  A$ = A$ + |        <span class="onoffswitch-switch"></span>|
  A$ = A$ + |    </label>|
  A$ = A$ + |</div>|
  A$ = A$ + |<td> AEC 2|
  A$ = A$ + |</table><center>|
  A$ = A$ + |</center></table></center>|
  
else
  ' Compute links to stored fotos. The fotos open in a NEW window
  ' This prevents from opening to many files (max 5!)  on the CAM-webserver at the same time
  A$ = A$ + |<center>SHOW  <a href="/images/PIC_1.jpg" target="_blank"> THE LATEST FOTO </a> IN A NEW WINDOW </center>|
  A$ = A$ + |<center>SHOW |
  for I = 1 to PIC_NUM
    A$ = A$ + | <a href="/images/PIC_|+ str$(I) +|.jpg?dummy=|+ MAKE_UNIQUE$ + |" target="_blank"> PIC_|+ str$(I) +| ,  </a> |
  next I
  if flashfree <  MIN_SPACE then
    A$ = A$ + "<br>"+ button$("DELETE ALL FOTOS", DELETE_FOTOS, BUT_ON$) + "<br>"
    
  endif
endif
cls
html a$
a$ = ""
autorefresh 1000
jscall "set_pictimer(" + str$(ms_per_pic) + ");"
a$ = ""

CSS cssid$("slider_vert", "position: relative;right: 130%;transform:rotate(-90deg);height:80px;width:400%; ")
CSS cssid$("slider_hor", "position: relative; top: -30px;height:20px;width:110%; ")
CSS cssid$(BUT_ON$, "background-color:red;;height:50px;")
CSS cssid$(BUT_OFF$, "background-color:#44c767;height:50px;")
CSS cssid$("butyellow", "background-color:#ffec64;height:50px;")
CSS cssid$("tbox","text-align: center; background-color:lightgrey;")
CSS cssid$("tbox_top","text-align: left;position: relative;top: 30px; background-color:lightgrey;opacity: 0.3;")
CSS cssid$("lbox", "background-color:#44c767;;height:50px;")

return

'############################################
DELETE_FOTOS:
'#########
D$ = FILE.DIR$("/images/*.jpg")
While D$ <> ""
  r = file.delete("/images/"+ D$)
  D$ = FILE.DIR$
Wend
gosub setpage
return


'############################################
AUTO_PAN:
'#########
'Toggle AUTO_PAN ON or OFF
if AUTO_PAN_TXT$ = "AUTO_PAN=OFF" then
  AUTO_PAN_TXT$ = "AUTO_PAN=ON"
  AUTO_PAN_COL$ = BUT_ON$
  gosub AUTO_PAN_STEP
  timer1 4000,AUTO_PAN_STEP  'more auto-panning each 4 seconds
else
  AUTO_PAN_TXT$ = "AUTO_PAN=OFF"
  AUTO_PAN_COL$ = BUT_OFF$
  timer1 0                   'stopp auto-panning
endif
gosub setpage
return

'############################################
AUTO_PAN_STEP:
'#########
'slowly pan the camera completely and endlessly
' as this is called every 3 seconds by timer1
if SERVO_H_POS> SERVO_H_MAX then HSTEP = 0-abs(HSTEP)
if SERVO_H_POS< SERVO_H_MIN then HSTEP = abs(HSTEP)
SERVO_H_POS = SERVO_H_POS + HSTEP
return


'############################################
LED_ON_OFF:
'#########
pin(4)=1-pin(4)
if pin(4)= 0 then
  LED_ON_OFF_COL$ = BUT_OFF$
  LED_ON_OFF_TXT$ = "LED=OFF"
else
  LED_ON_OFF_COL$ = "butyellow"
  LED_ON_OFF_TXT$ = "LED=ON"
endif
gosub setpage
return

'############################################
MAKE_FOTO:
'#########
IF not FOTO_LOCKED then   'Prevent a parallel second start
  FOTO_LOCKED      = 1
  if flashfree >  MIN_SPACE then
    MAKE_FOTO_TXT$ = "--WAIT---"
    MAKE_FOTO_COL$ = BUT_ON$
    ms_per_pic_old = ms_per_pic
    ms_per_pic     = 3000  'slow down live frame rate to give time to take and save the full pic
    gosub setpage
    pause 500
    FOTO$          = "/images/PIC_"+STR$(PIC_NUM+1)+".jpg"
    if file.exists(FOTO$) then print file.delete(FOTO$)
    for I = (PIC_NUM) to 1 step -1
      print file.rename("/images/PIC_"+STR$(I)+".jpg","/images/PIC_"+STR$(I+1)+".jpg")
    next I
    FOTO$          = "/images/PIC_1.JPG"
    print CAMERA.PICTURE(FOTO$) ' ###### save the picture ####
    MAKE_FOTO_TXT$ = "make FOTO"
    MAKE_FOTO_COL$ = BUT_OFF$
  else
    MAKE_FOTO_TXT$ = "NO SPACE FOR FOTO!"
    MAKE_FOTO_COL$ = BUT_ON$
    gosub setpage
  endif
  MAKE_UNIQUE$   = str$(millis)
  ms_per_pic     = ms_per_pic_old
  gosub setpage
  FOTO_LOCKED    = 0
endif
return

'############################################
SHOW_PARAMS_ON_OFF:
'#########
SHOW_PARAMS = 1-SHOW_PARAMS
IF SHOW_PARAMS = 0 then
  SHOW_PARAMS_COL$ = BUT_OFF$
  SHOW_PARAMS_TXT$ = "SETTINGS=OFF"
else
  SHOW_PARAMS_COL$ = BUT_ON$
  SHOW_PARAMS_TXT$ = "SETTINGS=ON"
endif
gosub setpage
refresh
return

'############################################
res_320x240:
'#########
print camera.params("framesize", 4)
RES$="320x240"
return

'############################################
res_640x480:
'#########
print camera.params("framesize", 6)
RES$="640x480"
gosub setpage
return

'############################################
res_800x600:
'#########
print camera.params("framesize", 7)
RES$="800x600"
gosub setpage
return

'############################################
res_1024x768:
'#########
print camera.params("framesize", 8)
RES$="1024x768"
gosub setpage
return

'############################################
res_1280x1024:
'#########
print camera.params("framesize", 9)
RES$="1280x1024"
gosub setpage
return

'############################################
res_1600x1200:
'#########
print camera.params("framesize", 10)
RES$="1600x1200"
gosub setpage
return

'############################################
v_flip:
'#########
v = camera.getvalue("vflip")
print camera.params("vflip", 1 - v)
return

'############################################
h_mirror:
'#########
v = camera.getvalue("hmirror")
print camera.params("hmirror", 1 - v)
return

'############################################
paramchange:
'#########
V$=""
if VX$ <> "X" print HtmlEventVar$
if VX$ <> "X" v$ = HtmlEventVar$
if (vx$ = "X") or (v$ = "quality")     then print camera.params("quality", quality)
if (vx$ = "X") or (v$ = "brightness")  then print camera.params("brightness", brightness)
if (vx$ = "X") or (v$ = "contrast")    then print camera.params("contrast", contrast)
if (vx$ = "X") or (v$ = "saturation")  then print camera.params("saturation", saturation)
if (vx$ = "X") or (v$ = "awb")         then print camera.params("awb", awb)
if (vx$ = "X") or (v$ = "awb_gain")    then print camera.params("awb_gain", awb_gain)
if (vx$ = "X") or (v$ = "wb_mode")     then print camera.params("wb_mode", wb_mode)
if (vx$ = "X") or (v$ = "aec")         then print camera.params("aec", aec)
if (vx$ = "X") or (v$ = "aec2")        then print camera.params("aec2", aec2)
if (vx$ = "X") or (v$ = "ae_level")    then print camera.params("ae_level", ae_level)
if (vx$ = "X") or (v$ = "agc")         then print camera.params("agc", agc)
if (vx$ = "X") or (v$ = "agc_gain")    then print camera.params("agc_gain", agc_gain)
if (vx$ = "X") or (v$ = "gainceiling") then print camera.params("gainceiling", gainceiling)
vx$ = ""
return

'######################################################################

SERVO_H_INIT:
'Horizontal servo -------------------------------
S_H  = SERVO_H_POS
if BAS.DEVICE = ESP32CAM SERVO_H_PIN  = 12 'FOR ESP32CAM
if BAS.DEVICE = M5CAM    SERVO_H_PIN  = 13 'FOR M5CAM only
SERVO_H_CHAN = 7
PWM.SETUP SERVO_H_PIN, SERVO_H_CHAN, SERVO_H_POS, 50, 12
GOSUB SERVO_H_SET
pause 1000
return

'######################################################################

SERVO_V_INIT:
'Vertical servo -------------------------------
S_V  = SERVO_V_POS
if BAS.DEVICE = ESP32CAM SERVO_V_PIN  = 3   '= RX-Pin!!!!            '<<<<<<<<<<<<<<<
if BAS.DEVICE = M5CAM    SERVO_V_PIN  = 4   'FOR M5CAM only
SERVO_V_CHAN = 8
PWM.SETUP SERVO_V_PIN, SERVO_V_CHAN, SERVO_V_POS, 50, 12
GOSUB SERVO_V_SET
return

'############################################
SERVO_H_SET:
'#########
if abs(S_H - SERVO_H_POS)> 4 then
  S_H = int( S_H+((SERVO_H_POS - S_H )/10))
  if SERVO_H_FLIP then
    PWM.OUT SERVO_H_CHAN, (600-S_H)        '<<<<<<<<<<horizontal servo inverted
  else
    PWM.OUT SERVO_H_CHAN, (S_H)            '<<<<<<<<<<horizontal servo normal
  endif
endif
return

'############################################
SERVO_V_SET:
'#########
if abs (S_V - SERVO_V_POS) > 4 then
  S_V = int( S_V+((SERVO_V_POS - S_V )/10))
  if SERVO_V_FLIP then
    PWM.OUT SERVO_V_CHAN, (600 - S_V)                '<<<<<<<<<<vertical servo inverted
  else
    PWM.OUT SERVO_V_CHAN, (S_V)                      '<<<<<<<<<<vertical servo normal
  endif
endif
return


'############################################
CAM_INIT:
'#########
' variables with CAM parameters
quality     = 10   : brightness  = 0
contrast    = 0    : saturation  = 0
awb         = 1    : awb_gain    = 1
wb_mode     = 0    : aec         = 0
aec2        = 1    : ae_level    = 0
agc         = 0    : agc_gain    = 0
gainceiling = 0

vx$ ="X"           ' "X" = change all parameters 
gosub paramchange  ' initialize camera with this parameters

'set CAM-ORIENTATION
print camera.params("vflip",  PIC_V_FLIP)
print camera.params("hmirror",PIC_H_MIRROR)

'set initial CAM-resolution            '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
'gosub res_800x600
gosub res_1024x768
'gosub res_1280x1024
RES_NEW$ = RES$
if file.exists(FOTO$) = 0 then print CAMERA.PICTURE(FOTO$) ' save the first picture
return



And that is the web interface:
IMG_6542.PNG
IMG_6543.PNG
IMG_6544.PNG
You do not have the required permissions to view the files attached to this post.
User avatar
PANNO
Posts: 114
Joined: Thu Feb 25, 2021 4:03 am
Has thanked: 119 times
Been thanked: 25 times

Re: Servo-CAM with M5CAMERA or ESP32CAM and two SG90 servos

Post by PANNO »

Great Idea ! A full Motion Web Cam with Ftp Support and no data Spy . Maybe u can use Face detection and if you have found a Face change the Camera Resolution.

Btw: holiday on Balkonien ?

Gtx
User avatar
PeterN
Posts: 366
Joined: Mon Feb 08, 2021 7:56 pm
Location: Krefeld, Germany
Has thanked: 171 times
Been thanked: 203 times
Contact:

Re: Servo-CAM with M5CAMERA or ESP32CAM and two SG90 servos

Post by PeterN »

Hi panno,

that's an interesting thought - toggeling the resolution between 320x240 (for facedetection and autopositioning) and a higher value - I will try!

And yes - my place for the hobby often has only one wall in this summertime :-)

I posted some more thoughts about this - including your suggestion at https://peterneufeld.wordpress.com/2021 ... h-annex32/
User avatar
cicciocb
Site Admin
Posts: 1889
Joined: Mon Feb 03, 2020 1:15 pm
Location: Toulouse
Has thanked: 405 times
Been thanked: 1260 times
Contact:

Re: Servo-CAM with M5CAMERA or ESP32CAM and two SG90 servos

Post by cicciocb »

Very nice application, as usual, Peter.
lyizb
Posts: 93
Joined: Fri Feb 12, 2021 8:23 pm
Has thanked: 36 times
Been thanked: 23 times

Re: Servo-CAM with M5CAMERA or ESP32CAM and two SG90 servos

Post by lyizb »

Clever mounting of the pan servo to the base--I never thought of that, and have produced convoluted mechanisms instead. I also like the springy folding of the cable on the camera--excellent idea.

Very neat and compact arrangement overall--thanks for posting.
User avatar
PeterN
Posts: 366
Joined: Mon Feb 08, 2021 7:56 pm
Location: Krefeld, Germany
Has thanked: 171 times
Been thanked: 203 times
Contact:

Re: Servo-CAM with M5CAMERA or ESP32CAM and two SG90 servos

Post by PeterN »

Hello to all AnnexCam co-enthusiasts,

I updated my code for the pan/tilt camera to work with Annex ESPCam V1.48.22.
The firmware seems to be much faster now :-)
I did some ugly workaround to actually transmit the latest photo with telegram as there currently is a problem with the four pictures held in the internal buffer.
Hope my comments add well to the code and make it a good starting point for further experimentation.

Code: [Local Link Removed for Guests]

' A N N E X 3 2 C A M - p r o g r a m
'  - show a life camera picture in browser in some resolutions
'  - control the pan/tilt servos (manually or auto-pan)
'  - take some still pictures in NV-RAM or on SD-Card
'  - control the onboard white LED (ESP32CAM only)
'  - set some camera parameters via web-interface
'  - CONNECT TO A TELEGRAM BOT
'   -- return a current camera picture via the telegram BOT
'   -- set servo position by some one-letter commands via the telegram BOT
' Hardware:
'   ESP32CAM  or M5CAM version "B"  with or without two servos
'     ESP32CAM : H-Servo at Pin GPIO12; V-Servo at Pin GPIO3 = RX
'     M5CAM    : H-Servo at Pin GPIO4;  V-Servo at Pin GPIO13; pins at grove-port
' DB9JG@ME:COM   2021/08

' 2022/11: V10.4 Changes of resolution/framesize table  in AnnexCam 1.48.22
' 2022/12: V10.5 No Telegram if in AP-Modus (IP=192.168.4.1)
'          workaround for ANNEXCAM 1.48.22 addressing the wrong/eldest pic in the 4 pic buffer

VERSION$    = "V10.5"
WLOG "ANNEX32CAM "; VERSION$
option.wdt  45000  'watchdog timer 45seconds, as Telegram seems to freeze the system sometimes


'MY_NAME$      = "DB9JG"
MY_NAME$      = "PeterN"
'MY_NAME$       = "PeterN1"

TELEGRAM_activated         = 1   ' 1 >> activate TELEGRAM-BOT
TELEGRAM_still_running     = 0
TELEGRAM_MAX_FAILED        = 10  'reboot if connection to telegram is lost for x *5 seconds
TELEGRAM_REFRESH           = 12000
no_cmd_count               = 0
if word$(IP$,1)="192.168.4.1" then TELEGRAM_ACTIVATED = 0 'deactivate if in AP-Mode, thus no Internet

'Save snapshots in local NVRAM or SD (if ANNEX runs on the SD)?
'PIC_NUM    = 0 ' => do not save or show  pics
PIC_NUM     = 2 ' number of  pics to save  <<ATTENTION: NEEDS SUFFICIENT FLASH-RAM OR SD-CARD
MIN_SPACE   = 100000    'take pictures only if some space is left on flash or SD-card

'set camera lense orientation according to HW-setup
PIC_V_FLIP  = 1    'Vertical orientation   0 = normal, 1 = flipped -------M5
PIC_H_MIRROR= 1    'Horizontal orientation 0 = normal, 1 = flipped -------M5
'PIC_V_FLIP  = 0    'Vertical orientation   0 = normal, 1 = flipped
'PIC_H_MIRROR= 0    'Horizontal orientation 0 = normal, 1 = flipped


SERVO_H     = 1   ' 1 == a hori servo is connected
SERVO_V     = 0   ' 1 == a vert servo is connected
'----------------------------------------------
'SERVO range  (my settings for two SG90 servos)
SERVO_H_POS = 280  '<<<initial slider position
SERVO_V_POS = 230  '<<<initial slider position
SERVO_H_MIN = 100  'horizontal leftmost position
SERVO_H_MAX = 470  'horizontal rightmost position
SERVO_V_MIN = 160  'vertical leftmost position
SERVO_V_MAX = 420  'vertical rightmost position
HSTEP       = 20   'STEP width for automatic panning

'Set servo orientation according to construction of servo mount
SERVO_H_FLIP= 1    'PAN  servo  0 = normal, 1 = inverted -------M5
SERVO_V_FLIP= 0    'TILT servo  0 = normal, 1 = inverted -------M5
'SERVO_H_FLIP= 1    'PAN  servo  0 = normal, 1 = inverted
'SERVO_V_FLIP= 1    'TILT servo  0 = normal, 1 = inverted

'SERVO_H_FLIP= 0    'PAN  servo  0 = normal, 1 = inverted

SHOW_PARAMS   = 0   '0 = starts with CLOSED parameter-menue
ms_per_pic    = 100 '<< 100ms/pic = 10pics/sec at HTML-page <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
'ms_per_pic    = 330 '<< 3pics/sec at HTML-page <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
ms_per_pic_old= ms_per_pic
M5CAM            = 202 'HW-device-numbers returned by BAS.DEVICE
ESP32CAM         = 201
BUT_OFF$         = "butgreen"
BUT_ON$          = "butred"
SHOW_PARAMS_TXT$ = "SETTINGS=OFF"
MAKE_FOTO_COL$   = BUT_OFF$
MAKE_FOTO_TXT$   = "make FOTO"
ret              = file.mkdir("/images")   'ensure folder for saving pics
FOTO$            = "/images/PIC_1.jpg"
LAST_IP_file$    = "/LAST_IP.txt"
LAST_IP$         = ""
RES_NEW$         = ""
MAKE_UNIQUE$     = str$(millis)
T$               = ""
TIME_OLD$        = ""
TELEGRAM_MAX_FAILED_COUNTER= 0
L                = 0
FOTO_LOCKED      = 0
DateTime$        = ""
SHOW_PARAMS_COL$ = BUT_OFF$
SHOW_PARAMS_TXT$ = "SETTINGS=OFF"
LED_ON_OFF_COL$  = BUT_OFF$
LED_ON_OFF_TXT$  = "LED=OFF"
AUTO_PAN_TXT$    = "AUTO_PAN=OFF"
AUTO_PAN_COL$    = BUT_OFF$
INFO$            = MY_NAME$ + "-CAM " + VERSION$
count_s          = 0
meter            = 0

flashfree_x = flashfree


'SERVO-setup if used with pan/tilt servos
If SERVO_H then gosub SERVO_H_INIT
If SERVO_V then gosub SERVO_V_INIT

'use the two onboard LEDs only at ESP32CAM but not with M5CAM
if BAS.DEVICE = ESP32CAM then
  pin.mode 33, output  'red LED
  pin.mode 4, output   'white LED
  pin(33)        = 0   'red LED OFF
  pin(4)         = 1   'WHITE LED ON
  pause 100
  pin(4)         = 0   'WHITE LED OFF
endif

gosub        CAM_INIT
if (file.exists(FOTO$) = 0) and (PIC_NUM > 0) then
  WLOG  CAMERA.PICTURE(FOTO$) ' save the very first picture
endif

gosub        MAIN
onHtmlReload setpage
gosub        setpage
onHtmlChange paramchange

IF TELEGRAM_activated then
  gosub TELEGRAM_INIT
  pause 2000
endif

timer0 250,  MAIN
wait
'##################
'##################
'##################

'#########################################################
TELEGRAM_INIT:
WLOG "The TELEGRAM-Token now used, is the token for the user and BOT    @"; MY_NAME$; "_BOT"
IF MY_NAME$ = "PeterN"  telegram.settoken "xxxxxxxxxx:AAEvrEjHxjdV1CdfmFpZu8BOZdCjKvd5nQ0" '@yyyyyyyyyy
IF MY_NAME$ = "PeterN1" telegram.settoken "xxxxxxxxxx:AAHz6T9Lmlduu0xxz43GtYmoB9qHubU-Y0s" '@yyyyyyyyyy
IF MY_NAME$ = "DB9JG"   telegram.settoken "xxxxxxxxxx:AAEvrEjHxjdV1CdfmFpZu8BOZdCjKvd5nQ0" '@yyyyyyyyyy


telegram.setwait   8
telegram.setmode   0
onwgetasync        TELEGRAM_asynco

'Get the update only each 15 seconds to keep traffic low;
'This initial request-rate is set to 5000 in "TELEGRAM_asynco" if the Telegram_bot is actually used
timer1 TELEGRAM_REFRESH, TELEGRAM_getMessage
return



'#########################################################
TELEGRAM_getMessage:
'#########
WLOG  time$;": TELEGRAM_getMessage:"
telegram.GetUpdatesAsync
return

'#########################################################
TELEGRAM_asynco:
'#########
'Receive the messages
if TELEGRAM_still_running then return
TELEGRAM_still_running = 1
timer0 0
timer1 0  'avoid any interruption
r$ = WGETRESULT$
'onwgetasync   off   '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
WLOG "The TELEGRAM_BOT-Service for "; MY_NAME$;"_BOT returns at  "; Time$; ": "; r$
if instr(lcase$(r$)," failed") then
  TELEGRAM_MAX_FAILED_COUNTER = TELEGRAM_MAX_FAILED_COUNTER + 1
  WLOG "The TELEGRAM_BOT-Service failed; REBOOT countdown initialized : ", str$(TELEGRAM_MAX_FAILED - TELEGRAM_MAX_FAILED_COUNTER)
  if TELEGRAM_MAX_FAILED_COUNTER = TELEGRAM_MAX_FAILED then
    WLOG "REBOOT NOW..."
    reboot
  endif
endif

if instr(r$,|"ok"|) then TELEGRAM_MAX_FAILED_COUNTER = 0

c$ = json$(r$, "chat.id")   'get the chat_id
t$=""
text$ = json$(r$, "text")
if (text$ <> "not found") then
  text$=replace$(text$,"/","") ' now the command may, but must not include a  leading /
  select case left$(lcase$(text$),1)
    case "l" :
      for i= 1 to word.count(lcase$(text$),"l")-1
        SERVO_H_POS = SERVO_H_POS - 50 : t$="Moved left"
      next i
    case "r" :
      for i= 1 to word.count(lcase$(text$),"r")-1
        SERVO_H_POS = SERVO_H_POS + 50 : t$="Moved right"
      next i
    case "x" :
      SERVO_H_POS = 280
      SERVO_V_POS = 230
      t$="Moved to center position"
    case "u" : SERVO_V_POS = SERVO_V_POS + 40 : t$="Moved up"
    case "d" : SERVO_V_POS = SERVO_V_POS - 40 : t$="Moved down"
    case "i" : t$=" Local IP-Adress is " + word$(IP$,1)
      
  end select
  t$=replace$(t$,"Moved",word$(IP$,1)&" was moved")
  if SERVO_H_POS > SERVO_H_MAX then SERVO_H_POS = SERVO_H_MAX
  if SERVO_H_POS < SERVO_H_MIN then SERVO_H_POS = SERVO_H_MIN
  if SERVO_V_POS > SERVO_V_MAX then SERVO_V_POS = SERVO_V_MAX
  if SERVO_V_POS < SERVO_V_MIN then SERVO_V_POS = SERVO_V_MIN
  
  S_H = SERVO_H_POS + 5
  if SERVO_H gosub SERVO_H_SET
  S_V = SERVO_V_POS + 5
  if SERVO_V gosub SERVO_V_SET
  
  WLOG telegram.sendmessage$(val(c$),MY_NAME$+"_BOT-CAM at IP-Adr "+word$(IP$,1)+" : One moment please ... " )
  gosub MAKE_FOTO
  If  MAKE_FOTO_TXT$ <> "NO SPACE FOR FOTO!" then
    WLOG telegram.sendimage$(val(c$), FOTO$)
  else
    WLOG telegram.sendmessage$(val(c$),TIME$ + " " + MAKE_FOTO_TXT$ )
  endif
  If t$ <> "" then
    WLOG telegram.sendmessage$(val(c$),TIME$ + " " + MY_NAME$+"_BOT-CAM at " + t$ )
  else
    WLOG telegram.sendmessage$(val(c$),MY_NAME$+"_BOT-CAM at IP-Adr "+word$(IP$,1)+"  Move me with  l=left r=right x=center; u=up; d=down " )
    
  end if
  'Set a lower refresh-rate from now on, if a command was acually received via  the telegram bot
  TELEGRAM_REFRESH = 5000
else
  no_cmd_count=no_cmd_count+1
  if no_cmd_count > 30 then  'reduce Telegram-request-rate again, if no cmd received for a while
    no_cmd_count=0
    TELEGRAM_REFRESH = 12000
  endif
end if
timer1 TELEGRAM_REFRESH, TELEGRAM_getMessage
TELEGRAM_still_running = 0
timer0 250,  MAIN
'onwgetasync  TELEGRAM_asynco
return


'#########################################################
'#########################################################
'#########################################################
MAIN:
'#########
if TIME_OLD$ <> time$ then
  'only once per sec
  TIME_OLD$ = time$
  DateTime$ = "20" + date$(2) + "_" + TIME_OLD$
  DateTime$ = replace$(DateTime$,"/","-")
  
  if count_s = 10 then       ' every 10s
    flashfree_x = flashfree
    count_s = 0
    option.wdtreset
  endif
  count_s = count_s + 1
  meter   = val(right$(time$,2)) 'to show the  activ connection at webpage
  
  if flashfree_x <  MIN_SPACE then
    MAKE_FOTO_TXT$ = "NO SPACE FOR FOTO!"
    MAKE_FOTO_COL$ = BUT_ON$
  else
    MAKE_FOTO_TXT$ = "make Foto"
    MAKE_FOTO_COL$ = BUT_OFF$
  endif
  if BAS.DEVICE = ESP32CAM pin(33)=1-pin(33)   'toggles the red LED only at ESP32CAM
endif
IF SERVO_H gosub SERVO_H_SET
IF SERVO_V gosub SERVO_V_SET

'Set new resolution
IF RES_NEW$ <> RES$ goto "res_" + RES_NEW$
if word$(IP$,1)="192.168.4.1" then
  if BAS.DEVICE = ESP32CAM pin(33)=1-pin(33)   'toggles the red LED FAST if in AP-Mode (only at ESP32CAM)
endif
return

'############################################
setpage:
'#########
A$ = ""
A$ = A$ + |<table><td>| + textbox$(INFO$, "tbox_top")  +  textbox$(DateTime$, "tbox_top")
A$ = A$ + |<img id='camera' src="picture" alt="NO PIC from AnnexCam" style="width:112%;">|
A$ = A$ + |<br>|
IF SERVO_H then A$ = A$ + slider$(SERVO_H_POS, SERVO_H_MIN, SERVO_H_MAX, "slider_hor" )
A$ = A$ + |<td>|
IF SERVO_V then A$ = A$ + slider$(SERVO_V_POS, SERVO_V_MIN, SERVO_V_MAX, "slider_vert" )
A$ = A$ + |</table>|
A$ = A$ +"<center>"+ meter$(meter,0,60,"meter")
A$ = A$ + "<center>"
if BAS.DEVICE = ESP32CAM then A$ = A$ + button$(LED_ON_OFF_TXT$, LED_ON_OFF, LED_ON_OFF_COL$)+ " "
A$ = A$ + listbox$(RES_NEW$,"320x240,640x480,800x600,1024x768,1280x1024,1600x1200","lbox")
A$ = A$ + button$(SHOW_PARAMS_TXT$, SHOW_PARAMS_ON_OFF, SHOW_PARAMS_COL$)+ " "
A$ = A$ + button$(MAKE_FOTO_TXT$, MAKE_FOTO, MAKE_FOTO_COL$) + " "
IF SERVO_H then A$ = A$ + button$(AUTO_PAN_TXT$, AUTO_PAN, AUTO_PAN_COL$)
A$ = A$ + "<br></center>"

if SHOW_PARAMS = 1 then
  A$ = A$ + |<center><table>|
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(brightness, -2, 2, "slider2") + "<td>Brightness"
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(contrast, -2, 2, "slider") + "<td>Contrast"
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(saturation, -2, 2, "slider2") + "<td>Saturation"
  A$ = A$ + |<tr><td>|
  'A$ = A$ + checkbox$(awb) + "AWB"
  'A$ = A$ + |<tr><td>|
  'A$ = A$ + checkbox$(awb_gain) + "<td>AWB gain"
  ' this is a checkbox using the variable 'awb_gain' (data-var='awb_gain')
  A$ = A$ + |<div class="onoffswitch">|
  A$ = A$ + |    <input type="checkbox" data-var='awb_gain' onchange='cmdChange(event)' class="onoffswitch-checkbox" id="mycheck1" checked>|
  A$ = A$ + |    <label class="onoffswitch-label" for="mycheck1">|
  A$ = A$ + |        <span class="onoffswitch-inner"></span>|
  A$ = A$ + |        <span class="onoffswitch-switch"></span>|
  A$ = A$ + |    </label>|
  A$ = A$ + |</div>|
  A$ = A$ + |<td> AWB gain|
  A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(wb_mode, 0, 4, "slider") + "<td>WB mode"
  A$ = A$ + |<tr><td>|
  'A$ = A$ + checkbox$(aec) + "AEC "
  'A$ = A$ + |<tr><td>|
  A$ = A$ + slider$(ae_level, -2, 2, "slider2" ) + "<td>AE Level"
  A$ = A$ + |<tr><td>|
else
  'Compute links to stored fotos. The fotos open in a NEW window
  'This prevents from opening to many files (max 5!) an connections on the CAM-webserver at the same time
  A$ = A$ + |<center>SHOW  <a href="/images/PIC_1.jpg" target="_blank"> THE LATEST FOTO </a> IN A NEW WINDOW </center>|
  A$ = A$ + |<center>SHOW |
  for I = 1 to PIC_NUM
    A$ = A$ + | <a href="/images/PIC_|+ str$(I) +|.jpg?dummy=|+ MAKE_UNIQUE$ + |" target="_blank"> FOTO_|+ str$(I) +| ,  </a> |
  next I
  if flashfree_x <  MIN_SPACE then
    A$ = A$ + "<br>"+ button$("DELETE ALL FOTOS", DELETE_FOTOS, BUT_ON$) + "<br>"
  endif
endif
cls
autorefresh 1000
html a$
jscall "set_pictimer(" + str$(ms_per_pic) + ");"

CSS cssid$("slider_vert", "position: relative;right: 130%;transform:rotate(-90deg);height:80px;width:400%; ")
CSS cssid$("slider_hor", "position: relative; top: -30px;height:20px;width:100%; ")
CSS cssid$(BUT_ON$, "background-color:red;;height:50px;")
CSS cssid$(BUT_OFF$, "background-color:#44c767;height:50px;")
CSS cssid$("butyellow", "background-color:#ffec64;height:50px;")
CSS cssid$("tbox","text-align: center; background-color:lightgrey;")
CSS cssid$("tbox_top","text-align: left;position: relative;top: 30px; background-color:lightgrey;opacity: 0.5;")
CSS cssid$("lbox", "background-color:#44c767;;height:50px;")
CSS cssid$("meter", "height:12px;width:100%;opacity: 0.3;")

return

'############################################
DELETE_FOTOS:
'#########
D$ = FILE.DIR$("/images/*.jpg")
While D$ <> ""
  rr = file.delete("/images/"+ D$)
  D$ = FILE.DIR$
Wend
gosub setpage
return

'############################################
AUTO_PAN:
'#########
'Toggle hor servo  AUTO_PAN ON or OFF
if AUTO_PAN_TXT$ = "AUTO_PAN=OFF" then
  AUTO_PAN_TXT$ = "AUTO_PAN=ON"
  AUTO_PAN_COL$ = BUT_ON$
  gosub AUTO_PAN_STEP
  timer1 5000,AUTO_PAN_STEP  'more auto-panning each 4 seconds, BUT NO MORE TELEGRAM
else
  AUTO_PAN_TXT$ = "AUTO_PAN=OFF"
  AUTO_PAN_COL$ = BUT_OFF$
  timer1 0                   'stopp auto-panning
  IF TELEGRAM_activated then
    TELEGRAM_REFRESH = 12000
    gosub TELEGRAM_INIT
  endif
endif
gosub setpage
return

'############################################
AUTO_PAN_STEP:
'#########
'slowly pan the camera completely and endlessly
' as this is called every 3 seconds by timer1
if SERVO_H_POS> SERVO_H_MAX then HSTEP = 0-abs(HSTEP)
if SERVO_H_POS< SERVO_H_MIN then HSTEP = abs(HSTEP)
SERVO_H_POS = SERVO_H_POS + HSTEP
return

'############################################
LED_ON_OFF:
'#########
pin(4)=1-pin(4)
if pin(4)= 0 then
  LED_ON_OFF_COL$ = BUT_OFF$
  LED_ON_OFF_TXT$ = "LED=OFF"
else
  LED_ON_OFF_COL$ = "butyellow"
  LED_ON_OFF_TXT$ = "LED=ON"
endif
gosub setpage
return

'############################################
MAKE_FOTO:
'#########
IF not FOTO_LOCKED then   'Prevent a parallel second start
  FOTO_LOCKED      = 1
  if flashfree >  MIN_SPACE then
    MAKE_FOTO_TXT$ = "--WAIT---"
    MAKE_FOTO_COL$ = BUT_ON$
    ms_per_pic_old = ms_per_pic
    ms_per_pic     = 3000  'slow down live frame rate to give time to take and save the full pic
    gosub setpage
    '   pause 200
    FOTO$          = "/images/PIC_"+STR$(PIC_NUM)+".jpg"
    if file.exists(FOTO$) then WLOG  file.delete(FOTO$)
    for p = (PIC_NUM-1) to 1 step -1
      WLOG  file.rename("/images/PIC_"+STR$(P)+".jpg","/images/PIC_"+STR$(P+1)+".jpg")
    next P
    FOTO$          = "/images/PIC_1.JPG"
    WLOG  CAMERA.PICTURE(FOTO$) ' ###### save the picture ####
    'workaround for ANNEXCAM 1.48.22 adressing the wrong pic in the 4 pic buffer
    if bas.ver = 1.482 then
      WLOG  CAMERA.PICTURE(FOTO$) ' ###### save the picture ####
      WLOG  CAMERA.PICTURE(FOTO$) ' ###### save the picture ####
      WLOG  CAMERA.PICTURE(FOTO$) ' ###### save the picture ####
      WLOG  CAMERA.PICTURE(FOTO$) ' ###### save the picture ####
    endif
    MAKE_FOTO_TXT$ = "make FOTO"
    MAKE_FOTO_COL$ = BUT_OFF$
  else
    MAKE_FOTO_TXT$ = "NO SPACE FOR FOTO!"
    MAKE_FOTO_COL$ = BUT_ON$
    gosub setpage
  endif
  MAKE_UNIQUE$   = str$(millis)
  ms_per_pic     = ms_per_pic_old
  gosub setpage
  FOTO_LOCKED    = 0
endif
return

'############################################
SHOW_PARAMS_ON_OFF:
'#########
SHOW_PARAMS = 1-SHOW_PARAMS
IF SHOW_PARAMS = 0 then
  SHOW_PARAMS_COL$ = BUT_OFF$
  SHOW_PARAMS_TXT$ = "SETTINGS=OFF"
else
  SHOW_PARAMS_COL$ = BUT_ON$
  SHOW_PARAMS_TXT$ = "SETTINGS=ON"
endif
gosub setpage
refresh
return

'############################################
res_320x240:
'#########
WLOG camera.params("framesize", 5)
RES$="320x240"
gosub setpage
return

'############################################
res_640x480:
'#########
WLOG camera.params("framesize", 8)
RES$="640x480"
gosub setpage
return

'############################################
res_800x600:
'#########
WLOG camera.params("framesize", 9)
RES$="800x600"
gosub setpage
return

'############################################
res_1024x768:
'#########
WLOG camera.params("framesize", 10)
RES$="1024x768"
gosub setpage
return

'############################################
res_1280x1024:
'#########
WLOG camera.params("framesize", 12)
RES$="1280x1024"
gosub setpage
return

'############################################
res_1600x1200:
'#########
WLOG camera.params("framesize", 13)
RES$="1600x1200"
gosub setpage
return

'############################################
v_flip:
'#########
v = camera.getvalue("vflip")
WLOG camera.params("vflip", 1 - v)
return

'############################################
h_mirror:
'#########
v = camera.getvalue("hmirror")
WLOG camera.params("hmirror", 1 - v)
return

'############################################
paramchange:
'#########
V$=""
if VX$ <> "X" WLOG  HtmlEventVar$
if VX$ <> "X" v$ = HtmlEventVar$
if (vx$ = "X") or (v$ = "quality")     then WLOG camera.params("quality", quality)
if (vx$ = "X") or (v$ = "brightness")  then WLOG camera.params("brightness", brightness)
if (vx$ = "X") or (v$ = "contrast")    then WLOG camera.params("contrast", contrast)
if (vx$ = "X") or (v$ = "saturation")  then WLOG camera.params("saturation", saturation)
if (vx$ = "X") or (v$ = "awb")         then WLOG camera.params("awb", awb)
if (vx$ = "X") or (v$ = "awb_gain")    then WLOG camera.params("awb_gain", awb_gain)
if (vx$ = "X") or (v$ = "wb_mode")     then WLOG camera.params("wb_mode", wb_mode)
if (vx$ = "X") or (v$ = "aec")         then WLOG camera.params("aec", aec)
if (vx$ = "X") or (v$ = "aec2")        then WLOG camera.params("aec2", aec2)
if (vx$ = "X") or (v$ = "ae_level")    then WLOG camera.params("ae_level", ae_level)
if (vx$ = "X") or (v$ = "agc")         then WLOG camera.params("agc", agc)
if (vx$ = "X") or (v$ = "agc_gain")    then WLOG camera.params("agc_gain", agc_gain)
if (vx$ = "X") or (v$ = "gainceiling") then WLOG camera.params("gainceiling", gainceiling)
vx$ = ""
return

'######################################################################

SERVO_H_INIT:
'Horizontal servo -------------------------------
S_H  = SERVO_H_POS
if BAS.DEVICE = ESP32CAM SERVO_H_PIN  = 12 'FOR ESP32CAM
if BAS.DEVICE = M5CAM    SERVO_H_PIN  = 13 'FOR M5CAM only
SERVO_H_CHAN = 7
PWM.SETUP SERVO_H_PIN, SERVO_H_CHAN, SERVO_H_POS, 50, 12
GOSUB SERVO_H_SET
pause 1000
return

'######################################################################
SERVO_V_INIT:
'Vertical servo -------------------------------
S_V  = SERVO_V_POS
if BAS.DEVICE = ESP32CAM SERVO_V_PIN  = 3   '= RX-Pin!!!!            '<<<<<<<<<<<<<<<
if BAS.DEVICE = M5CAM    SERVO_V_PIN  = 4   'FOR M5CAM only
SERVO_V_CHAN = 8
PWM.SETUP SERVO_V_PIN, SERVO_V_CHAN, SERVO_V_POS, 50, 12
GOSUB SERVO_V_SET
return

'############################################
SERVO_H_SET:
'#########
if abs(S_H - SERVO_H_POS)> 4 then
  S_H = int( S_H+((SERVO_H_POS - S_H )/10))
  if SERVO_H_FLIP then
    PWM.OUT SERVO_H_CHAN, (600-S_H)        '<<<<<<<<<<horizontal servo inverted
  else
    PWM.OUT SERVO_H_CHAN, (S_H)            '<<<<<<<<<<horizontal servo normal
  endif
endif
return

'############################################
SERVO_V_SET:
'#########
if abs (S_V - SERVO_V_POS) > 4 then
  S_V = int( S_V+((SERVO_V_POS - S_V )/10))
  if SERVO_V_FLIP then
    PWM.OUT SERVO_V_CHAN, (600 - S_V)                '<<<<<<<<<<vertical servo inverted
  else
    PWM.OUT SERVO_V_CHAN, (S_V)                      '<<<<<<<<<<vertical servo normal
  endif
endif
return


'############################################
CAM_INIT:
'#########
WLOG "CAM_INIT: begin"
' variables with CAM parameters
quality     = 10   : brightness  = 0
contrast    = 0    : saturation  = 0
awb         = 1    : awb_gain    = 1
wb_mode     = 0    : aec         = 1
aec2        = 1    : ae_level    = 1
agc         = 0    : agc_gain    = 0
gainceiling = 0

vx$ ="X"           ' "X" = change all parameters
gosub paramchange  ' initialize camera with this parameters

'set CAM-ORIENTATION
'#########
WLOG camera.params("vflip",  PIC_V_FLIP)
WLOG camera.params("hmirror",PIC_H_MIRROR)

'set initial CAM-resolution            '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
'gosub res_800x600
gosub res_1024x768
'gosub res_1280x1024
RES_NEW$ = RES$
if file.exists(FOTO$) = 0 then WLOG  CAMERA.PICTURE(FOTO$) ' save the first picture
WLOG "CAM_INIT finished"
return
Post Reply