Skip to content

13. Output devices

Individual Assignment

For this assignment I’m choosing to work with servo motor and DC motor with electronic speed controller. I’m going to use them in my final project.

The roller can rotate inside clockwise. The blade likes a spoon to raise the screws and let the screws fall in the track.

Screw Aligement Roller

It’s a DC motor with electronic speed controller so I can make it work by connecting to the signal pin, voltage and ground with PWM control.

I’m going to use ESP32-CAM for that my previousely group project experience. I make a new shield for this week. Before drawing the new PCB, I try to soldeI build a trial board with solderable perf board first.

I draw the PCB trace with Eagle. There are 2x3 header pins for two servo, 1x4 female pins for I2C, 1x4 header pins for FTDI and 1x3 female pins for input/output device.

Export the png file from Eagle and use http://fabmodules.org/index.html to export NC for milling.

Milling the board with Roland MDX-500 and soldering the pins on the board.

Use Esp32-cam control output device

Demo Webserver control servo

Code Example

#include <ArduinoWebsockets.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include "esp_camera.h"
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"

int index_html_gz_len = 3863;
const uint8_t index_html_gz[] = {
 0x1f ,0x8b ,0x08 ,0x08 ,0x21 ,0x68 ,0x68 ,0x60 ,0x00 ,0xff ,0x69 ,0x6e ,0x64 ,0x65 ,0x78 ,0x2e ,0x68 ,0x74 ,0x6d ,0x6c ,0x2e ,0x67 ,0x7a ,0x00 ,0x95 ,0x58 ,0x7b ,0x6f ,0x1b ,0xb9 ,0x11 ,0xff ,0xdb ,0xfa ,0x14 ,0x3c ,0x19 ,0xcd ,0x4a ,0x8d ,0xb4 ,0x2b ,0x4b ,0xc9 ,0x35 ,0x56 ,0x24 ,0x17 ,0xbd ,0xb3 ,0x81 ,0x04 ,0x48 ,0x70 ,0x41 ,0xed ,0x36 ,0x36 ,0x8a ,0xc2 ,0xa0 ,0x76 ,0x29 ,0x89 ,0x39 ,0x2e ,0xb9 ,0x25 ,0xb9 ,0x7a ,0xf4 ,0xce ,0xdf ,0x3d ,0x33 ,0x5c ,0xee ,0x4b ,0x96 ,0x0d ,0x47 ,0x7f ,0x48 ,0xbb ,0xe4 ,0xfc ,0xe6 ,0xc5 ,0x79 ,0x51 ,0xb3 ,0xb5 ,0x4d ,0xc5 ,0x45 ,0x67 ,0xb6 ,0x66 ,0x34 ,0x81 ,0x9f ,0x94 ,0x59 ,0x4a ,0x24 ,0x4d ,0xd9 ,0x3c ,0xd8 ,0x70 ,0xb6 ,0xcd ,0x94 ,0xb6 ,0x01 ,0x29 ,0x3f ,0xb1 ,0x92 ,0x96 ,0x49 ,0x3b ,0x0f ,0xb6 ,0x3c ,0xb1 ,0xeb ,0x79 ,0xc2 ,0x36 ,0x3c ,0x66 ,0x43 ,0xf7 ,0x32 ,0xa8 ,0x88 ,0xb8 ,0xe4 ,0x96 ,0x53 ,0x31 ,0x34 ,0x31 ,0x15 ,0x6c ,0x7e ,0x16 ,0x8e ,0xea ,0xad ,0xdc ,0x30 ,0xed ,0xd6 ,0xe9 ,0x02 ,0xb6 ,0xa4 ,0x0a ,0x48 ,0x04 ,0x22 ,0x2d ,0xb7 ,0x82 ,0x5d ,0x7c ,0xa1 ,0x92 ,0x50 ,0x99 ,0x90 ,0x1b ,0x2e ,0x2c ,0xb9 ,0xba ,0xfe ,0x32 ,0x19 ,0x0f ,0x7f ,0xfd ,0xc7 ,0xe7 ,0x59 ,0x54 ,0xec ,0x76 ,0x66 ,0xc6 ,0xee ,0xe1 ,0x97 ,0x74 ,0x4e ,0x51 ,0x09 ,0xca ,0x25 ,0xd3 ,0xe4 ,0x8f ,0x8e ,0xe3 ,0xea ,0xe4 ,0x4f ,0xc9 ,0xd9 ,0x68 ,0xf4 ,0x97 ,0xf7 ,0xc5 ,0xca ,0x9a ,0xf1 ,0xd5 ,0xda ,0x4e ,0xc9 ,0x9b ,0xf3 ,0xcd ,0xda ,0x2f ,0x2d ,0x68 ,0xfc ,0xfb ,0x4a ,0xab ,0x5c ,0x26 ,0xc3 ,0x58 ,0x09 ,0xa5 ,0xa7 ,0xe4 ,0x74 ,0x32 ,0x99 ,0xf8 ,0xcd ,0x84 ,0x9b ,0x4c ,0xd0 ,0xfd ,0x94 ,0x2c ,0x05 ,0xdb ,0xf9 ,0x35 ,0x2a ,0xf8 ,0x4a ,0x0e ,0xb9 ,0x65 ,0xa9 ,0x99 ,0x92 ,0x18 ,0xac ,0x66 ,0xda ,0xef ,0x7c ,0xcb ,0x8d ,0xe5 ,0xcb ,0x3d ,0xf0 ,0x71 ,0xde ,0x38 ,0xd8 ,0x55 ,0x1b ,0xa6 ,0x97 ,0x42 ,0x6d ,0xa7 ,0x64 ,0xcd ,0x93 ,0x84 ,0xc9 ,0x52 ,0xbe ,0xd2 ,0x09 ,0x18 ,0xaf ,0x69 ,0xc2 ,0x73 ,0x60 ,0xf8 ,0xb7 ,0xac ,0x94 ,0x63 ,0x55 ,0x1e ,0xaf ,0x87 ,0x34 ,0xb6 ,0x5c ,0xc9 ,0x29 ,0x91 ,0x4a ,0xb2 ,0xf7 ,0x9d ,0x87 ,0xce ,0x29 ,0x0a ,0x7e ,0x6c ,0x60 ,0x85 ,0x2a ,0x2d ,0x6c ,0xae ,0x3d ,0x36 ,0x51 ,0xaf ,0x16 ,0xbd ,0xf1 ,0x9b ,0xb7 ,0x03 ,0x32 ,0x9e ,0xc0 ,0x29 ,0x9c ,0x9f ,0xf7 ,0x5b ,0xca ,0x20 ,0x3a ,0xdb ,0x11 ,0xa3 ,0x04 ,0x4f ,0x90 ,0x94 ,0xf6 ,0xce ,0x26 ,0x3f ,0x0f ,0x48 ,0xfd ,0x15 ,0xbe ,0x6d ,0x03 ,0x2a ,0xed ,0xdf ,0x56 ,0x9e ,0x3e ,0xa6 ,0x7d ,0xe3 ,0xa8 ,0x99 ,0x60 ,0x31 ,0x68 ,0xd9 ,0xb2 ,0x6a ,0x8a ,0xd4 ,0x1b ,0x56 ,0x1a ,0x77 ,0x54 ,0x6b ,0x50 ,0xe5 ,0xe7 ,0x77 ,0xa0 ,0xf6 ,0x19 ,0x7e ,0x8d ,0x41 ,0x77 ,0x08 ,0xa3 ,0x11 ,0x28 ,0x53 ,0xb2 ,0x58 ,0xa3 ,0x97 ,0x4b ,0x0e ,0x71 ,0xae ,0x0d ,0xe2 ,0x32 ,0xc5 ,0x1b ,0xe7 ,0xe0 ,0x55 ,0xf6 ,0xbe ,0x1b ,0x3b ,0x37 ,0x01 ,0x9c ,0x6a ,0x46 ,0x4b ,0x60 ,0xa6 ,0x0c ,0x84 ,0x2a ,0x2a ,0xbe ,0xe4 ,0x3b ,0x96 ,0x78 ,0xa0 ,0x2e ,0x3c ,0x3b ,0xaa ,0x2c ,0xcc ,0xdc ,0xcb ,0x43 ,0xa7 ,0x73 ,0x6a ,0x2c ,0xa0 ,0x53 ,0x77 ,0xf0 ,0x2e ,0x02 ,0x3d ,0x9f ,0x23 ,0xe1 ,0x96 ,0xd1 ,0x24 ,0xe1 ,0x72 ,0x35 ,0x2d ,0xb9 ,0xa4 ,0x54 ,0xaf ,0xb8 ,0x3c ,0x78 ,0x1d ,0x2e ,0x84 ,0x8a ,0x7f ,0x1f ,0x1a ,0x4b ,0xb5 ,0x3d ,0xbe ,0xc5 ,0x64 ,0x72 ,0xb8 ,0xc1 ,0xa5 ,0x00 ,0xd1 ,0xc7 ,0x41 ,0x7e ,0xcf ,0xa1 ,0x08 ,0x5a ,0x7b ,0xa8 ,0x30 ,0xe1 ,0xe9 ,0xca ,0x2b ,0x5d ,0xc6 ,0xbc ,0x13 ,0x54 ,0xb1 ,0xd9 ,0x79 ,0x87 ,0x35 ,0x92 ,0x29 ,0x05 ,0xc6 ,0xde ,0xc2 ,0x66 ,0x3e ,0xb5 ,0x22 ,0xe2 ,0x4d ,0x15 ,0x84 ,0x5e ,0x13 ,0xf4 ,0xda ,0x3b ,0x08 ,0x2e ,0x74 ,0xdb ,0x2c ,0x2a ,0x72 ,0x17 ,0x1e ,0x7c ,0x91 ,0x59 ,0xa8 ,0x64 ,0x0f ,0x3f ,0x5c ,0x66 ,0xb9 ,0x25 ,0x76 ,0x9f ,0x41 ,0xb1 ,0xb1 ,0x6c ,0x07 ,0x16 ,0x31 ,0x1a ,0x10 ,0x9e ,0xcc ,0x83 ,0xe2 ,0x09 ,0x54 ,0xc4 ,0x42 ,0x91 ,0xb8 ,0x2a ,0x91 ,0xf0 ,0x8d ,0xdb ,0x52 ,0x39 ,0x9c ,0xf1 ,0xaf ,0xa5 ,0x41 ,0xc1 ,0x05 ,0x88 ,0xad ,0xf6 ,0x2a ,0x3b ,0xdd ,0x72 ,0x63 ,0x03 ,0x83 ,0x26 ,0xb8 ,0x20 ,0xb3 ,0x08 ,0x16 ,0x1c ,0xa2 ,0x7a ,0xf0 ,0x14 ,0xdd ,0x43 ,0x4f ,0x75 ,0x49 ,0x2c ,0xa8 ,0x31 ,0xf3 ,0x2e ,0x4f ,0xe9 ,0x8a ,0x35 ,0xd6 ,0x1d ,0xe7 ,0x19 ,0xf8 ,0xb1 ,0x01 ,0xeb ,0x12 ,0xa3 ,0xe3 ,0x79 ,0xd7 ,0xed ,0x79 ,0xd6 ,0xe5 ,0x8f ,0x89 ,0x35 ,0xcf ,0xec ,0x45 ,0x07 ,0x18 ,0x18 ,0x4b ,0xb0 ,0xa4 ,0x92 ,0x39 ,0x49 ,0x54 ,0x9c ,0xa7 ,0x50 ,0x34 ,0xc2 ,0x15 ,0xb3 ,0x57 ,0x82 ,0xe1 ,0xe3 ,0x2f ,0xfb ,0x8f ,0x49 ,0x2f ,0x28 ,0xd8 ,0x05 ,0x10 ,0xe9 ,0x05 ,0xfd ,0xd7 ,0xeb ,0xfb ,0x7f ,0xfd ,0xf3 ,0x13 ,0x20 ,0xba ,0x5b ,0x33 ,0x8d ,0xa2 ,0x2e ,0x79 ,0x0d ,0xc5 ,0x40 ,0x26 ,0x6a ,0x1b ,0xc2 ,0xa9 ,0x51 ,0x8c ,0xdd ,0x70 ,0xad ,0x80 ,0xee ,0x35 ,0xe9 ,0x4e ,0xdf ,0x8d ,0xbb ,0x25 ,0x6c ,0x6b ,0x00 ,0x22 ,0x41 ,0xd4 ,0x57 ,0xb6 ,0xb8 ,0x86 ,0xe3 ,0x65 ,0xb6 ,0x57 ,0x70 ,0x02 ,0xc6 ,0x27 ,0x27 ,0x9d ,0xad ,0x09 ,0x95 ,0x4c ,0x99 ,0x31 ,0x60 ,0x19 ,0x10 ,0x56 ,0x4f ,0x17 ,0x90 ,0x18 ,0x27 ,0x7c ,0x49 ,0x7a ,0x7e ,0x25 ,0x4c ,0x28 ,0x34 ,0x03 ,0x0e ,0x1c ,0xa9 ,0x8c ,0x99 ,0x5a ,0x92 ,0x5f ,0x84 ,0x5a ,0xf4 ,0x91 ,0x88 ,0x90 ,0x0d ,0xd5 ,0x24 ,0xd7 ,0xe2 ,0xb7 ,0xc5 ,0x37 ,0xc8 ,0x70 ,0x60 ,0x02 ,0xcc ,0xc3 ,0x18 ,0x94 ,0xb7 ,0xac ,0x58 ,0x82 ,0xf7 ,0x16 ,0x1b ,0x94 ,0x0c ,0x28 ,0xb0 ,0x3f ,0x04 ,0x5f ,0x01 ,0xa0 ,0x02 ,0xc3 ,0xc6 ,0x43 ,0xe7 ,0xe1 ,0x7d ,0xa7 ,0x83 ,0x2c ,0x13 ,0x4d ,0x57 ,0x1f ,0xb1 ,0xf4 ,0x35 ,0x9c ,0xf4 ,0xbf ,0x9c ,0xe9 ,0xfd ,0xb5 ,0x2b ,0x25 ,0x4a ,0xf7 ,0x02 ,0x57 ,0x01 ,0xd0 ,0x45 ,0x48 ,0x5f ,0x47 ,0xf6 ,0x33 ,0x80 ,0x3a ,0x2c ,0x0e ,0x51 ,0x5f ,0x31 ,0xd8 ,0x01 ,0x5a ,0x2d ,0x84 ,0x6a ,0xb9 ,0x34 ,0xcc ,0xba ,0xf5 ,0x03 ,0xda ,0x0f ,0x2e ,0x07 ,0x8e ,0x10 ,0x17 ,0x1b ,0x05 ,0x35 ,0x64 ,0xd0 ,0x25 ,0x98 ,0xf0 ,0x41 ,0x69 ,0xfe ,0x7f ,0x24 ,0x13 ,0x4d ,0xfa ,0x42 ,0x5a ,0x44 ,0xc6 ,0x2d ,0xda ,0x7f ,0x33 ,0x6d ,0x39 ,0xf4 ,0xc4 ,0x26 ,0xa5 ,0x97 ,0xe5 ,0x48 ,0x9f ,0x0c ,0x16 ,0x97 ,0x24 ,0xfd ,0x70 ,0x43 ,0x45 ,0x8e ,0xc7 ,0x58 ,0x34 ,0xe5 ,0x29 ,0x09 ,0x20 ,0x1a ,0x1e ,0xab ,0xf1 ,0x1a ,0xd6 ,0xcb ,0x3a ,0xd5 ,0xa0 ,0x28 ,0x85 ,0x17 ,0x1a ,0xf9 ,0xca ,0x3c ,0x27 ,0x4b ,0x2a ,0x0c ,0x54 ,0x6c ,0x67 ,0x7f ,0xae ,0x35 ,0x88 ,0xbc ,0x6d ,0xbd ,0xdd ,0x15 ,0x6f ,0xbe ,0xd5 ,0xfb ,0x3d ,0xff ,0xe6 ,0xf7 ,0x76 ,0xbf ,0x39 ,0xe7 ,0x00 ,0x33 ,0x28 ,0x52 ,0xb8 ,0xb0 ,0x3f ,0x5c ,0x80 ,0xfc ,0xb2 ,0x37 ,0x90 ,0xf6 ,0x03 ,0xf7 ,0x74 ,0x0d ,0x55 ,0x6b ,0x40 ,0x0c ,0x7c ,0xdf ,0xf0 ,0x94 ,0x41 ,0x96 ,0xbb ,0x60 ,0xf6 ,0x8e ,0x86 ,0x6a ,0x7a ,0xb5 ,0x01 ,0xb9 ,0x9f ,0xb8 ,0x81 ,0x96 ,0xcb ,0xe0 ,0x50 ,0x5d ,0xe3 ,0x71 ,0x45 ,0x30 ,0x18 ,0xb8 ,0xa8 ,0xb9 ,0xc6 ,0xe7 ,0x41 ,0xa1 ,0x79 ,0x91 ,0x3f ,0xcf ,0x63 ,0x41 ,0x90 ,0x47 ,0x5e ,0xa1 ,0xe0 ,0x17 ,0xe3 ,0x52 ,0x68 ,0x3d ,0x1e ,0xf8 ,0x32 ,0x54 ,0xaa ,0xa0 ,0x17 ,0x42 ,0xca ,0xca ,0x1f ,0x57 ,0xd4 ,0x41 ,0xf3 ,0xec ,0x47 ,0xf5 ,0x74 ,0xb0 ,0xa3 ,0x7a ,0x76 ,0x96 ,0xb9 ,0x74 ,0xbd ,0xba ,0xd6 ,0xa4 ,0xc7 ,0x30 ,0xa3 ,0xdd ,0xe0 ,0x06 ,0x99 ,0xcf ,0x42 ,0x2c ,0xc7 ,0x64 ,0x3e ,0x87 ,0x78 ,0x6a ,0xb8 ,0xb8 ,0x24 ,0x69 ,0xcc ,0x77 ,0xb7 ,0x70 ,0x90 ,0x40 ,0xed ,0x5c ,0x69 ,0xfe ,0x33 ,0xfa ,0x6f ,0x18 ,0x0b ,0x8e ,0x71 ,0x42 ,0x86 ,0xe5 ,0xd1 ,0xfb ,0x8e ,0x50 ,0x43 ,0xee ,0x8e ,0x43 ,0xee ,0x00 ,0xe2 ,0x83 ,0xa3 ,0x80 ,0x3c ,0x10 ,0x06 ,0xea ,0x3e ,0x25 ,0xf2 ,0xa5 ,0x72 ,0x9e ,0x62 ,0xde ,0xb4 ,0x15 ,0x9a ,0x15 ,0x46 ,0x24 ,0x58 ,0x5b ,0x16 ,0x9e ,0xa6 ,0xa5 ,0x55 ,0x3a ,0x58 ,0x9d ,0x97 ,0x73 ,0x0d ,0x7c ,0x30 ,0x46 ,0x7b ,0xc1 ,0xf0 ,0xfc ,0xfc ,0x7c ,0x80 ,0x5f ,0x50 ,0x54 ,0x88 ,0xe7 ,0x0c ,0xcd ,0xae ,0xe5 ,0x60 ,0x38 ,0xb1 ,0x86 ,0x7b ,0x6b ,0x23 ,0xea ,0x9c ,0x3a ,0xd0 ,0xba ,0x4e ,0xaf ,0x96 ,0x7c ,0x9f ,0x8e ,0xb5 ,0x70 ,0x94 ,0x5d ,0x8a ,0x3e ,0x14 ,0xda ,0x3e ,0xd0 ,0x82 ,0x47 ,0xd3 ,0x2a ,0x16 ,0x66 ,0x9a ,0x61 ,0xc0 ,0x5c ,0xb2 ,0x25 ,0xcd ,0x85 ,0xed ,0x95 ,0x43 ,0xde ,0x53 ,0x21 ,0xe0 ,0x22 ,0xa9 ,0xc9 ,0xc1 ,0x0f ,0x5d ,0xce ,0x84 ,0xa7 ,0xa3 ,0xa0 ,0x2e ,0x0e ,0x47 ,0x70 ,0xcf ,0x84 ,0x42 ,0x5d ,0x46 ,0x4a ,0xcc ,0xa3 ,0x78 ,0x78 ,0xa4 ,0xc0 ,0x0f ,0x49 ,0x7d ,0x56 ,0x54 ,0xf5 ,0x54 ,0xd7 ,0xaf ,0xf6 ,0x69 ,0xe1 ,0xa7 ,0x2e ,0x65 ,0xed ,0x03 ,0x2b ,0x5d ,0xf8 ,0x99 ,0xda ,0x75 ,0x48 ,0x17 ,0xa6 ,0x57 ,0x6e ,0xf7 ,0xc9 ,0xec ,0x51 ,0xb9 ,0x7f ,0xf5 ,0x8a ,0x1c ,0xd2 ,0xdd ,0x36 ,0xe8 ,0xea ,0xda ,0x7d ,0xe8 ,0x7a ,0x90 ,0x7c ,0xa3 ,0xa9 ,0x34 ,0x02 ,0x9a ,0x6d ,0x85 ,0x1c ,0x54 ,0xaa ,0x14 ,0x39 ,0xef ,0x62 ,0xf9 ,0x98 ,0x5d ,0x2f ,0x6e ,0x27 ,0xb7 ,0x45 ,0xa3 ,0xa8 ,0xfc ,0x8c ,0x1d ,0xe4 ,0xae ,0xb5 ,0xe6 ,0xad ,0x2e ,0x78 ,0xe3 ,0x11 ,0xfd ,0xd1 ,0xa9 ,0x13 ,0x21 ,0x8a ,0x88 ,0xe0 ,0x29 ,0xb7 ,0x2e ,0x62 ,0x61 ,0x14 ,0x86 ,0x41 ,0x9a ,0xc0 ,0x35 ,0xa0 ,0x9a ,0x36 ,0x20 ,0x04 ,0xf5 ,0x9e ,0x4c ,0x46 ,0x24 ,0x35 ,0x48 ,0xbb ,0xb6 ,0x36 ,0xc3 ,0x11 ,0x67 ,0xc5 ,0xed ,0x3a ,0x5f ,0x84 ,0xb1 ,0x4a ,0x23 ,0xc9 ,0x94 ,0xe4 ,0x50 ,0xca ,0x22 ,0xb8 ,0x4d ,0x7d ,0x33 ,0xf7 ,0xcc ,0x64 ,0x93 ,0xf1 ,0x3d ,0xdb ,0xd1 ,0x34 ,0x13 ,0xcc ,0x44 ,0x30 ,0xb7 ,0x2e ,0xa2 ,0x14 ,0x1a ,0x07 ,0xd3 ,0x15 ,0xe5 ,0x3d ,0x08 ,0x88 ,0x62 ,0x26 ,0x44 ,0xb6 ,0x86 ,0xa7 ,0x7b ,0xac ,0x91 ,0x5a ,0x09 ,0x98 ,0x20 ,0xef ,0x75 ,0x7c ,0x1f ,0x53 ,0x1d ,0x6d ,0xb7 ,0xdb ,0x08 ,0xe6 ,0x27 ,0xb6 ,0x0b ,0xf1 ,0xd6 ,0x5b ,0xe7 ,0x8d ,0xcb ,0x2a ,0xbb ,0xb3 ,0xa5 ,0xab ,0xb1 ,0x3d ,0x49 ,0x85 ,0xa3 ,0x1a ,0x4e ,0x51 ,0x97 ,0xe8 ,0xe8 ,0x3e ,0x3a ,0x0c ,0x5b ,0x53 ,0x99 ,0x2f ,0x7c ,0xd9 ,0x2b ,0xfb ,0x96 ,0x4b ,0x16 ,0xb8 ,0xc1 ,0xb0 ,0x25 ,0x54 ,0xe4 ,0x84 ,0xfc ,0xf9 ,0xa7 ,0x03 ,0x0f ,0xab ,0xbe ,0x46 ,0x2e ,0xe6 ,0x60 ,0x69 ,0xf3 ,0x1c ,0x2d ,0xd8 ,0xde ,0x3e ,0x55 ,0x18 ,0xca ,0x2a ,0x2d ,0xda ,0xc1 ,0x5b ,0x4b ,0x79 ,0x46 ,0x9b ,0xf2 ,0xa3 ,0x99 ,0xcd ,0x75 ,0x79 ,0xe9 ,0x74 ,0xb9 ,0x03 ,0x73 ,0x62 ,0xbc ,0xae ,0x8b ,0x42 ,0xe3 ,0x2e ,0x0f ,0x37 ,0x3f ,0x06 ,0x83 ,0x24 ,0x56 ,0x8c ,0xc3 ,0x48 ,0x29 ,0xbe ,0xcb ,0x0e ,0x8d ,0x25 ,0x70 ,0xe7 ,0xeb ,0x27 ,0x98 ,0xfd ,0x53 ,0xa3 ,0x4b ,0x37 ,0xd9 ,0xba ,0xa1 ,0x06 ,0x47 ,0xcf ,0x4a ,0xe3 ,0x9f ,0x5a ,0x7e ,0xf9 ,0x3b ,0x1e ,0xf7 ,0x90 ,0xf4 ,0xda ,0xce ,0xe9 ,0x93 ,0x29 ,0xac ,0x37 ,0x13 ,0xa8 ,0x07 ,0x4c ,0x66 ,0x64 ,0xd4 ,0x6f ,0xe9 ,0xeb ,0x18 ,0x37 ,0xc8 ,0x1a ,0x3a ,0xc0 ,0x06 ,0xe6 ,0x44 ,0xf1 ,0xd2 ,0xeb ,0xf5 ,0x8b ,0x49 ,0xb6 ,0x9d ,0x32 ,0x4d ,0x62 ,0x99 ,0x0b ,0x18 ,0x78 ,0x0e ,0xf7 ,0xdd ,0x69 ,0xa2 ,0xb5 ,0x4d ,0x67 ,0x0c ,0x40 ,0xae ,0x7f ,0x6f ,0x97 ,0xf7 ,0x56 ,0x12 ,0xee ,0xbe ,0x28 ,0x33 ,0x20 ,0x7b ,0xf7 ,0xcd ,0xaa ,0x7c ,0x65 ,0x22 ,0x74 ,0x17 ,0x9f ,0xd0 ,0x22 ,0xe1 ,0x52 ,0x69 ,0x9c ,0x6a ,0x03 ,0xf7 ,0x82 ,0xa8 ,0x09 ,0xe4 ,0x1c ,0xe4 ,0x12 ,0x62 ,0x31 ,0xb7 ,0xb2 ,0xdd ,0xc0 ,0xe5 ,0x16 ,0x72 ,0x29 ,0xdf ,0x47 ,0xfd ,0xa0 ,0x90 ,0x8d ,0x9e ,0xcd ,0xa8 ,0xbc ,0x64 ,0x2b ,0xcd ,0x18 ,0x3a ,0xc2 ,0xa1 ,0xfe ,0x4a ,0xce ,0x47 ,0x30 ,0x23 ,0x3e ,0x2a ,0x18 ,0x35 ,0xc6 ,0xc2 ,0x9f ,0x29 ,0x35 ,0xc8 ,0xb1 ,0x6e ,0x83 ,0xea ,0xf9 ,0xef ,0xc4 ,0xf9 ,0xa0 ,0x21 ,0x04 ,0x74 ,0x18 ,0xa0 ,0x42 ,0x0d ,0x1e ,0xee ,0x06 ,0x0e ,0xd7 ,0x39 ,0x7f ,0xa7 ,0x99 ,0x45 ,0xfe ,0x22 ,0x17 ,0xb9 ,0xff ,0x90 ,0xbe ,0x03 ,0x97 ,0x76 ,0xc7 ,0xd7 ,0x4a ,0x12 ,0x00 ,0x00
 };

