YellowToyCar
1.0.0
이 저장소에는 제가 만든 노란색 장난감 자동차 프로젝트와 관련된 코드, 문서 및 기타 내용이 포함되어 있습니다.
또한 장난감 자동차를 제어하기 위한 Flutter 모바일 앱도 만들었습니다. YellowToyCarApp 저장소를 참조하세요.
하드웨어는 다음으로 구성됩니다:
소프트웨어는 다음으로 구성됩니다:
/
또는 /index
또는 /index.html
→ 사용자가 자동차를 제어할 수 있는 웹사이트가 제공됩니다.
/status
→ 시간, 조명 및 모터 상태, 기타 진단 데이터를 포함한 기본 상태.
{
"uptime" : 123456 , // Microseconds passed from device boot.
"time" : "2023-01-12T23:49:03.348+0100" , // Device time, synced using SNTP.
"rssi" : - 67 , // Signal strength of AP the device is connected to, or 0 if not connected.
/* With `?details=1` querystring parameter, extended response is provided. */
"stations" : [ "a1:b2:c3:d4:e5:f6" ] , // list of stations currently connected to our AP
}
/config
→ 구성 설정 요청 엔드포인트(JSON GET/POST API)
{
/* Control & config for motors and lights */
"control" : {
/* Other */
"timeout" : 2000 , // Time in milliseconds counted from last control request/packet, after which movement should stop for safety reason
/* Input values */
"mainLight" : 1 ,
"otherLight" : 1 ,
"left" : 12.3 , // The motors duty cycle are floats as percents,
"right" : 12.3 , // i.e. 12.3 means 12.3% duty cycle.
/* Calibration */
"calibrate" : {
"left" : 0.95 , // Inputs will be multiplied by calibration values before outputting PWM signal.
"right" : 1.05 ,
"frequency" : 100 , // Frequency to be used by PWMs
}
} ,
/* Networking related. Some things are not implemented, including: DNS and DHCP leases */
"network" : {
"mode" : "ap" , // for Access Point or "sta" for station mode, or "nat" (to make it work like router)
"fallback" : 10000 , // duration after should fallback to hosting AP if cannot connect as station
"dns1" : "1.1.1.1" ,
"dns2" : "1.0.0.1" ,
"sta" : {
"ssid" : "YellowToyCar" ,
"psk" : "AAaa11!!" ,
"static" : 0 , // 1 if static IP is to be used in STA mode
"ip" : "192.168.4.1" ,
"mask" : 24 , // as number or IP
"gateway" : "192.168.4.1"
} ,
"ap" : {
"ssid" : "YellowToyCar" ,
"psk" : "AAaa11!!" ,
"channel" : 0 , // channel to use for AP, 0 for automatic
"hidden" : 0 ,
"ip" : "192.168.4.1" ,
"mask" : 24 , // as number or IP
"gateway" : "192.168.4.1" ,
"dhcp" : {
"enabled" : 1 ,
"lease" : [ "192.168.4.1" , "192.168.4.20" ] ,
}
} ,
"sntp" : {
"pool" : "pl.pool.ntp.org" ,
"tz" : "CET-1CEST,M3.5.0,M10.5.0/3" ,
"interval" : 3600000
}
} ,
/* Camera settings. See this project or `esp32_camera` library sources for details. */
"camera" : {
"framesize" : 13 ,
"pixformat" : 4 ,
"quality" : 12 ,
"bpc" : 0 ,
"wpc" : 1 ,
"hmirror" : 0 ,
"vflip" : 0 ,
"contrast" : 0 ,
"brightness" : 0 ,
"sharpness" : 0 ,
"denoise" : 0 ,
"gain_ceiling" : 0 ,
"agc" : 1 ,
"agc_gain" : 0 ,
"aec" : 1 ,
"aec2" : 0 ,
"ae_level" : 0 ,
"aec_value" : 168 ,
"awb" : 1 ,
"awb_gain" : 1 ,
"wb_mode" : 0 ,
"dcw" : 1 ,
"raw_gma" : 1 ,
"lenc" : 1 ,
"special" : 0
}
}
아무것도 변경하지 않은 경우 현재 구성의 JSON을 반환합니다.
192.168.4.1
로 유지되어야 합니다. /capture
→ 자동차 카메라에서 프레임을 캡처합니다.
:81/stream
→ 특별한 콘텐츠 유형인 multipart/x-mixed-replace
활용하는 MJPEG를 사용하여 자동차 카메라에서 연속 프레임 스트림을 보내 필요한 경우 이미지를 교체하도록 클라이언트에 알립니다. 이 하나의 끝없는 요청에서 부분(다음 프레임)을 지속적으로 보내는 가장 쉬운 방법으로 별도의 HTTP 서버가 사용됩니다 (따라서 비표준 포트 81).
애플리케이션은 포트 83에서 UDP 패킷을 기다립니다.
팔중주 | 0 | 1 | 2 | 3 | |
---|---|---|---|---|---|
팔중주 | 비트 | 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15 | 16 17 18 19 20 21 22 23 | 24 25 26 27 28 29 30 31 |
0 | 0 | (UDP) 소스 포트 | (UDP) 대상 포트 | ||
4 | 32 | (UDP) 길이 | (UDP) 체크섬 | ||
8 | 64 | 패킷 유형 (항상 1) | 플래그 (아래 표 참조) | 왼쪽 모터 듀티 | 올바른 모터 듀티 |
조금 | 마스크 | 설명 |
---|---|---|
0 | 0b00000001 | 주 조명(외부 밝은 백색 LED) |
1 | 0b00000010 | 기타 조명(내부 소형 빨간색 LED) |
2 | 0b00000100 | 예약된 |
3 | 0b00001000 | 예약된 |
4 | 0b00010000 | 예약된 |
5 | 0b00100000 | 예약된 |
6 | 0b01000000 | 왼쪽 모터 방향 |
7 | 0b10000000 | 올바른 모터 방향 |
0
)는 앞으로를 의미하고, 비트 설정( 1
)은 뒤로를 의미합니다. 팔중주 | 0 | 1 | 2 | 3 | |
---|---|---|---|---|---|
팔중주 | 비트 | 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15 | 16 17 18 19 20 21 22 23 | 24 25 26 27 28 29 30 31 |
0 | 0 | (UDP) 소스 포트 | (UDP) 대상 포트 | ||
4 | 32 | (UDP) 길이 | (UDP) 체크섬 | ||
8 | 64 | 패킷 유형: 2 | 플래그 (아래 참조) | 목표 모터 값으로 부드럽게 혼합하는 데 걸리는 시간(밀리초) | |
12 | 96 | 왼쪽 모터 듀티, 플로트 백분율(예: 63.8f 63.3% 듀티 사이클과 같음) | |||
16 | 128 | 오른쪽 모터 듀티, 플로트 백분율(예: 63.8f 63.3% 듀티 사이클과 동일) |
일부 스크립트는 개발 및 사용을 쉽게 하기 위해 개발되었습니다.
$ python . s cripts c onfig.py --help
usage: config.py [-h] [--status] [--status-only] [--config-file PATH] [--wifi-mode {ap,sta,apsta,nat,null}] [--ip IP] [--read-only] [--restart [RESTART]]
This script allows to send & retrieve config from the car.
optional arguments:
-h, --help show this help message and exit
--status Request status before sending/requesting config.
--status-only Only request status.
--config-file PATH JSON file to be send as config.
--wifi-mode {ap,sta,apsta,nat,null}
Overwrite WiFi mode from config.
--ip IP, --address IP
IP of the device. Defaults to the one used for AP mode from new config or 192.168.4.1.
--read-only If set, only reads the request (GET request instead POST).
--restart [TIMEOUT] Requests for restart after updating config/retrieving the config.
$ python . s cripts c ontrol.py --help
usage: control.py [-h] [--ip IP] [--port PORT] [--interval INTERVAL] [--dry-run] [--show-packets] [--short-packet-type] [--no-blink] [--max-speed VALUE] [--min-speed VALUE] [--acceleration VALUE]
This script allows to control the car by continuously reading keyboard inputs and sending packets.
optional arguments:
-h, --help show this help message and exit
--ip IP, --address IP
IP of the device. Default: 192.168.4.1
--port PORT Port of UDP control server. Default: 83
--interval INTERVAL Interval between control packets in milliseconds. Default: 100
--dry-run Performs dry-run for testing.
--show-packets Show sent packets (like in dry run).
--short-packet-type Uses short packet type instead long.
--no-blink Prevents default behaviour of constant status led blinking.
Driving model:
--max-speed VALUE Initial maximal speed. From 0.0 for still to 1.0 for full.
--min-speed VALUE Minimal speed to drive motor. Used to avoid motor noises and damage.
--acceleration VALUE Initial acceleration per second.
Note: The 'keyboard' library were used (requires sudo under Linux), and it hooks work also out of focus, which is benefit and issue at the same time, so please care.
Controls:
WASD (or arrows) keys to move; QE to rotate;
F to toggle main light; R to toggle the other light;
Space to stop (immediately, uses both UDP and HTTP);
V to toggle between vectorized (smoothed) and raw mode;
+/- to modify acceleration; [/] to modify max speed;
Shift to temporary uncap speed; ESC to exit.
친숙한 이름 | 이름 | 유연 | 우선 사항 | 소스 파일 | 설명 |
---|---|---|---|---|---|
IPC 작업 | ipcx * | 모두* | 0 | (내부) | IPC 작업은 프로세서 간 호출 기능을 구현하는 데 사용됩니다. |
기본 | main | CPU0 | 1 | main.cpp | 모든 것을 초기화하고 다른 작업을 시작한 다음 백그라운드 논리를 전달합니다. |
카메라 스트림 | httpd | CPU0 | 5 | camera.cpp | |
LwIP | ? | ||||
WiFi | CPU0 | ||||
이벤트 | ? | ||||
유휴 작업 | ipcx * | 모두* | 24 | (내부) | 각 CPU에 대해 생성되고 고정된 유휴 작업입니다. |
* - 일부 작업은 여러 CPU에서 별도의 작업으로 작동합니다.
struct
집계 이니셜라이저와 관련된 10년 전의 알려진 GCC 버그를 포함하고 있습니다. 여기에서 토론을 참조하세요. 해결책으로 나는 인라인/최적화되는 strncpy
사용하는 것이 가장 쉽다는 것을 알았습니다.GENERATE_HTTPD_HANDLER_FOR_EMBEDDED_FILE
매크로)의 시작/끝 레이블에 액세스하는 동안 접두사 _binary_src_
사용하도록 제안하지만 이는 사실이 아닙니다. 적어도 esp-idf
의 경우 일부 영역에서는 문서가 오래되었거나 유효하지 않은 것 같습니다. 그러나 해결책을 찾았습니다. platformio.ini
의 board_build.embed_files
와 CMakeLists.txt
의 EMBED_FILES
모두 사용하십시오. 코드에서는 src_
부분 없이 _binary_
사용하세요.snake_case
와 camelCase
혼합되어 있습니다. 뱀 떼 한가운데서 낙타 한 마리를 타는 것은 더욱 추악하다.ESP_LOGV
및 ESP_LOGD
쉽게 활성화하는 데 문제가 있으므로 해결 방법으로 해당 매크로를 ESP_LOGI
로 재정의했습니다.esp32-camera
라이브러리에는 몇 가지 이상한 문제가 있습니다. 다음은 몇 가지입니다.camera.py
로 테스트합니다.string_view
입니다. 최근 strlen
이 안전하지 않은 문제가 있었습니다...vTaskList
/ uxTaskGetSystemState
Kconfig
파일을 만듭니다. https://esp32tutorials.com/esp32-static-fixed-ip-address-esp-idf/도 참조하세요.esp32-camera
fb_size
수정합니다. 최소 2048이면 작동하는 것 같으며, 좋은 측정을 위해 더 많은 것을 사용하는 것이 좋습니다. (github의 문제).xclk_freq_hz = 10'000'000,
camera_config_t
? 10MHz가 20MHz보다 나을 수 있습니다. espressif/esp32-camera#15를 참조하세요.COM8_AGC_EN
1씩 꺼져 있지 않나요?constexpr
문자열 생성