{"id":20100687,"url":"https://github.com/againpsychox/yellowtoycar","last_synced_at":"2025-06-26T08:33:01.610Z","repository":{"id":153029522,"uuid":"591484121","full_name":"AgainPsychoX/YellowToyCar","owner":"AgainPsychoX","description":"WiFi-enabled toy car with ESP32-Cam (AI-Thinker with OV2640) and 2 pairs of motors controlled by L298N-based module. Software includes HTTP server with network \u0026 camera configuration.","archived":false,"fork":false,"pushed_at":"2024-12-20T15:15:43.000Z","size":249,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-06T06:47:17.087Z","etag":null,"topics":["car","esp-idf","esp32","esp32-cam","esp32-camera","l298n","ov2640","rc-car","udp","wifi"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AgainPsychoX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-01-20T21:46:05.000Z","updated_at":"2025-03-26T08:54:14.000Z","dependencies_parsed_at":"2024-12-20T16:27:08.494Z","dependency_job_id":"b8d3c440-6b88-47ff-bf60-6dcbdb918e52","html_url":"https://github.com/AgainPsychoX/YellowToyCar","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AgainPsychoX/YellowToyCar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AgainPsychoX%2FYellowToyCar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AgainPsychoX%2FYellowToyCar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AgainPsychoX%2FYellowToyCar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AgainPsychoX%2FYellowToyCar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AgainPsychoX","download_url":"https://codeload.github.com/AgainPsychoX/YellowToyCar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AgainPsychoX%2FYellowToyCar/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262030279,"owners_count":23247627,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["car","esp-idf","esp32","esp32-cam","esp32-camera","l298n","ov2640","rc-car","udp","wifi"],"created_at":"2024-11-13T17:16:50.317Z","updated_at":"2025-06-26T08:33:01.603Z","avatar_url":"https://github.com/AgainPsychoX.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Yellow Toy Car\n\nThis repository contains code, documentation and other stuff related to yellow toy car project I made.\n\nI also made Flutter mobile app for controlling the toy car, see [YellowToyCarApp](https://github.com/AgainPsychoX/YellowToyCarApp) repository.\n\n\u003ctable\u003e\n\t\u003ctbody\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd colspan=2\u003e\u003cimg src=\"https://i.imgur.com/3KbkHvP.jpg\" width=\"720\" /\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003cimg src=\"https://i.imgur.com/duyLOIX.jpg\" width=\"400\" /\u003e\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\n\n## Hardware\n\nHardware consist of:\n\n* Microcontroller: [ESP32-Cam AI-Thinker development board](https://microcontrollerslab.com/esp32-cam-ai-thinker-pinout-gpio-pins-features-how-to-program/)\n\t* ESP32S chip\n\t\t* 2x 32-bit LX6 CPU; up to 240 MHz; 520 KB SRAM.\n\t\t* 802.11 b/g/n Wi-Fi and Bluetooth 4.2 BR/EDR with BLE\n\t* PSRAM on board, adding 4 MB.\n\t* [OV2640 camera](https://www.uctronics.com/download/cam_module/OV2640DS.pdf).\n\t* MicroSD card slot (unused, as GPIOs are used for motors and flash LED).\n\t* 2 LEDs: red internal pulled high, and bright white external, acting for camera flash.\n* Motors driver: [L298N-based module](https://abc-rc.pl/product-pol-6196-Modul-sterownika-L298N-do-silnikow-DC-i-krokowych-Arduino.html?query_id=1), able to drive 2 DC motors.\n* 4 brushed motors, controlled in pairs, attached by gears to wheels.\n* External antenna for ESP32 Wi-Fi connectivity is used.\n* Battery (3 cells of 4 V, total 12 V for main board, 8 V for motors used).\n* Additional circuitry:\n\t* Voltage converter (down to 5V, red LED)\n\t* Voltage stabilizer (down to 3.3V required for ESP32, green LED).\n\t* Battery, motor drivers and programmer connectors.\n\t* Switch for programming mode (ON to program, OFF to execute). \n* Plastic grid and packaging.\n\n\u003c!-- TODO: Pictures here, in table --\u003e\n\n\n\n\n\n## Software\n\nSoftware consist of:\n\n+ Espressif IoT Development Framework (ESP-IDF) is used, which includes modified FreeRTOS.\n+ Networking related code (\u003cabbr title=\"access point\"\u003eAP\u003c/abbr\u003e or \u003cabbr title=\"station\"\u003eSTA\u003c/abbr\u003e)\n+ Camera related code\n+ JSON configuration interface functions\n+ Main HTTP web server (port 80)\n\t+ Status JSON\n\t+ Configuration endpoint\n\t+ Basic (slow) controls\n\t+ Car camera frame capture\n+ Stream HTTP web server (port 81)\n\t+ Camera stream only, since it's blocking multipart data stream.\n\t+ Separate server to allow concurrent requests for main server.\n+ Simple HAL for the motors and the lights\n+ UDP socket server for fast controls inputs (port 83)\n\t+ Used by external scripts, allowing to control from the computer.\n\t+ Used by dedicated mobile app (related project)\n\n\n\n### Web API (HTTP)\n\n* `/` or `/index` or `/index.html` → Website presented for user to control the car.\n\n\t\u003c!-- TODO: Website screens here --\u003e\n\n* `/status` → Basic status, including time, lights \u0026 motors state and other diagnostic data.\n\n\t```json5\n\t{\n\t\t\"uptime\": 123456, // Microseconds passed from device boot.\n\t\t\"time\": \"2023-01-12T23:49:03.348+0100\", // Device time, synced using SNTP.\n\t\t\"rssi\": -67, // Signal strength of AP the device is connected to, or 0 if not connected.\n\n\t\t/* With `?details=1` querystring parameter, extended response is provided. */\n\t\t\"stations\": [\"a1:b2:c3:d4:e5:f6\"], // list of stations currently connected to our AP\n\t}\n\t```\n\n* `/config` → Endpoint for requests to set configuration (JSON GET/POST API)\n\n\t```json5\n\t{\n\t\t/* Control \u0026 config for motors and lights */\n\t\t\"control\": {\n\t\t\t/* Other */\n\t\t\t\"timeout\": 2000, // Time in milliseconds counted from last control request/packet, after which movement should stop for safety reason\n\t\t\t/* Input values */\n\t\t\t\"mainLight\": 1,\n\t\t\t\"otherLight\": 1,\n\t\t\t\"left\": 12.3,  // The motors duty cycle are floats as percents,\n\t\t\t\"right\": 12.3, // i.e. 12.3 means 12.3% duty cycle.\n\t\t\t/* Calibration */\n\t\t\t\"calibrate\": {\n\t\t\t\t\"left\": 0.95, // Inputs will be multiplied by calibration values before outputting PWM signal.\n\t\t\t\t\"right\": 1.05,\n\t\t\t\t\"frequency\": 100, // Frequency to be used by PWMs\n\t\t\t}\n\t\t},\n\t\t/* Networking related. Some things are not implemented, including: DNS and DHCP leases */\n\t\t\"network\": {\n\t\t\t\"mode\": \"ap\", // for Access Point or \"sta\" for station mode, or \"nat\" (to make it work like router)\n\t\t\t\"fallback\": 10000, // duration after should fallback to hosting AP if cannot connect as station\n\t\t\t\"dns1\": \"1.1.1.1\",\n\t\t\t\"dns2\": \"1.0.0.1\",\n\t\t\t\"sta\": {\n\t\t\t\t\"ssid\": \"YellowToyCar\",\n\t\t\t\t\"psk\": \"AAaa11!!\",\n\t\t\t\t\"static\": 0, // 1 if static IP is to be used in STA mode\n\t\t\t\t\"ip\": \"192.168.4.1\",\n\t\t\t\t\"mask\": 24, // as number or IP\n\t\t\t\t\"gateway\": \"192.168.4.1\"\n\t\t\t},\n\t\t\t\"ap\": {\n\t\t\t\t\"ssid\": \"YellowToyCar\",\n\t\t\t\t\"psk\": \"AAaa11!!\",\n\t\t\t\t\"channel\": 0, // channel to use for AP, 0 for automatic\n\t\t\t\t\"hidden\": 0,\n\t\t\t\t\"ip\": \"192.168.4.1\",\n\t\t\t\t\"mask\": 24, // as number or IP\n\t\t\t\t\"gateway\": \"192.168.4.1\",\n\t\t\t\t\"dhcp\": {\n\t\t\t\t\t\"enabled\": 1,\n\t\t\t\t\t\"lease\": [\"192.168.4.1\", \"192.168.4.20\"],\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"sntp\": {\n\t\t\t\t\"pool\": \"pl.pool.ntp.org\",\n\t\t\t\t\"tz\": \"CET-1CEST,M3.5.0,M10.5.0/3\",\n\t\t\t\t\"interval\": 3600000\n\t\t\t}\n\t\t},\n\t\t/* Camera settings. See this project or `esp32_camera` library sources for details. */\n\t\t\"camera\": {\n\t\t\t\"framesize\": 13,\n\t\t\t\"pixformat\": 4,\n\t\t\t\"quality\": 12,\n\t\t\t\"bpc\": 0,\n\t\t\t\"wpc\": 1,\n\t\t\t\"hmirror\": 0,\n\t\t\t\"vflip\": 0,\n\t\t\t\"contrast\": 0,\n\t\t\t\"brightness\": 0,\n\t\t\t\"sharpness\": 0,\n\t\t\t\"denoise\": 0,\n\t\t\t\"gain_ceiling\": 0,\n\t\t\t\"agc\": 1,\n\t\t\t\"agc_gain\": 0,\n\t\t\t\"aec\": 1,\n\t\t\t\"aec2\": 0,\n\t\t\t\"ae_level\": 0,\n\t\t\t\"aec_value\": 168,\n\t\t\t\"awb\": 1,\n\t\t\t\"awb_gain\": 1,\n\t\t\t\"wb_mode\": 0,\n\t\t\t\"dcw\": 1,\n\t\t\t\"raw_gma\": 1,\n\t\t\t\"lenc\": 1,\n\t\t\t\"special\": 0\n\t\t}\n\t}\n\t```\n\tReturns JSON of current configuration, if not changing anything. \n\n\t* For AP mode, default IP/gateway should stay `192.168.4.1` for now, as DHCP settings are hardcoded to some default values.\n\t* DNS, SNTP and NAT settings are also not implemented yet.\n\t* When changing network settings, device might get disconnected, so no response will be sent.\n\n* `/capture` → Frame capture from the car camera.\n\n* `:81/stream` → Continuous frames stream from the car camera using \u003cabbr title=\"Motion JPEG\"\u003eMJPEG\u003c/abbr\u003e that exploits special content type: `multipart/x-mixed-replace` that informs the client to replace the image if necessary. **Separate HTTP server is used** (hence the non-standard port 81), as it easiest way to continously send parts (next frames) in this single one endless request.\n\n\n\n### Fast controls API (UDP)\n\nApplication waits for UDP packets on port 83.\n\n#### Short control packet\n\n\u003ctable\u003e\n\t\u003ctbody\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003cth\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003csub\u003eOctet\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e0\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e1\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e2\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e3\u003c/sub\u003e\u003c/th\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003cth\u003e\u003csub\u003eOctet\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003csub\u003eBits\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e0 \u0026nbsp; 1 \u0026nbsp; 2 \u0026nbsp; 3 \u0026nbsp; 4 \u0026nbsp; 5 \u0026nbsp; 6 \u0026nbsp; 7\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e8 \u0026nbsp; 9 \u0026nbsp; 10 \u0026nbsp; 11 \u0026nbsp; 12 \u0026nbsp; 13 \u0026nbsp; 14 \u0026nbsp; 15\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e16 \u0026nbsp; 17 \u0026nbsp; 18 \u0026nbsp; 19 \u0026nbsp; 20 \u0026nbsp; 21 \u0026nbsp; 22 \u0026nbsp; 23\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e24 \u0026nbsp; 25 \u0026nbsp; 26 \u0026nbsp; 27 \u0026nbsp; 28 \u0026nbsp; 29 \u0026nbsp; 30 \u0026nbsp; 31\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e0\u003c/td\u003e\n\t\t\t\u003ctd\u003e0\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Source port\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Destination port\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e4\u003c/td\u003e\n\t\t\t\u003ctd\u003e32\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Length\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Checksum\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e8\u003c/td\u003e\n\t\t\t\u003ctd\u003e64\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"1\"\u003ePacket type \u003csup\u003e(always 1)\u003c/sup\u003e\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"1\"\u003eFlags \u003csup\u003e(see table below)\u003c/sup\u003e\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"1\"\u003eLeft motor duty\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"1\"\u003eRight motor duty\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n#### Flags\n\n| Bit | Mask         | Description                                             |\n|:---:|:-------------|:--------------------------------------------------------|\n| 0   | `0b00000001` | Main light (external bright white LED)                  |\n| 1   | `0b00000010` | Other light (internal small red LED)                    |\n| 2   | `0b00000100` | Reserved                                                |\n| 3   | `0b00001000` | Reserved                                                |\n| 4   | `0b00010000` | Reserved                                                |\n| 5   | `0b00100000` | Reserved                                                |\n| 6   | `0b01000000` | Left motor direction                                    |\n| 7   | `0b10000000` | Right motor direction                                   |\n\n* For motor direction in the flags, cleared bit (`0`) means forward, set bit (`1`) means backward.\n\n#### Long control packet\n\n\u003ctable\u003e\n\t\u003ctbody\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003cth\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003csub\u003eOctet\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e0\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e1\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e2\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth style=\"text-align:center\"\u003e\u003csub\u003e3\u003c/sub\u003e\u003c/th\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003cth\u003e\u003csub\u003eOctet\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003csub\u003eBits\u003c/sub\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e0 \u0026nbsp; 1 \u0026nbsp; 2 \u0026nbsp; 3 \u0026nbsp; 4 \u0026nbsp; 5 \u0026nbsp; 6 \u0026nbsp; 7\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e8 \u0026nbsp; 9 \u0026nbsp; 10 \u0026nbsp; 11 \u0026nbsp; 12 \u0026nbsp; 13 \u0026nbsp; 14 \u0026nbsp; 15\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e16 \u0026nbsp; 17 \u0026nbsp; 18 \u0026nbsp; 19 \u0026nbsp; 20 \u0026nbsp; 21 \u0026nbsp; 22 \u0026nbsp; 23\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\t\u003cth\u003e\u003ci\u003e\u003csub\u003e24 \u0026nbsp; 25 \u0026nbsp; 26 \u0026nbsp; 27 \u0026nbsp; 28 \u0026nbsp; 29 \u0026nbsp; 30 \u0026nbsp; 31\u003c/sub\u003e\u003c/i\u003e\u003c/th\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e0\u003c/td\u003e\n\t\t\t\u003ctd\u003e0\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Source port\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Destination port\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e4\u003c/td\u003e\n\t\t\t\u003ctd\u003e32\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Length\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003e(UDP) Checksum\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e8\u003c/td\u003e\n\t\t\t\u003ctd\u003e64\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"1\"\u003ePacket type: 2\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"1\"\u003eFlags \u003csup\u003e(see below)\u003c/sup\u003e\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"2\"\u003eTime (in milliseconds) to smooth blend towards target motor values\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e12\u003c/td\u003e\n\t\t\t\u003ctd\u003e96\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"4\"\u003eLeft motor duty, percent as float (i.e. \u003ccode\u003e63.8f\u003c/code\u003e equals to 63.3% duty cycle)\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e16\u003c/td\u003e\n\t\t\t\u003ctd\u003e128\u003c/td\u003e\n\t\t\t\u003ctd colspan=\"4\"\u003eRight motor duty, percent as float (i.e. \u003ccode\u003e63.8f\u003c/code\u003e equals to 63.3% duty cycle)\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n* The flags in long control packet are the same as in the short, but motor directions flags are not respected. \n* Use negative float numbers for moving backwards.\n\n\n\n### Scripts\n\nSome scripts were developed to ease development and usage.\n\n#### Config\n\n```console\n$ python .\\scripts\\config.py --help\nusage: config.py [-h] [--status] [--status-only] [--config-file PATH] [--wifi-mode {ap,sta,apsta,nat,null}] [--ip IP] [--read-only] [--restart [RESTART]]\n\nThis script allows to send \u0026 retrieve config from the car.\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --status              Request status before sending/requesting config.\n  --status-only         Only request status.\n  --config-file PATH    JSON file to be send as config.\n  --wifi-mode {ap,sta,apsta,nat,null}\n                        Overwrite WiFi mode from config.\n  --ip IP, --address IP\n                        IP of the device. Defaults to the one used for AP mode from new config or 192.168.4.1.\n  --read-only           If set, only reads the request (GET request instead POST).\n  --restart [TIMEOUT]   Requests for restart after updating config/retrieving the config.\n```\n\n#### Control\n\n```console\n$ python .\\scripts\\control.py --help       \nusage: 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]\n\nThis script allows to control the car by continuously reading keyboard inputs and sending packets.\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --ip IP, --address IP\n                        IP of the device. Default: 192.168.4.1\n  --port PORT           Port of UDP control server. Default: 83\n  --interval INTERVAL   Interval between control packets in milliseconds. Default: 100\n  --dry-run             Performs dry-run for testing.\n  --show-packets        Show sent packets (like in dry run).\n  --short-packet-type   Uses short packet type instead long.\n  --no-blink            Prevents default behaviour of constant status led blinking.\n\nDriving model:\n  --max-speed VALUE     Initial maximal speed. From 0.0 for still to 1.0 for full.\n  --min-speed VALUE     Minimal speed to drive motor. Used to avoid motor noises and damage.\n  --acceleration VALUE  Initial acceleration per second.\n\nNote: 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.\n```\n\n##### Controls for the control script\n\n```\nControls:\n\tWASD (or arrows) keys to move; QE to rotate;\n\tF to toggle main light; R to toggle the other light;   \n\tSpace to stop (immediately, uses both UDP and HTTP);   \n\tV to toggle between vectorized (smoothed) and raw mode;\n\t+/- to modify acceleration; [/] to modify max speed;\n\tShift to temporary uncap speed; ESC to exit.\n```\n\n\n\n### Tasks\n\n| Friendly name | Name     | Affinity | Priority | Source file | Description   |\n|:--------------|:---------|:--------:|:--------:|:------------|:--------------|\n| IPC tasks     | `ipcx`\\* | All\\*    | 0        | (internal)  | IPC tasks are used to implement the Inter-Processor Call feature.          |\n| Main          | `main`   | CPU0     | 1        | `main.cpp`  | Initializes everything, starts other tasks, then carries background logic. |\n| Camera stream | `httpd`  | CPU0     | 5        | `camera.cpp`\n| LwIP          |          | ?\n| WiFi          |          | CPU0\n| Events        |          | ?\n| Idle tasks    | `ipcx`\\* | All\\*    | 24       | (internal)  | Idle tasks created for (and pinned to) each CPU.\n\n\u003csmall\u003e\\* - Some tasks work on multiple CPUs, as separate tasks.\u003c/small\u003e\n\n\n\n\n\n## Notes\n\n\n### Known issues\n\n* The communication (to ESP32) seems to work best in AP mode with UDP packets.\n* C/C++ compiler used is quite old and includes decade old known GCC bug related to `struct`s aggregate initializers. See [discussion here](https://stackoverflow.com/questions/70172941/c99-designator-member-outside-of-aggregate-initializer). As solution I found out its easiest to use `strncpy` which gets inlined/optimized away.\n* [The PlatformIO docs about embedding files](https://docs.platformio.org/en/latest/platforms/espressif32.html#embedding-binary-data) suggest to use prefix `_binary_src_` while accessing the start/end labels of embedded data blocks (like in  `GENERATE_HTTPD_HANDLER_FOR_EMBEDDED_FILE` macro), its not true. The docs seems outdated or invalid in some areas, at least for `esp-idf`. However I found **solution**: Use both `board_build.embed_files` in `platformio.ini` and also `EMBED_FILES` in `CMakeLists.txt`. In code, use `_binary_`, without `src_` part.\n* Code style is a bit mess, `snake_case` mixed with `camelCase` because we use C libraries from ESP-IDF and some parts use them a lot. It's even uglier to ride a single camel in the middle of snakes.\n* There is [an issue with easy enabling `ESP_LOGV` and `ESP_LOGD` for single file](https://github.com/espressif/esp-idf/issues/8570), so I redefine those macros to `ESP_LOGI` as a workaround.\n* The `esp32-camera` library the project uses has some weird issues, here are some:\n\t* When capturing small JPEGs, it maybe required to modify some library code and/or use specific JPEG quality values. What's more confusing, there are cases where using better quality (which requires more memory) results in more reliability. [(issue on GitHub)](https://github.com/espressif/esp32-camera/issues/436#issuecomment-1962142072)\n* ...\n\n\n\n### Interesting materials\n\n* [Some information about ESP32-CAM AI Thinker board used in this project](https://github.com/raphaelbs/esp32-cam-ai-thinker/)\n* [ESP-IDF 5.3.1 for ESP32 - Programming Guide](https://docs.espressif.com/projects/esp-idf/en/v5.3.1/esp32/index.html) - including API references, examples, guides and other resources.\n* [YouTube series about RTOS](https://www.youtube.com/watch?v=F321087yYy4\u0026list=PLEBQazB0HUyQ4hAPU1cJED6t3DU0h34bz) by Digi-Key. Great introduction to ESP32-flavoured RTOS, with exercises for viewer.\n* [Program to record an MJPEG AVI video on the SD Card of an ESP32-CAM](https://github.com/jameszah/ESP32-CAM-Video-Recorder), along with many useful notes about ESP32-CAM and low cost recording to [AVI](https://learn.microsoft.com/en-us/windows/win32/directshow/avi-riff-file-reference) itself.\n\n\n\n### To-do\n\n+ Figure out most performant method of taking the picture\n\t+ Testing just with `camera.py`, which includes task of sending it via WiFi:\n\t\t+ With XCLK 20MHz:\n\t\t\t+ JPEG 240x240 = 48 FPS, 125 KB/s.\n\t\t\t+ GRAYSCALE 96x96 = 12 FPS, 111 KB/s. Why is it so slow?\n\t\t\t+ YUV 96x96 = 12 FPS, 220 KB/s. Well, it's expected, since grayscale is calculated from it.\n\t\t+ With XCLK 10MHz (tried because [some people suggested it might better](https://github.com/espressif/esp32-camera/issues/15)):\n\t\t\t+ JPEG 240x240 = 25 FPS, 79 KB/s.\n\t\t\t+ GRAYSCALE 96x96 = 6 FPS, 57 KB/s.\n\t\t+ Maybe it's possible to get better framerate with YUV/GRAYSCALE, [some people online claim](https://github.com/espressif/esp32-camera/issues/140), also [some tips on VSYNC issues around it](https://github.com/espressif/esp32-camera/issues/99).\n+ Movement detection into rotating around\n\t+ diff next frames in gray scale\n\t+ ignore margin\n\t+ maybe figure out how to select which previous frame to compare to (instead of immediately previous one)\n\t+ no movement -\u003e do nothing (or spin slowly?) \n\t+ little movement -\u003e find position (rect and then center) and rotate somewhat\n\t+ too much movement -\u003e do nothing? (safety)\n+ Test \u0026 fix driving model used in control.py script\n+ Checkout mobile app (related project), play around, fix any obvious issues\n+ Make sure caching for HTTP is disabled for dynamic routes.\n+ Add remaining controls for HTTP endpoint\n+ After updating to ESP-IDF 5.X:\n\t+ [Update to new motors/PWM driver](https://docs.espressif.com/projects/esp-idf/en/v5.0.7/esp32/migration-guides/release-5.x/peripherals.html#mcpwm), currently there are warnings about it (deprecation) when building.\n+ Use more C++ stuff instead C:\n\t+ `string_view`s, like in config/JSON related code. Recently had issue with `strlen` being unsafe...\n+ Detailed status output, including debug stuff\n\t+ Process list and stats.\n\t+ Memory heap usage \u0026 fragmentation.\n\t+ Networking stats (packet counts?)\n+ Min-max tasks:\n\t+ CPU pins:\n\t\t+ One core for HTTP and trash tasks\n\t\t+ Other core for networking \u0026 fast control (UDP)\n\t+ Trace tasks? `vTaskList`/`uxTaskGetSystemState`\n+ Website\n\t+ Camera\n\t+ Basic controls\n\t+ Network settings\n\t+ Camera settings\n\t+ Motors calibration\n+ Networking\n\t+ When network config is changed, make sure to send some kind of response before disconnecting.\n\t+ Allow set IP and DHCP settings for AP mode.\n\t+ Allow change DNS settings.\n\t+ Captive portal when in AP mode.\n\t+ Password protection (especially useful when connecting to open networks).\n\t+ If password was to be implemented, don't forget to secure UDP server somehow.\n+ [SNTP time sync](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html#sntp-time-synchronization)\n\t+ Make pool server and timezone configurable\n+ Create our own `Kconfig` file to keep optional features there, including some debugging. Also see https://esp32tutorials.com/esp32-static-fixed-ip-address-esp-idf/ \n+ Consider using some error codes instead full error messages (maybe some macro?)\n+ Allow some calibration for motors\n+ Allow changing frequency for PWM signals for motors\n+ Control LEDs with PWM?\n+ Should there be status/echo packet types for UDP?\n+ How does JSMN JSON handle escaping characters? Some strings like SSID/PSK might be invalid...\n+ How do we nicely pass understandable error, i.e. from parsing config to response? https://github.com/TartanLlama/expected 👀\n+ Does STA mode groups packets before delivering?\n+ Fix `esp32-camera` `fb_size` when using JPEG to allow smallest 96x96 to work. Having minimum of 2048 seems to work, using more for good measure seems advised. [(issue on github)](https://github.com/espressif/esp32-camera/issues/436)\n+ [Investigate rare bad JPEG issues](https://github.com/espressif/esp32-camera/issues/162) (missing 0xD9 and junk data).\n+ Explore hidden features of the camera, see https://github.com/espressif/esp32-camera/issues/203\n+ Rumor: `.xclk_freq_hz = 10'000'000,` for `camera_config_t`? 10 MHz might be better than 20 MHz, see https://github.com/espressif/esp32-camera/issues/15\n+ Isn't `COM8_AGC_EN` in the camera registers definitions off by 1? \n+ Camera parameters are better described in [old CircuitPython bindings docs for the esp32_camera library](https://web.archive.org/web/20221006004020/https://docs.circuitpython.org/en/latest/shared-bindings/esp32_camera/index.html) (or [newer link](https://docs.circuitpython.org/en/8.2.x/shared-bindings/espcamera/index.html), \u003csmall\u003eprobably they renamed the library wrapper\u003c/small\u003e)\n+ Create fast and C++ `constexpr` string to IP 4 function\n+ NVS dump. See https://github.com/AFontaine79/Espressif-NVS-Analyzer\n+ Expose nice [console](https://docs.espressif.com/projects/esp-idf/en/v4.4.3/esp32/api-reference/system/console.html) over serial monitor\n\t+ Basic WiFi config\n\t+ Allow uploading JSON to change config?\n+ You can use NAT?! \n\t+ https://github.com/jonask1337/esp-idf-nat-example/blob/master/main/main.c \n\t+ https://github.com/espressif/esp-lwip/blob/6132c9755a43d4e04de4457f1558ced415756e4d/src/core/ipv4/ip4_napt.c#L228\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagainpsychox%2Fyellowtoycar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagainpsychox%2Fyellowtoycar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagainpsychox%2Fyellowtoycar/lists"}