const char* ssid = "fablab";
const char* password = "27796851";

#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27
#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

camera_fb_t * fb = NULL;

using namespace websockets;
WebsocketsServer WSserver;
AsyncWebServer webserver(80);

// Arduino like analogWrite
// value has to be between 0 and valueMax
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 180) {
  // calculate duty, 8191 from 2 ^ 13 - 1
  uint32_t duty = (8191 / valueMax) * min(value, valueMax);
  ledcWrite(channel, duty);
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  Serial.begin(115200);
  // Ai-Thinker: pins 13 and 12
  ledcSetup(12, 50, 16); //channel, freq, resolution
  ledcAttachPin(12, 12); // pin, channel
  ledcSetup(13, 50, 16);
  ledcAttachPin(13, 13);
  pinMode(4, OUTPUT);
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  //init with high specs to pre-allocate larger buffers
  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();
  s->set_framesize(s, FRAMESIZE_QVGA);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, sizeof(index_html_gz));
    response->addHeader("Content-Encoding", "gzip");
    request->send(response);
  });

  webserver.begin();
  WSserver.listen(82);
}


void handle_message(WebsocketsMessage msg) {
  int commaIndex = msg.data().indexOf(',');
  int panValue = msg.data().substring(0, commaIndex).toInt();
  int tiltValue = msg.data().substring(commaIndex + 1).toInt();

  if (panValue > 900 || panValue < -900)
  {
    panValue > 900 ? digitalWrite(12, LOW) : digitalWrite(12, HIGH);
  }

  else
  {
    panValue = map(panValue, -90, 90, 180, 0); // 0-180
    tiltValue = map(tiltValue, -90, 90, 180, 0); // 0-180 

    ledcAnalogWrite(12, panValue); // channel, value
    ledcAnalogWrite(13, tiltValue);
  }


}

void loop() {
  auto client = WSserver.accept();
  client.onMessage(handle_message);
  while (client.available()) {
    client.poll();
    fb = esp_camera_fb_get();
    client.sendBinary((const char *)fb->buf, fb->len);
    esp_camera_fb_return(fb);
    fb = NULL;
  }
}

Demo Use Esp32-cam control I2C oLED.

Hint: The ESP32 has 2 x I2C Interfaces and any pin can be set as SDA or SCL. While using the ESP32 Arduino Core, the default I2C pins are: GPIO 21 (SDA) GPIO 22 (SCL) Use wire.begin(SDA_pin, SCL_pin); //(15,14) at esp32-cam

Code Example

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

void setup() {
  Wire.begin(15, 14); //Wire.begin(SDA_pin, SCL_pin) change I2C pins
  Serial.begin(115200);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // Clear display buffer

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, 0, i, display.height()-1, WHITE);
    display.display(); // Update screen with each newly-drawn line
    delay(1);
  }
  for(i=0; i<display.height(); i+=4) {
    display.drawLine(0, 0, display.width()-1, i, WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-1, 0, 0, i, WHITE);
    display.display();
    delay(1);
  }
  for(i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-1, 0, i, display.height()-1, WHITE);
    display.display();
    delay(1);
  }

  delay(2000); // Pause for 2 seconds
}

void testdrawrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, WHITE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testfillrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=3) {
    // The INVERSE color is used so rectangles alternate white/black
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, INVERSE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, INVERSE);
    display.display(); // Update screen with each newly-drawn circle
    delay(1);
  }

  delay(2000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    // The INVERSE color is used so round-rects alternate white/black
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
    // The INVERSE color is used so triangles alternate white/black
    display.fillTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // Not all the characters will fit on the display. This is normal.
  // Library will draw what it can and the rest will be clipped.
  for(int16_t i=0; i<256; i++) {
    if(i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(2000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(BLACK, WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

Supplementary Servo Test with ESP32 Output Board (new board)

Referred by Week11 - ESP32 Input Board, I use the GPIO 4 as servo control pin.

Connecting the Servo Motor to the ESP32

Servo motors have three wires: power, ground, and signal. The power is usually red, the GND is black or brown, and the signal wire is usually yellow, orange, or white.

I find a problem using FTDI to drive the 9G servo.

It is not enough current to drive the servo. Therefore, I use electronic speed controller’s BEC as power source 6V/3A.

Installing the ESP32_Arduino_Servo_Library

The ESP32 Arduino Servo Library makes it easier to control a servo motor with your ESP32, using the Arduino IDE. Follow the next steps to install the library in your Arduino IDE:

  • Click here to download the ESP32_Arduino_Servo_Library . You should have a .zip folder in your Downloads folder
  • Unzip the .zip folder and you should get ESP32-Arduino-Servo-Library-Master folder
  • Rename your folder from ESP32-Arduino-Servo-Library-Master to ESP32_Arduino_Servo_Library
  • Move the ESP32_Arduino_Servo_Library folder to your Arduino IDE installation libraries folder
  • Finally, re-open your Arduino IDE
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position

void setup() {
  myservo.attach(4);  // attaches the servo on pin 4 to the servo object
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
}

Group assignment

Measure the power consumption of an output device

Group Assignment

Motor power consumption measurement demo

For this week’s group assignment, I’ve used the power supply build in voltage, current and power meter to measure the power consumption of the motor. Before ON, power supply panel shows 7.2V, 0A, 0W. After ON, it show 7.2V, 0.3A, 2.16W.

The current consumption of the screen is 0.24A. To know the power, we use the following formula P = V x I.

On this particular measurement, I powered the supply with a DC 7.2V , and we take the consumption of 0.3A. The power consumption show P = 7.2 x 0.3 = 2.16 W.

Normally it show the no load situation of DC motor.

I collect a DC motor with slide crank, brushed electronic speed controller (ESC) and servo test following the ESC user manual.

Brushed electronic speed controller connections following the user manual. First test, we set the Servo tester with PWM 60%. The panel show 7.2V, 0.15A, 1.08W. Second test, we set the Servo tester with PWM 100%. The panel show 7.2V, 0.25A, 1.80W. The power consumption is increasing proportional according to the PWM percentage.

Final test, we add a can at the end of the slide crank. The motor is blocked by the can. It is full load situation for calculate the power consumption. The panel show 7.2V, 0.92A, 6.62W. It is about 3.5 time no load power consumption.


Last update: July 3, 2021