bc7d764cc8d8fc6f0bffeeae6efe538bbaa3fee3
Network-dat/wifi-dat/WIFI-DAT.md
| ... | ... | @@ -17,10 +17,12 @@ |
| 17 | 17 | |
| 18 | 18 | ## cheatsheet |
| 19 | 19 | |
| 20 | -- AP = access point |
|
| 21 | -- STA = station |
|
| 20 | +- AP = access point - Access point (ap) is the thing you connect to, e.g. wireless router. |
|
| 21 | +- STA = station - wireless/mobile station (sta) is your end user device, e.g. your phone. |
|
| 22 | + |
|
| 23 | + |
|
| 24 | + |
|
| 22 | 25 | |
| 23 | -Access point (ap) is the thing you connect to, e.g. wireless router. wireless/mobile station (sta) is your end user device, e.g. your phone. |
|
| 24 | 26 | |
| 25 | 27 | |
| 26 | 28 | - [[espressif-dat]] - [[esp8266-dat]] - [[ESP32-dat]] |
Tech-dat/acturator-dat/motor-driver-dat/motor-driver-code-dat/PWM-motor-esp-webserver-ap-1.ino
| ... | ... | @@ -1,98 +0,0 @@ |
| 1 | -#include <ESP8266WiFi.h> |
|
| 2 | -#include <ESP8266WebServer.h> |
|
| 3 | - |
|
| 4 | -// ===== WiFi 配置 ===== |
|
| 5 | -const char* ssid = "YOUR_SSID"; |
|
| 6 | -const char* password = "YOUR_PASSWORD"; |
|
| 7 | - |
|
| 8 | -// ===== GPIO 定义 ===== |
|
| 9 | -const int PWM_PIN = D1; // PWM 控制速度 IO5 |
|
| 10 | -const int DIR_PIN1 = D2; // 方向引脚1 IO4 |
|
| 11 | -const int DIR_PIN2 = D3; // 方向引脚2 IO0 |
|
| 12 | - |
|
| 13 | -// ===== Web Server ===== |
|
| 14 | -ESP8266WebServer server(80); |
|
| 15 | - |
|
| 16 | -// ===== HTML Web 控制界面 ===== |
|
| 17 | -const char html_page[] PROGMEM = R"rawliteral( |
|
| 18 | -<!DOCTYPE html><html> |
|
| 19 | -<head><title>ESP8266 Motor Control</title></head> |
|
| 20 | -<body> |
|
| 21 | -<h2>Motor Control</h2> |
|
| 22 | -<form action="/control"> |
|
| 23 | -Speed: <input type="range" name="speed" min="0" max="1023"><br> |
|
| 24 | -Direction: |
|
| 25 | -<select name="dir"> |
|
| 26 | - <option value="fw">Forward</option> |
|
| 27 | - <option value="rv">Reverse</option> |
|
| 28 | -</select><br> |
|
| 29 | -<input type="submit" value="Apply"> |
|
| 30 | -</form> |
|
| 31 | -</body></html> |
|
| 32 | -)rawliteral"; |
|
| 33 | - |
|
| 34 | -// ===== 处理 Web 请求 ===== |
|
| 35 | -void handleRoot() { |
|
| 36 | - server.send(200, "text/html", html_page); |
|
| 37 | -} |
|
| 38 | - |
|
| 39 | -void handleControl() { |
|
| 40 | - if (server.hasArg("speed")) { |
|
| 41 | - int speed = server.arg("speed").toInt(); // PWM 值 0-1023 |
|
| 42 | - analogWrite(PWM_PIN, speed); |
|
| 43 | - } |
|
| 44 | - |
|
| 45 | - if (server.hasArg("dir")) { |
|
| 46 | - String d = server.arg("dir"); |
|
| 47 | - if (d == "fw") { |
|
| 48 | - digitalWrite(DIR_PIN1, HIGH); |
|
| 49 | - digitalWrite(DIR_PIN2, LOW); |
|
| 50 | - } else { |
|
| 51 | - digitalWrite(DIR_PIN1, LOW); |
|
| 52 | - digitalWrite(DIR_PIN2, HIGH); |
|
| 53 | - } |
|
| 54 | - } |
|
| 55 | - |
|
| 56 | - server.sendHeader("Location", "/"); |
|
| 57 | - server.send(302, "text/plain", ""); |
|
| 58 | -} |
|
| 59 | - |
|
| 60 | -// ===== 初始化 ===== |
|
| 61 | -void setup() { |
|
| 62 | - Serial.begin(115200); |
|
| 63 | - |
|
| 64 | - pinMode(PWM_PIN, OUTPUT); |
|
| 65 | - pinMode(DIR_PIN1, OUTPUT); |
|
| 66 | - pinMode(DIR_PIN2, OUTPUT); |
|
| 67 | - |
|
| 68 | - // 默认停止 |
|
| 69 | - analogWrite(PWM_PIN, 0); |
|
| 70 | - digitalWrite(DIR_PIN1, LOW); |
|
| 71 | - digitalWrite(DIR_PIN2, LOW); |
|
| 72 | - |
|
| 73 | - // 启动为 WiFi AP 模式,使用固定 IP |
|
| 74 | - WiFi.mode(WIFI_AP); |
|
| 75 | - // 固定 AP 地址(根据需要修改) |
|
| 76 | - IPAddress apIP(192, 168, 50, 1); |
|
| 77 | - IPAddress apGateway(192, 168, 50, 1); |
|
| 78 | - IPAddress apSubnet(255, 255, 255, 0); |
|
| 79 | - if (!WiFi.softAPConfig(apIP, apGateway, apSubnet)) { |
|
| 80 | - Serial.println("softAPConfig failed"); |
|
| 81 | - } |
|
| 82 | - |
|
| 83 | - // 启动软 AP:使用 ssid 和 password(注意:WPA2 密码至少 8 字符) |
|
| 84 | - WiFi.softAP(ssid, password); |
|
| 85 | - delay(500); |
|
| 86 | - Serial.println(""); |
|
| 87 | - Serial.print("AP started, IP: "); |
|
| 88 | - Serial.println(WiFi.softAPIP()); |
|
| 89 | - |
|
| 90 | - // Web 服务 |
|
| 91 | - server.on("/", handleRoot); |
|
| 92 | - server.on("/control", handleControl); |
|
| 93 | - server.begin(); |
|
| 94 | -} |
|
| 95 | - |
|
| 96 | -void loop() { |
|
| 97 | - server.handleClient(); |
|
| 98 | -} |
|
| ... | ... | \ No newline at end of file |
Tech-dat/acturator-dat/motor-driver-dat/motor-driver-code-dat/PWM-motor-esp-webserver-sta-1.ino.ino
| ... | ... | @@ -1,94 +0,0 @@ |
| 1 | - |
|
| 2 | - |
|
| 3 | -#include <ESP8266WiFi.h> |
|
| 4 | -#include <ESP8266WebServer.h> |
|
| 5 | - |
|
| 6 | -// ===== WiFi 配置 ===== |
|
| 7 | -const char* ssid = "YOUR_SSID"; |
|
| 8 | -const char* password = "YOUR_PASSWORD"; |
|
| 9 | - |
|
| 10 | -// ===== GPIO 定义 ===== |
|
| 11 | -const int PWM_PIN = D1; // PWM 控制速度 IO5 |
|
| 12 | -const int DIR_PIN1 = D2; // 方向引脚1 IO4 |
|
| 13 | -const int DIR_PIN2 = D3; // 方向引脚2 IO0 |
|
| 14 | - |
|
| 15 | -// ===== Web Server ===== |
|
| 16 | -ESP8266WebServer server(80); |
|
| 17 | - |
|
| 18 | -// ===== HTML Web 控制界面 ===== |
|
| 19 | -const char html_page[] PROGMEM = R"rawliteral( |
|
| 20 | -<!DOCTYPE html><html> |
|
| 21 | -<head><title>ESP8266 Motor Control</title></head> |
|
| 22 | -<body> |
|
| 23 | -<h2>Motor Control</h2> |
|
| 24 | -<form action="/control"> |
|
| 25 | -Speed: <input type="range" name="speed" min="0" max="1023"><br> |
|
| 26 | -Direction: |
|
| 27 | -<select name="dir"> |
|
| 28 | - <option value="fw">Forward</option> |
|
| 29 | - <option value="rv">Reverse</option> |
|
| 30 | -</select><br> |
|
| 31 | -<input type="submit" value="Apply"> |
|
| 32 | -</form> |
|
| 33 | -</body></html> |
|
| 34 | -)rawliteral"; |
|
| 35 | - |
|
| 36 | -// ===== 处理 Web 请求 ===== |
|
| 37 | -void handleRoot() { |
|
| 38 | - server.send(200, "text/html", html_page); |
|
| 39 | -} |
|
| 40 | - |
|
| 41 | -void handleControl() { |
|
| 42 | - if (server.hasArg("speed")) { |
|
| 43 | - int speed = server.arg("speed").toInt(); // PWM 值 0-1023 |
|
| 44 | - analogWrite(PWM_PIN, speed); |
|
| 45 | - } |
|
| 46 | - |
|
| 47 | - if (server.hasArg("dir")) { |
|
| 48 | - String d = server.arg("dir"); |
|
| 49 | - if (d == "fw") { |
|
| 50 | - digitalWrite(DIR_PIN1, HIGH); |
|
| 51 | - digitalWrite(DIR_PIN2, LOW); |
|
| 52 | - } else { |
|
| 53 | - digitalWrite(DIR_PIN1, LOW); |
|
| 54 | - digitalWrite(DIR_PIN2, HIGH); |
|
| 55 | - } |
|
| 56 | - } |
|
| 57 | - |
|
| 58 | - server.sendHeader("Location", "/"); |
|
| 59 | - server.send(302, "text/plain", ""); |
|
| 60 | -} |
|
| 61 | - |
|
| 62 | -// ===== 初始化 ===== |
|
| 63 | -void setup() { |
|
| 64 | - Serial.begin(115200); |
|
| 65 | - |
|
| 66 | - pinMode(PWM_PIN, OUTPUT); |
|
| 67 | - pinMode(DIR_PIN1, OUTPUT); |
|
| 68 | - pinMode(DIR_PIN2, OUTPUT); |
|
| 69 | - |
|
| 70 | - // 默认停止 |
|
| 71 | - analogWrite(PWM_PIN, 0); |
|
| 72 | - digitalWrite(DIR_PIN1, LOW); |
|
| 73 | - digitalWrite(DIR_PIN2, LOW); |
|
| 74 | - |
|
| 75 | - // 连接 WiFi |
|
| 76 | - WiFi.mode(WIFI_STA); |
|
| 77 | - WiFi.begin(ssid, password); |
|
| 78 | - while (WiFi.status() != WL_CONNECTED) { |
|
| 79 | - delay(500); |
|
| 80 | - Serial.print("."); |
|
| 81 | - } |
|
| 82 | - Serial.println(""); |
|
| 83 | - Serial.print("Connected, IP: "); |
|
| 84 | - Serial.println(WiFi.localIP()); |
|
| 85 | - |
|
| 86 | - // Web 服务 |
|
| 87 | - server.on("/", handleRoot); |
|
| 88 | - server.on("/control", handleControl); |
|
| 89 | - server.begin(); |
|
| 90 | -} |
|
| 91 | - |
|
| 92 | -void loop() { |
|
| 93 | - server.handleClient(); |
|
| 94 | -} |
|
| ... | ... | \ No newline at end of file |
Tech-dat/acturator-dat/motor-driver-dat/motor-driver-code-dat/motor-driver-code-dat.md
| ... | ... | @@ -1,22 +0,0 @@ |
| 1 | - |
|
| 2 | -# motor-driver-code-dat |
|
| 3 | - |
|
| 4 | - |
|
| 5 | - |
|
| 6 | -## drive by wifi and webserver |
|
| 7 | - |
|
| 8 | -- [[PWM-motor-esp-webserver-sta-1.ino]] |
|
| 9 | - |
|
| 10 | -- [[wifi-motor-control-dat]] |
|
| 11 | - |
|
| 12 | -- [[ESP32-rc-car-dat]] |
|
| 13 | - |
|
| 14 | - |
|
| 15 | - |
|
| 16 | - |
|
| 17 | - |
|
| 18 | -## ref |
|
| 19 | - |
|
| 20 | -- [[motor-driver-dat]] |
|
| 21 | - |
|
| 22 | - |
code-dat/RC-code-dat/PWM-1ch.ino
| ... | ... | @@ -1,74 +0,0 @@ |
| 1 | -// Define pins for each RC channel |
|
| 2 | -int aileronPin = 2; // Channel 1 |
|
| 3 | - |
|
| 4 | -const int ENA = 5; // PWM for speed for Motor 1 |
|
| 5 | -const int ENB = 4; // PWM for speed for Motor 2 |
|
| 6 | - |
|
| 7 | -const int IN1 = 0; // Direction for Motor 1 (IN2_Motor1 is inverted in hardware) |
|
| 8 | -const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 9 | - |
|
| 10 | -long aileronControl; |
|
| 11 | - |
|
| 12 | -long readAileronControlSignal() { |
|
| 13 | - unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 14 | - if (rawPWM == 0) { // Timeout or no signal |
|
| 15 | - return 50; // Mid-point for 0-100 scale (1500us equivalent) |
|
| 16 | - } |
|
| 17 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 18 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 19 | -} |
|
| 20 | - |
|
| 21 | -void setup() { |
|
| 22 | - pinMode(aileronPin, INPUT); |
|
| 23 | - |
|
| 24 | - pinMode(ENA, OUTPUT); |
|
| 25 | - pinMode(ENB, OUTPUT); |
|
| 26 | - pinMode(IN1, OUTPUT); |
|
| 27 | - pinMode(IN2, OUTPUT); |
|
| 28 | - |
|
| 29 | - // Initialize motors to off |
|
| 30 | - digitalWrite(IN1, LOW); |
|
| 31 | - digitalWrite(IN2, LOW); |
|
| 32 | - analogWrite(ENA, 0); |
|
| 33 | - analogWrite(ENB, 0); |
|
| 34 | - |
|
| 35 | - Serial.begin(9600); |
|
| 36 | -} |
|
| 37 | - |
|
| 38 | -void loop() { |
|
| 39 | - // Read mapped control signals from each channel |
|
| 40 | - aileronControl = readAileronControlSignal(); |
|
| 41 | - |
|
| 42 | - // Print the mapped control signal values to the Serial Monitor |
|
| 43 | - Serial.print("Aileron: "); |
|
| 44 | - Serial.print(aileronControl); |
|
| 45 | - Serial.println(); // Newline for better readability |
|
| 46 | - |
|
| 47 | - if (aileronControl > 70) { |
|
| 48 | - // Forward |
|
| 49 | - digitalWrite(IN1, HIGH); // Motor 1 forward |
|
| 50 | - digitalWrite(IN2, HIGH); // Motor 2 forward |
|
| 51 | - |
|
| 52 | - // Map aileronControl (61-100) to PWM speed (e.g., 100-255) |
|
| 53 | - int motorSpeed = map(aileronControl, 61, 100, 100, 255); |
|
| 54 | - analogWrite(ENA, motorSpeed); |
|
| 55 | - analogWrite(ENB, motorSpeed); |
|
| 56 | - } else if (aileronControl < 30) { |
|
| 57 | - // Backward |
|
| 58 | - digitalWrite(IN1, LOW); // Motor 1 backward |
|
| 59 | - digitalWrite(IN2, LOW); // Motor 2 backward |
|
| 60 | - |
|
| 61 | - // Map aileronControl (0-39) to PWM speed (e.g., 255-100, reversing the range for backward) |
|
| 62 | - int motorSpeed = map(aileronControl, 0, 39, 255, 100); |
|
| 63 | - analogWrite(ENA, motorSpeed); |
|
| 64 | - analogWrite(ENB, motorSpeed); |
|
| 65 | - } else { |
|
| 66 | - // Stop motors (aileronControl is between 40 and 60 inclusive) |
|
| 67 | - digitalWrite(IN1, LOW); |
|
| 68 | - digitalWrite(IN2, LOW); |
|
| 69 | - analogWrite(ENA, 0); |
|
| 70 | - analogWrite(ENB, 0); |
|
| 71 | - } |
|
| 72 | - |
|
| 73 | - delay(100); // Limit output rate |
|
| 74 | -} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/PWM-2ch-2.ino
| ... | ... | @@ -1,142 +0,0 @@ |
| 1 | -// Define pins for each RC channel |
|
| 2 | -int aileronPin = 14; // Channel 1 (Throttle) |
|
| 3 | -int elevatorPin = 12; // Channel 2 (Steering) |
|
| 4 | - |
|
| 5 | -const int ENA = 5; // PWM for speed for Motor 1 |
|
| 6 | -const int ENB = 4; // PWM for speed for Motor 2 |
|
| 7 | - |
|
| 8 | -const int IN1 = 0; // Direction for Motor 1 |
|
| 9 | -const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 10 | - |
|
| 11 | -long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 12 | -long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 13 | - |
|
| 14 | -// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 15 | -long readAileronControlSignal() { |
|
| 16 | - unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 17 | - // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 18 | - // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 19 | - if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 20 | - return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 21 | - } |
|
| 22 | - // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 23 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 24 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 25 | -} |
|
| 26 | - |
|
| 27 | -// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 28 | -long readElevatorControlSignal() { |
|
| 29 | - unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 30 | - // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 31 | - // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 32 | - if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 33 | - return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 34 | - } |
|
| 35 | - // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 36 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 37 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 38 | -} |
|
| 39 | - |
|
| 40 | -void setup() { |
|
| 41 | - pinMode(aileronPin, INPUT); |
|
| 42 | - pinMode(elevatorPin, INPUT); // Initialize elevator pin |
|
| 43 | - |
|
| 44 | - pinMode(ENA, OUTPUT); |
|
| 45 | - pinMode(ENB, OUTPUT); |
|
| 46 | - pinMode(IN1, OUTPUT); |
|
| 47 | - pinMode(IN2, OUTPUT); |
|
| 48 | - |
|
| 49 | - // Initialize motors to off |
|
| 50 | - digitalWrite(IN1, LOW); |
|
| 51 | - digitalWrite(IN2, LOW); |
|
| 52 | - analogWrite(ENA, 0); |
|
| 53 | - analogWrite(ENB, 0); |
|
| 54 | - |
|
| 55 | - Serial.begin(9600); |
|
| 56 | -} |
|
| 57 | - |
|
| 58 | -// Helper function to control a single motor |
|
| 59 | -// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 60 | -void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 61 | - if (pwmVal > 0) { // Forward |
|
| 62 | - digitalWrite(dirPin, HIGH); |
|
| 63 | - analogWrite(speedPin, pwmVal); |
|
| 64 | - } else if (pwmVal < 0) { // Backward |
|
| 65 | - digitalWrite(dirPin, LOW); |
|
| 66 | - analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 67 | - } else { // Stop |
|
| 68 | - digitalWrite(dirPin, LOW); // Or HIGH, doesn't matter much if speed is 0 |
|
| 69 | - analogWrite(speedPin, 0); |
|
| 70 | - } |
|
| 71 | -} |
|
| 72 | - |
|
| 73 | -// Helper function to map RC control input (0-100) to an output range (e.g., -255 to 255) |
|
| 74 | -// with a deadband around the center (e.g., 50). |
|
| 75 | -long mapWithDeadband(long rcValue, int rcMin, int rcMax, int rcCenter, int deadbandRadius, int outMin, int outMax) { |
|
| 76 | - long mappedValue = 0; |
|
| 77 | - int deadbandLower = rcCenter - deadbandRadius; |
|
| 78 | - int deadbandUpper = rcCenter + deadbandRadius; |
|
| 79 | - |
|
| 80 | - if (rcValue < deadbandLower) { |
|
| 81 | - // Map the range [rcMin, deadbandLower - 1] to [outMin, -1] |
|
| 82 | - // Ensure deadbandLower - 1 is not less than rcMin |
|
| 83 | - if (deadbandLower -1 < rcMin) { |
|
| 84 | - mappedValue = outMin; |
|
| 85 | - } else { |
|
| 86 | - mappedValue = map(rcValue, rcMin, deadbandLower - 1, outMin, -1); |
|
| 87 | - } |
|
| 88 | - } else if (rcValue > deadbandUpper) { |
|
| 89 | - // Map the range [deadbandUpper + 1, rcMax] to [1, outMax] |
|
| 90 | - // Ensure deadbandUpper + 1 is not greater than rcMax |
|
| 91 | - if (deadbandUpper + 1 > rcMax) { |
|
| 92 | - mappedValue = outMax; |
|
| 93 | - } else { |
|
| 94 | - mappedValue = map(rcValue, deadbandUpper + 1, rcMax, 1, outMax); |
|
| 95 | - } |
|
| 96 | - } else { |
|
| 97 | - // Inside deadband |
|
| 98 | - mappedValue = 0; |
|
| 99 | - } |
|
| 100 | - return constrain(mappedValue, outMin, outMax); |
|
| 101 | -} |
|
| 102 | - |
|
| 103 | -void loop() { |
|
| 104 | - // Read mapped control signals from each channel |
|
| 105 | - aileronControl = readAileronControlSignal(); // Throttle (0-100) |
|
| 106 | - elevatorControl = readElevatorControlSignal(); // Steering (0-100) |
|
| 107 | - |
|
| 108 | - // Print the mapped control signal values to the Serial Monitor |
|
| 109 | - Serial.print("Aileron (Throttle): "); |
|
| 110 | - Serial.print(aileronControl); |
|
| 111 | - Serial.print(" Elevator (Steering): "); |
|
| 112 | - Serial.print(elevatorControl); |
|
| 113 | - Serial.println(); |
|
| 114 | - |
|
| 115 | - // Define deadband radius (e.g., +/- 5 around center of 50 for a 0-100 input) |
|
| 116 | - // This means input values from 45 to 55 (inclusive if center is 50 and radius is 5) will be treated as 0. |
|
| 117 | - int deadbandRadius = 10; |
|
| 118 | - float steeringFactor = 3; // Adjust this value to change steering sensitivity |
|
| 119 | - float throttleFactor = 3; // Adjust this value to change throttle sensitivity (e.g., 1.2 for 20% stronger throttle) |
|
| 120 | - |
|
| 121 | - // Map control values with deadband |
|
| 122 | - long rawThrottleValue = mapWithDeadband(aileronControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 123 | - long rawSteeringValue = mapWithDeadband(elevatorControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 124 | - |
|
| 125 | - // Apply sensitivity factors |
|
| 126 | - long throttleValue = rawThrottleValue * throttleFactor; |
|
| 127 | - long adjustedSteeringValue = rawSteeringValue * steeringFactor; |
|
| 128 | - |
|
| 129 | - // Mix throttle and steering for differential drive |
|
| 130 | - long motor1Pwm = throttleValue + adjustedSteeringValue; |
|
| 131 | - long motor2Pwm = throttleValue - adjustedSteeringValue; |
|
| 132 | - |
|
| 133 | - // Constrain PWM values to the valid range [-255, 255] |
|
| 134 | - motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 135 | - motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 136 | - |
|
| 137 | - // Set motor speeds and directions |
|
| 138 | - setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 139 | - setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 140 | - |
|
| 141 | - delay(20); // Shorter delay for better responsiveness |
|
| 142 | -} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/PWM-2ch-v2.ino
| ... | ... | @@ -1,68 +0,0 @@ |
| 1 | -// RC signal input pins |
|
| 2 | -#define THROTTLE_PIN 2 // Channel 1 (forward/back) |
|
| 3 | -#define STEERING_PIN 3 // Channel 2 (left/right) |
|
| 4 | - |
|
| 5 | -// Motor control pins (L298N) |
|
| 6 | -#define LEFT_ENA 9 |
|
| 7 | -#define LEFT_IN1 4 |
|
| 8 | -#define LEFT_IN2 5 |
|
| 9 | - |
|
| 10 | -#define RIGHT_ENB 10 |
|
| 11 | -#define RIGHT_IN3 6 |
|
| 12 | -#define RIGHT_IN4 7 |
|
| 13 | - |
|
| 14 | -int throttle, steering; |
|
| 15 | - |
|
| 16 | -void setup() { |
|
| 17 | - pinMode(THROTTLE_PIN, INPUT); |
|
| 18 | - pinMode(STEERING_PIN, INPUT); |
|
| 19 | - |
|
| 20 | - pinMode(LEFT_IN1, OUTPUT); |
|
| 21 | - pinMode(LEFT_IN2, OUTPUT); |
|
| 22 | - pinMode(LEFT_ENA, OUTPUT); |
|
| 23 | - |
|
| 24 | - pinMode(RIGHT_IN3, OUTPUT); |
|
| 25 | - pinMode(RIGHT_IN4, OUTPUT); |
|
| 26 | - pinMode(RIGHT_ENB, OUTPUT); |
|
| 27 | - |
|
| 28 | - Serial.begin(9600); |
|
| 29 | -} |
|
| 30 | - |
|
| 31 | -void loop() { |
|
| 32 | - // Read PWM input |
|
| 33 | - throttle = pulseIn(THROTTLE_PIN, HIGH, 25000); |
|
| 34 | - steering = pulseIn(STEERING_PIN, HIGH, 25000); |
|
| 35 | - |
|
| 36 | - // Center = 1500, range = 1000–2000 |
|
| 37 | - int throttleVal = map(throttle, 1000, 2000, -255, 255); |
|
| 38 | - int steeringVal = map(steering, 1000, 2000, -100, 100); // less aggressive |
|
| 39 | - |
|
| 40 | - // Motor mixing (differential drive) |
|
| 41 | - int leftSpeed = constrain(throttleVal + steeringVal, -255, 255); |
|
| 42 | - int rightSpeed = constrain(throttleVal - steeringVal, -255, 255); |
|
| 43 | - |
|
| 44 | - setMotor(LEFT_IN1, LEFT_IN2, LEFT_ENA, leftSpeed); |
|
| 45 | - setMotor(RIGHT_IN3, RIGHT_IN4, RIGHT_ENB, rightSpeed); |
|
| 46 | - |
|
| 47 | - // Debug |
|
| 48 | - Serial.print("Throttle: "); Serial.print(throttleVal); |
|
| 49 | - Serial.print(" Steering: "); Serial.print(steeringVal); |
|
| 50 | - Serial.print(" L: "); Serial.print(leftSpeed); |
|
| 51 | - Serial.print(" R: "); Serial.println(rightSpeed); |
|
| 52 | - |
|
| 53 | - delay(20); |
|
| 54 | -} |
|
| 55 | - |
|
| 56 | -void setMotor(int in1, int in2, int ena, int speed) { |
|
| 57 | - if (speed > 0) { |
|
| 58 | - digitalWrite(in1, HIGH); |
|
| 59 | - digitalWrite(in2, LOW); |
|
| 60 | - } else if (speed < 0) { |
|
| 61 | - digitalWrite(in1, LOW); |
|
| 62 | - digitalWrite(in2, HIGH); |
|
| 63 | - } else { |
|
| 64 | - digitalWrite(in1, LOW); |
|
| 65 | - digitalWrite(in2, LOW); |
|
| 66 | - } |
|
| 67 | - analogWrite(ena, abs(speed)); |
|
| 68 | -} |
code-dat/RC-code-dat/RC-code-dat.md
| ... | ... | @@ -2,6 +2,11 @@ |
| 2 | 2 | # RC-code-dat |
| 3 | 3 | |
| 4 | 4 | |
| 5 | + |
|
| 6 | + |
|
| 7 | + |
|
| 8 | + |
|
| 9 | + |
|
| 5 | 10 | basic code == [[basic-code-1.ino]], or [[ultrasonic car-1602.pde]] |
| 6 | 11 | |
| 7 | 12 | |
| ... | ... | @@ -9,6 +14,10 @@ basic code == [[basic-code-1.ino]], or [[ultrasonic car-1602.pde]] |
| 9 | 14 | |
| 10 | 15 | - [[SDR1064-dat]] - [[nodemcu-dat]] |
| 11 | 16 | |
| 17 | +- [[serial-motor-1.ino]] - [[motor-1-wifi-ap.ino]] |
|
| 18 | + |
|
| 19 | + |
|
| 20 | + |
|
| 12 | 21 | ## code |
| 13 | 22 | |
| 14 | 23 | - [[PWM-1ch.ino]] - [[PWM-2ch.ino]] - [[PWM-2ch-v2.ino]] |
code-dat/RC-code-dat/SDR1064-1.ino
| ... | ... | @@ -1,94 +0,0 @@ |
| 1 | -// Define pins for each RC channel |
|
| 2 | -int aileronPin = 14; // Channel 1 (Throttle) |
|
| 3 | -int elevatorPin = 12; // Channel 2 (Steering) |
|
| 4 | - |
|
| 5 | -const int ENA = 5; // PWM for speed for Motor 1 |
|
| 6 | -const int ENB = 4; // PWM for speed for Motor 2 |
|
| 7 | - |
|
| 8 | -const int IN1 = 0; // Direction for Motor 1 |
|
| 9 | -const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 10 | - |
|
| 11 | -long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 12 | -long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 13 | - |
|
| 14 | -// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 15 | -long readAileronControlSignal() { |
|
| 16 | - unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 17 | - // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 18 | - if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 19 | - return 50; // Mid-point for 0-100 scale |
|
| 20 | - } |
|
| 21 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 22 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 23 | -} |
|
| 24 | - |
|
| 25 | -// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 26 | -long readElevatorControlSignal() { |
|
| 27 | - unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 28 | - // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 29 | - if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 30 | - return 50; // Mid-point for 0-100 scale |
|
| 31 | - } |
|
| 32 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 33 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 34 | -} |
|
| 35 | - |
|
| 36 | -void setup() { |
|
| 37 | - pinMode(aileronPin, INPUT); |
|
| 38 | - pinMode(elevatorPin, INPUT); |
|
| 39 | - |
|
| 40 | - pinMode(ENA, OUTPUT); |
|
| 41 | - pinMode(ENB, OUTPUT); |
|
| 42 | - pinMode(IN1, OUTPUT); |
|
| 43 | - pinMode(IN2, OUTPUT); |
|
| 44 | - |
|
| 45 | - // Initialize motors to off |
|
| 46 | - digitalWrite(IN1, LOW); |
|
| 47 | - digitalWrite(IN2, LOW); |
|
| 48 | - analogWrite(ENA, 0); |
|
| 49 | - analogWrite(ENB, 0); |
|
| 50 | -} |
|
| 51 | - |
|
| 52 | -// Helper function to control a single motor |
|
| 53 | -// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 54 | -void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 55 | - if (pwmVal > 0) { // Forward |
|
| 56 | - digitalWrite(dirPin, HIGH); |
|
| 57 | - analogWrite(speedPin, pwmVal); |
|
| 58 | - } else if (pwmVal < 0) { // Backward |
|
| 59 | - digitalWrite(dirPin, LOW); |
|
| 60 | - analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 61 | - } else { // Stop |
|
| 62 | - digitalWrite(dirPin, LOW); |
|
| 63 | - analogWrite(speedPin, 0); |
|
| 64 | - } |
|
| 65 | -} |
|
| 66 | - |
|
| 67 | -void loop() { |
|
| 68 | - // Read mapped control signals from each channel |
|
| 69 | - aileronControl = readAileronControlSignal(); // Throttle (0-100, 50 is neutral) |
|
| 70 | - elevatorControl = readElevatorControlSignal(); // Steering (0-100, 50 is neutral) |
|
| 71 | - |
|
| 72 | - // Map control values directly |
|
| 73 | - // aileronControl (0-100) to throttleValue (-255 to 255) |
|
| 74 | - // 0 -> -255 (full reverse), 50 -> 0 (stop), 100 -> 255 (full forward) |
|
| 75 | - long throttleValue = map(aileronControl, 0, 100, -255, 255); |
|
| 76 | - |
|
| 77 | - // elevatorControl (0-100) to steeringValue (-255 to 255) |
|
| 78 | - // 0 -> -255 (full left turn effect), 50 -> 0 (straight), 100 -> 255 (full right turn effect) |
|
| 79 | - long steeringValue = map(elevatorControl, 0, 100, -255, 255); |
|
| 80 | - |
|
| 81 | - // Mix throttle and steering for differential drive |
|
| 82 | - long motor1Pwm = throttleValue + steeringValue; |
|
| 83 | - long motor2Pwm = throttleValue - steeringValue; |
|
| 84 | - |
|
| 85 | - // Constrain PWM values to the valid range [-255, 255] |
|
| 86 | - motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 87 | - motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 88 | - |
|
| 89 | - // Set motor speeds and directions |
|
| 90 | - setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 91 | - setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 92 | - |
|
| 93 | - delay(20); // Delay for responsiveness |
|
| 94 | -} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-2.ino
| ... | ... | @@ -1,167 +0,0 @@ |
| 1 | -#include <Adafruit_NeoPixel.h> |
|
| 2 | - |
|
| 3 | -// Define pins for each RC channel |
|
| 4 | -int aileronPin = 14; // Channel 1 (Throttle) // D5 |
|
| 5 | -int elevatorPin = 12; // Channel 2 (Steering) // D6 |
|
| 6 | - |
|
| 7 | -const int IN1 = 0; // Direction for Motor 1 // D3 |
|
| 8 | -const int IN2 = 2; // Direction pin 1 for Motor 2 // D4 |
|
| 9 | - |
|
| 10 | -// WS2812 LED Strip Configuration |
|
| 11 | -#define LED_PIN 15 // nodemcu pin D8 |
|
| 12 | -#define LED_COUNT 8 |
|
| 13 | -Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); |
|
| 14 | - |
|
| 15 | -long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 16 | -long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 17 | - |
|
| 18 | -// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 19 | -long readAileronControlSignal() { |
|
| 20 | - unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 21 | - // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 22 | - // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 23 | - if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 24 | - return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 25 | - } |
|
| 26 | - // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 27 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 28 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 29 | -} |
|
| 30 | - |
|
| 31 | -// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 32 | -long readElevatorControlSignal() { |
|
| 33 | - unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 34 | - // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 35 | - // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 36 | - if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 37 | - return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 38 | - } |
|
| 39 | - // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 40 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 41 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 42 | -} |
|
| 43 | - |
|
| 44 | -void setup() { |
|
| 45 | - pinMode(aileronPin, INPUT); |
|
| 46 | - pinMode(elevatorPin, INPUT); // Initialize elevator pin |
|
| 47 | - |
|
| 48 | - pinMode(ENA, OUTPUT); |
|
| 49 | - pinMode(ENB, OUTPUT); |
|
| 50 | - pinMode(IN1, OUTPUT); |
|
| 51 | - pinMode(IN2, OUTPUT); |
|
| 52 | - |
|
| 53 | - // Initialize motors to off |
|
| 54 | - digitalWrite(IN1, LOW); |
|
| 55 | - digitalWrite(IN2, LOW); |
|
| 56 | - analogWrite(ENA, 0); |
|
| 57 | - analogWrite(ENB, 0); |
|
| 58 | - |
|
| 59 | - Serial.begin(9600); |
|
| 60 | - |
|
| 61 | - strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) |
|
| 62 | - strip.show(); // Turn OFF all pixels ASAP |
|
| 63 | - strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255) |
|
| 64 | -} |
|
| 65 | - |
|
| 66 | -// Helper function to control a single motor |
|
| 67 | -// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 68 | -void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 69 | - if (pwmVal > 0) { // Forward |
|
| 70 | - digitalWrite(dirPin, HIGH); |
|
| 71 | - analogWrite(speedPin, pwmVal); |
|
| 72 | - } else if (pwmVal < 0) { // Backward |
|
| 73 | - digitalWrite(dirPin, LOW); |
|
| 74 | - analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 75 | - } else { // Stop |
|
| 76 | - digitalWrite(dirPin, LOW); // Or HIGH, doesn't matter much if speed is 0 |
|
| 77 | - analogWrite(speedPin, 0); |
|
| 78 | - } |
|
| 79 | -} |
|
| 80 | - |
|
| 81 | -// Helper function to map RC control input (0-100) to an output range (e.g., -255 to 255) |
|
| 82 | -// with a deadband around the center (e.g., 50). |
|
| 83 | -long mapWithDeadband(long rcValue, int rcMin, int rcMax, int rcCenter, int deadbandRadius, int outMin, int outMax) { |
|
| 84 | - long mappedValue = 0; |
|
| 85 | - int deadbandLower = rcCenter - deadbandRadius; |
|
| 86 | - int deadbandUpper = rcCenter + deadbandRadius; |
|
| 87 | - |
|
| 88 | - if (rcValue < deadbandLower) { |
|
| 89 | - // Map the range [rcMin, deadbandLower - 1] to [outMin, -1] |
|
| 90 | - // Ensure deadbandLower - 1 is not less than rcMin |
|
| 91 | - if (deadbandLower -1 < rcMin) { |
|
| 92 | - mappedValue = outMin; |
|
| 93 | - } else { |
|
| 94 | - mappedValue = map(rcValue, rcMin, deadbandLower - 1, outMin, -1); |
|
| 95 | - } |
|
| 96 | - } else if (rcValue > deadbandUpper) { |
|
| 97 | - // Map the range [deadbandUpper + 1, rcMax] to [1, outMax] |
|
| 98 | - // Ensure deadbandUpper + 1 is not greater than rcMax |
|
| 99 | - if (deadbandUpper + 1 > rcMax) { |
|
| 100 | - mappedValue = outMax; |
|
| 101 | - } else { |
|
| 102 | - mappedValue = map(rcValue, deadbandUpper + 1, rcMax, 1, outMax); |
|
| 103 | - } |
|
| 104 | - } else { |
|
| 105 | - // Inside deadband |
|
| 106 | - mappedValue = 0; |
|
| 107 | - } |
|
| 108 | - return constrain(mappedValue, outMin, outMax); |
|
| 109 | -} |
|
| 110 | - |
|
| 111 | -// Function to create a random blinking effect for WS2812 LEDs |
|
| 112 | -void randomBlinkEffect() { |
|
| 113 | - for (int i = 0; i < LED_COUNT; i++) { |
|
| 114 | - // Turn on a random LED with a random color |
|
| 115 | - if (random(0, 2) == 1) { // 50% chance to turn on this LED |
|
| 116 | - strip.setPixelColor(i, strip.Color(random(0, 256), random(0, 256), random(0, 256))); |
|
| 117 | - } else { |
|
| 118 | - strip.setPixelColor(i, strip.Color(0, 0, 0)); // Turn off |
|
| 119 | - } |
|
| 120 | - } |
|
| 121 | - strip.show(); // Send the updated pixel colors to the hardware. |
|
| 122 | - delay(100); // Wait a short period |
|
| 123 | -} |
|
| 124 | - |
|
| 125 | -void loop() { |
|
| 126 | - // Read mapped control signals from each channel |
|
| 127 | - aileronControl = readAileronControlSignal(); // Throttle (0-100) |
|
| 128 | - elevatorControl = readElevatorControlSignal(); // Steering (0-100) |
|
| 129 | - |
|
| 130 | - // Print the mapped control signal values to the Serial Monitor |
|
| 131 | - Serial.print("Aileron (Throttle): "); |
|
| 132 | - Serial.print(aileronControl); |
|
| 133 | - Serial.print(" Elevator (Steering): "); |
|
| 134 | - Serial.print(elevatorControl); |
|
| 135 | - Serial.println(); |
|
| 136 | - |
|
| 137 | - // Define deadband radius (e.g., +/- 5 around center of 50 for a 0-100 input) |
|
| 138 | - // This means input values from 45 to 55 (inclusive if center is 50 and radius is 5) will be treated as 0. |
|
| 139 | - int deadbandRadius = 15; |
|
| 140 | - float steeringFactor = 3; // Adjust this value to change steering sensitivity |
|
| 141 | - float throttleFactor = 3; // Adjust this value to change throttle sensitivity (e.g., 1.2 for 20% stronger throttle) |
|
| 142 | - |
|
| 143 | - // Map control values with deadband |
|
| 144 | - long rawThrottleValue = mapWithDeadband(aileronControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 145 | - long rawSteeringValue = mapWithDeadband(elevatorControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 146 | - |
|
| 147 | - // Apply sensitivity factors |
|
| 148 | - long throttleValue = rawThrottleValue * throttleFactor; |
|
| 149 | - long adjustedSteeringValue = rawSteeringValue * steeringFactor; |
|
| 150 | - |
|
| 151 | - // Mix throttle and steering for differential drive |
|
| 152 | - long motor1Pwm = throttleValue + adjustedSteeringValue; |
|
| 153 | - long motor2Pwm = throttleValue - adjustedSteeringValue; |
|
| 154 | - |
|
| 155 | - // Constrain PWM values to the valid range [-255, 255] |
|
| 156 | - motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 157 | - motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 158 | - |
|
| 159 | - // Set motor speeds and directions |
|
| 160 | - setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 161 | - setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 162 | - |
|
| 163 | - // Add the LED effect |
|
| 164 | - randomBlinkEffect(); |
|
| 165 | - |
|
| 166 | - delay(20); // Shorter delay for better responsiveness |
|
| 167 | -} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-3.ino
| ... | ... | @@ -1,136 +0,0 @@ |
| 1 | -// Define pins for each RC channel |
|
| 2 | -int aileronPin = 14; // Channel 1 (Throttle) |
|
| 3 | -int elevatorPin = 12; // Channel 2 (Steering) |
|
| 4 | - |
|
| 5 | -const int ENA = 5; // PWM for speed for Motor 1 |
|
| 6 | -const int ENB = 4; // PWM for speed for Motor 2 |
|
| 7 | - |
|
| 8 | -const int IN1 = 0; // Direction for Motor 1 |
|
| 9 | -const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 10 | - |
|
| 11 | -long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 12 | -long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 13 | - |
|
| 14 | -// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 15 | -long readAileronControlSignal() { |
|
| 16 | - unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 17 | - if (rawPWM == 0) { // Timeout or no signal |
|
| 18 | - return 50; // Mid-point for 0-100 scale (1500us equivalent) |
|
| 19 | - } |
|
| 20 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 21 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 22 | -} |
|
| 23 | - |
|
| 24 | -// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 25 | -long readElevatorControlSignal() { |
|
| 26 | - unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 27 | - if (rawPWM == 0) { // Timeout or no signal |
|
| 28 | - return 50; // Mid-point for 0-100 scale (1500us equivalent) |
|
| 29 | - } |
|
| 30 | - long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 31 | - return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 32 | -} |
|
| 33 | - |
|
| 34 | -void setup() { |
|
| 35 | - pinMode(aileronPin, INPUT); |
|
| 36 | - pinMode(elevatorPin, INPUT); // Initialize elevator pin |
|
| 37 | - |
|
| 38 | - pinMode(ENA, OUTPUT); |
|
| 39 | - pinMode(ENB, OUTPUT); |
|
| 40 | - pinMode(IN1, OUTPUT); |
|
| 41 | - pinMode(IN2, OUTPUT); |
|
| 42 | - |
|
| 43 | - // Initialize motors to off |
|
| 44 | - digitalWrite(IN1, LOW); |
|
| 45 | - digitalWrite(IN2, LOW); |
|
| 46 | - analogWrite(ENA, 0); |
|
| 47 | - analogWrite(ENB, 0); |
|
| 48 | - |
|
| 49 | - Serial.begin(9600); |
|
| 50 | -} |
|
| 51 | - |
|
| 52 | -// Helper function to control a single motor |
|
| 53 | -// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 54 | -void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 55 | - if (pwmVal > 0) { // Forward |
|
| 56 | - digitalWrite(dirPin, HIGH); |
|
| 57 | - analogWrite(speedPin, pwmVal); |
|
| 58 | - } else if (pwmVal < 0) { // Backward |
|
| 59 | - digitalWrite(dirPin, LOW); |
|
| 60 | - analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 61 | - } else { // Stop |
|
| 62 | - digitalWrite(dirPin, LOW); // Or HIGH, doesn't matter much if speed is 0 |
|
| 63 | - analogWrite(speedPin, 0); |
|
| 64 | - } |
|
| 65 | -} |
|
| 66 | - |
|
| 67 | -// Helper function to map RC control input (0-100) to an output range (e.g., -255 to 255) |
|
| 68 | -// with a deadband around the center (e.g., 50). |
|
| 69 | -long mapWithDeadband(long rcValue, int rcMin, int rcMax, int rcCenter, int deadbandRadius, int outMin, int outMax) { |
|
| 70 | - long mappedValue = 0; |
|
| 71 | - int deadbandLower = rcCenter - deadbandRadius; |
|
| 72 | - int deadbandUpper = rcCenter + deadbandRadius; |
|
| 73 | - |
|
| 74 | - if (rcValue < deadbandLower) { |
|
| 75 | - // Map the range [rcMin, deadbandLower - 1] to [outMin, -1] |
|
| 76 | - // Ensure deadbandLower - 1 is not less than rcMin |
|
| 77 | - if (deadbandLower -1 < rcMin) { |
|
| 78 | - mappedValue = outMin; |
|
| 79 | - } else { |
|
| 80 | - mappedValue = map(rcValue, rcMin, deadbandLower - 1, outMin, -1); |
|
| 81 | - } |
|
| 82 | - } else if (rcValue > deadbandUpper) { |
|
| 83 | - // Map the range [deadbandUpper + 1, rcMax] to [1, outMax] |
|
| 84 | - // Ensure deadbandUpper + 1 is not greater than rcMax |
|
| 85 | - if (deadbandUpper + 1 > rcMax) { |
|
| 86 | - mappedValue = outMax; |
|
| 87 | - } else { |
|
| 88 | - mappedValue = map(rcValue, deadbandUpper + 1, rcMax, 1, outMax); |
|
| 89 | - } |
|
| 90 | - } else { |
|
| 91 | - // Inside deadband |
|
| 92 | - mappedValue = 0; |
|
| 93 | - } |
|
| 94 | - return constrain(mappedValue, outMin, outMax); |
|
| 95 | -} |
|
| 96 | - |
|
| 97 | -void loop() { |
|
| 98 | - // Read mapped control signals from each channel |
|
| 99 | - aileronControl = readAileronControlSignal(); // Throttle (0-100) |
|
| 100 | - elevatorControl = readElevatorControlSignal(); // Steering (0-100) |
|
| 101 | - |
|
| 102 | - // Print the mapped control signal values to the Serial Monitor |
|
| 103 | - Serial.print("Aileron (Throttle): "); |
|
| 104 | - Serial.print(aileronControl); |
|
| 105 | - Serial.print(" Elevator (Steering): "); |
|
| 106 | - Serial.print(elevatorControl); |
|
| 107 | - Serial.println(); |
|
| 108 | - |
|
| 109 | - // Define deadband radius (e.g., +/- 5 around center of 50 for a 0-100 input) |
|
| 110 | - // This means input values from 45 to 55 (inclusive if center is 50 and radius is 5) will be treated as 0. |
|
| 111 | - int deadbandRadius = 5; |
|
| 112 | - float steeringFactor = 1.5; // Adjust this value to change steering sensitivity |
|
| 113 | - float throttleFactor = 1.3; // Adjust this value to change throttle sensitivity (e.g., 1.2 for 20% stronger throttle) |
|
| 114 | - |
|
| 115 | - // Map control values with deadband |
|
| 116 | - long rawThrottleValue = mapWithDeadband(aileronControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 117 | - long rawSteeringValue = mapWithDeadband(elevatorControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 118 | - |
|
| 119 | - // Apply sensitivity factors |
|
| 120 | - long throttleValue = rawThrottleValue * throttleFactor; |
|
| 121 | - long adjustedSteeringValue = rawSteeringValue * steeringFactor; |
|
| 122 | - |
|
| 123 | - // Mix throttle and steering for differential drive |
|
| 124 | - long motor1Pwm = throttleValue + adjustedSteeringValue; |
|
| 125 | - long motor2Pwm = throttleValue - adjustedSteeringValue; |
|
| 126 | - |
|
| 127 | - // Constrain PWM values to the valid range [-255, 255] |
|
| 128 | - motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 129 | - motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 130 | - |
|
| 131 | - // Set motor speeds and directions |
|
| 132 | - setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 133 | - setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 134 | - |
|
| 135 | - delay(20); // Shorter delay for better responsiveness |
|
| 136 | -} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-aircraft-dat/PWM-1ch.ino
| ... | ... | @@ -0,0 +1,74 @@ |
| 1 | +// Define pins for each RC channel |
|
| 2 | +int aileronPin = 2; // Channel 1 |
|
| 3 | + |
|
| 4 | +const int ENA = 5; // PWM for speed for Motor 1 |
|
| 5 | +const int ENB = 4; // PWM for speed for Motor 2 |
|
| 6 | + |
|
| 7 | +const int IN1 = 0; // Direction for Motor 1 (IN2_Motor1 is inverted in hardware) |
|
| 8 | +const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 9 | + |
|
| 10 | +long aileronControl; |
|
| 11 | + |
|
| 12 | +long readAileronControlSignal() { |
|
| 13 | + unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 14 | + if (rawPWM == 0) { // Timeout or no signal |
|
| 15 | + return 50; // Mid-point for 0-100 scale (1500us equivalent) |
|
| 16 | + } |
|
| 17 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 18 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 19 | +} |
|
| 20 | + |
|
| 21 | +void setup() { |
|
| 22 | + pinMode(aileronPin, INPUT); |
|
| 23 | + |
|
| 24 | + pinMode(ENA, OUTPUT); |
|
| 25 | + pinMode(ENB, OUTPUT); |
|
| 26 | + pinMode(IN1, OUTPUT); |
|
| 27 | + pinMode(IN2, OUTPUT); |
|
| 28 | + |
|
| 29 | + // Initialize motors to off |
|
| 30 | + digitalWrite(IN1, LOW); |
|
| 31 | + digitalWrite(IN2, LOW); |
|
| 32 | + analogWrite(ENA, 0); |
|
| 33 | + analogWrite(ENB, 0); |
|
| 34 | + |
|
| 35 | + Serial.begin(9600); |
|
| 36 | +} |
|
| 37 | + |
|
| 38 | +void loop() { |
|
| 39 | + // Read mapped control signals from each channel |
|
| 40 | + aileronControl = readAileronControlSignal(); |
|
| 41 | + |
|
| 42 | + // Print the mapped control signal values to the Serial Monitor |
|
| 43 | + Serial.print("Aileron: "); |
|
| 44 | + Serial.print(aileronControl); |
|
| 45 | + Serial.println(); // Newline for better readability |
|
| 46 | + |
|
| 47 | + if (aileronControl > 70) { |
|
| 48 | + // Forward |
|
| 49 | + digitalWrite(IN1, HIGH); // Motor 1 forward |
|
| 50 | + digitalWrite(IN2, HIGH); // Motor 2 forward |
|
| 51 | + |
|
| 52 | + // Map aileronControl (61-100) to PWM speed (e.g., 100-255) |
|
| 53 | + int motorSpeed = map(aileronControl, 61, 100, 100, 255); |
|
| 54 | + analogWrite(ENA, motorSpeed); |
|
| 55 | + analogWrite(ENB, motorSpeed); |
|
| 56 | + } else if (aileronControl < 30) { |
|
| 57 | + // Backward |
|
| 58 | + digitalWrite(IN1, LOW); // Motor 1 backward |
|
| 59 | + digitalWrite(IN2, LOW); // Motor 2 backward |
|
| 60 | + |
|
| 61 | + // Map aileronControl (0-39) to PWM speed (e.g., 255-100, reversing the range for backward) |
|
| 62 | + int motorSpeed = map(aileronControl, 0, 39, 255, 100); |
|
| 63 | + analogWrite(ENA, motorSpeed); |
|
| 64 | + analogWrite(ENB, motorSpeed); |
|
| 65 | + } else { |
|
| 66 | + // Stop motors (aileronControl is between 40 and 60 inclusive) |
|
| 67 | + digitalWrite(IN1, LOW); |
|
| 68 | + digitalWrite(IN2, LOW); |
|
| 69 | + analogWrite(ENA, 0); |
|
| 70 | + analogWrite(ENB, 0); |
|
| 71 | + } |
|
| 72 | + |
|
| 73 | + delay(100); // Limit output rate |
|
| 74 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-aircraft-dat/PWM-2ch-2.ino
| ... | ... | @@ -0,0 +1,142 @@ |
| 1 | +// Define pins for each RC channel |
|
| 2 | +int aileronPin = 14; // Channel 1 (Throttle) |
|
| 3 | +int elevatorPin = 12; // Channel 2 (Steering) |
|
| 4 | + |
|
| 5 | +const int ENA = 5; // PWM for speed for Motor 1 |
|
| 6 | +const int ENB = 4; // PWM for speed for Motor 2 |
|
| 7 | + |
|
| 8 | +const int IN1 = 0; // Direction for Motor 1 |
|
| 9 | +const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 10 | + |
|
| 11 | +long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 12 | +long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 13 | + |
|
| 14 | +// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 15 | +long readAileronControlSignal() { |
|
| 16 | + unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 17 | + // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 18 | + // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 19 | + if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 20 | + return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 21 | + } |
|
| 22 | + // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 23 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 24 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 25 | +} |
|
| 26 | + |
|
| 27 | +// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 28 | +long readElevatorControlSignal() { |
|
| 29 | + unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 30 | + // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 31 | + // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 32 | + if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 33 | + return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 34 | + } |
|
| 35 | + // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 36 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 37 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 38 | +} |
|
| 39 | + |
|
| 40 | +void setup() { |
|
| 41 | + pinMode(aileronPin, INPUT); |
|
| 42 | + pinMode(elevatorPin, INPUT); // Initialize elevator pin |
|
| 43 | + |
|
| 44 | + pinMode(ENA, OUTPUT); |
|
| 45 | + pinMode(ENB, OUTPUT); |
|
| 46 | + pinMode(IN1, OUTPUT); |
|
| 47 | + pinMode(IN2, OUTPUT); |
|
| 48 | + |
|
| 49 | + // Initialize motors to off |
|
| 50 | + digitalWrite(IN1, LOW); |
|
| 51 | + digitalWrite(IN2, LOW); |
|
| 52 | + analogWrite(ENA, 0); |
|
| 53 | + analogWrite(ENB, 0); |
|
| 54 | + |
|
| 55 | + Serial.begin(9600); |
|
| 56 | +} |
|
| 57 | + |
|
| 58 | +// Helper function to control a single motor |
|
| 59 | +// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 60 | +void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 61 | + if (pwmVal > 0) { // Forward |
|
| 62 | + digitalWrite(dirPin, HIGH); |
|
| 63 | + analogWrite(speedPin, pwmVal); |
|
| 64 | + } else if (pwmVal < 0) { // Backward |
|
| 65 | + digitalWrite(dirPin, LOW); |
|
| 66 | + analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 67 | + } else { // Stop |
|
| 68 | + digitalWrite(dirPin, LOW); // Or HIGH, doesn't matter much if speed is 0 |
|
| 69 | + analogWrite(speedPin, 0); |
|
| 70 | + } |
|
| 71 | +} |
|
| 72 | + |
|
| 73 | +// Helper function to map RC control input (0-100) to an output range (e.g., -255 to 255) |
|
| 74 | +// with a deadband around the center (e.g., 50). |
|
| 75 | +long mapWithDeadband(long rcValue, int rcMin, int rcMax, int rcCenter, int deadbandRadius, int outMin, int outMax) { |
|
| 76 | + long mappedValue = 0; |
|
| 77 | + int deadbandLower = rcCenter - deadbandRadius; |
|
| 78 | + int deadbandUpper = rcCenter + deadbandRadius; |
|
| 79 | + |
|
| 80 | + if (rcValue < deadbandLower) { |
|
| 81 | + // Map the range [rcMin, deadbandLower - 1] to [outMin, -1] |
|
| 82 | + // Ensure deadbandLower - 1 is not less than rcMin |
|
| 83 | + if (deadbandLower -1 < rcMin) { |
|
| 84 | + mappedValue = outMin; |
|
| 85 | + } else { |
|
| 86 | + mappedValue = map(rcValue, rcMin, deadbandLower - 1, outMin, -1); |
|
| 87 | + } |
|
| 88 | + } else if (rcValue > deadbandUpper) { |
|
| 89 | + // Map the range [deadbandUpper + 1, rcMax] to [1, outMax] |
|
| 90 | + // Ensure deadbandUpper + 1 is not greater than rcMax |
|
| 91 | + if (deadbandUpper + 1 > rcMax) { |
|
| 92 | + mappedValue = outMax; |
|
| 93 | + } else { |
|
| 94 | + mappedValue = map(rcValue, deadbandUpper + 1, rcMax, 1, outMax); |
|
| 95 | + } |
|
| 96 | + } else { |
|
| 97 | + // Inside deadband |
|
| 98 | + mappedValue = 0; |
|
| 99 | + } |
|
| 100 | + return constrain(mappedValue, outMin, outMax); |
|
| 101 | +} |
|
| 102 | + |
|
| 103 | +void loop() { |
|
| 104 | + // Read mapped control signals from each channel |
|
| 105 | + aileronControl = readAileronControlSignal(); // Throttle (0-100) |
|
| 106 | + elevatorControl = readElevatorControlSignal(); // Steering (0-100) |
|
| 107 | + |
|
| 108 | + // Print the mapped control signal values to the Serial Monitor |
|
| 109 | + Serial.print("Aileron (Throttle): "); |
|
| 110 | + Serial.print(aileronControl); |
|
| 111 | + Serial.print(" Elevator (Steering): "); |
|
| 112 | + Serial.print(elevatorControl); |
|
| 113 | + Serial.println(); |
|
| 114 | + |
|
| 115 | + // Define deadband radius (e.g., +/- 5 around center of 50 for a 0-100 input) |
|
| 116 | + // This means input values from 45 to 55 (inclusive if center is 50 and radius is 5) will be treated as 0. |
|
| 117 | + int deadbandRadius = 10; |
|
| 118 | + float steeringFactor = 3; // Adjust this value to change steering sensitivity |
|
| 119 | + float throttleFactor = 3; // Adjust this value to change throttle sensitivity (e.g., 1.2 for 20% stronger throttle) |
|
| 120 | + |
|
| 121 | + // Map control values with deadband |
|
| 122 | + long rawThrottleValue = mapWithDeadband(aileronControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 123 | + long rawSteeringValue = mapWithDeadband(elevatorControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 124 | + |
|
| 125 | + // Apply sensitivity factors |
|
| 126 | + long throttleValue = rawThrottleValue * throttleFactor; |
|
| 127 | + long adjustedSteeringValue = rawSteeringValue * steeringFactor; |
|
| 128 | + |
|
| 129 | + // Mix throttle and steering for differential drive |
|
| 130 | + long motor1Pwm = throttleValue + adjustedSteeringValue; |
|
| 131 | + long motor2Pwm = throttleValue - adjustedSteeringValue; |
|
| 132 | + |
|
| 133 | + // Constrain PWM values to the valid range [-255, 255] |
|
| 134 | + motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 135 | + motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 136 | + |
|
| 137 | + // Set motor speeds and directions |
|
| 138 | + setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 139 | + setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 140 | + |
|
| 141 | + delay(20); // Shorter delay for better responsiveness |
|
| 142 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-aircraft-dat/PWM-2ch-v2.ino
| ... | ... | @@ -0,0 +1,68 @@ |
| 1 | +// RC signal input pins |
|
| 2 | +#define THROTTLE_PIN 2 // Channel 1 (forward/back) |
|
| 3 | +#define STEERING_PIN 3 // Channel 2 (left/right) |
|
| 4 | + |
|
| 5 | +// Motor control pins (L298N) |
|
| 6 | +#define LEFT_ENA 9 |
|
| 7 | +#define LEFT_IN1 4 |
|
| 8 | +#define LEFT_IN2 5 |
|
| 9 | + |
|
| 10 | +#define RIGHT_ENB 10 |
|
| 11 | +#define RIGHT_IN3 6 |
|
| 12 | +#define RIGHT_IN4 7 |
|
| 13 | + |
|
| 14 | +int throttle, steering; |
|
| 15 | + |
|
| 16 | +void setup() { |
|
| 17 | + pinMode(THROTTLE_PIN, INPUT); |
|
| 18 | + pinMode(STEERING_PIN, INPUT); |
|
| 19 | + |
|
| 20 | + pinMode(LEFT_IN1, OUTPUT); |
|
| 21 | + pinMode(LEFT_IN2, OUTPUT); |
|
| 22 | + pinMode(LEFT_ENA, OUTPUT); |
|
| 23 | + |
|
| 24 | + pinMode(RIGHT_IN3, OUTPUT); |
|
| 25 | + pinMode(RIGHT_IN4, OUTPUT); |
|
| 26 | + pinMode(RIGHT_ENB, OUTPUT); |
|
| 27 | + |
|
| 28 | + Serial.begin(9600); |
|
| 29 | +} |
|
| 30 | + |
|
| 31 | +void loop() { |
|
| 32 | + // Read PWM input |
|
| 33 | + throttle = pulseIn(THROTTLE_PIN, HIGH, 25000); |
|
| 34 | + steering = pulseIn(STEERING_PIN, HIGH, 25000); |
|
| 35 | + |
|
| 36 | + // Center = 1500, range = 1000–2000 |
|
| 37 | + int throttleVal = map(throttle, 1000, 2000, -255, 255); |
|
| 38 | + int steeringVal = map(steering, 1000, 2000, -100, 100); // less aggressive |
|
| 39 | + |
|
| 40 | + // Motor mixing (differential drive) |
|
| 41 | + int leftSpeed = constrain(throttleVal + steeringVal, -255, 255); |
|
| 42 | + int rightSpeed = constrain(throttleVal - steeringVal, -255, 255); |
|
| 43 | + |
|
| 44 | + setMotor(LEFT_IN1, LEFT_IN2, LEFT_ENA, leftSpeed); |
|
| 45 | + setMotor(RIGHT_IN3, RIGHT_IN4, RIGHT_ENB, rightSpeed); |
|
| 46 | + |
|
| 47 | + // Debug |
|
| 48 | + Serial.print("Throttle: "); Serial.print(throttleVal); |
|
| 49 | + Serial.print(" Steering: "); Serial.print(steeringVal); |
|
| 50 | + Serial.print(" L: "); Serial.print(leftSpeed); |
|
| 51 | + Serial.print(" R: "); Serial.println(rightSpeed); |
|
| 52 | + |
|
| 53 | + delay(20); |
|
| 54 | +} |
|
| 55 | + |
|
| 56 | +void setMotor(int in1, int in2, int ena, int speed) { |
|
| 57 | + if (speed > 0) { |
|
| 58 | + digitalWrite(in1, HIGH); |
|
| 59 | + digitalWrite(in2, LOW); |
|
| 60 | + } else if (speed < 0) { |
|
| 61 | + digitalWrite(in1, LOW); |
|
| 62 | + digitalWrite(in2, HIGH); |
|
| 63 | + } else { |
|
| 64 | + digitalWrite(in1, LOW); |
|
| 65 | + digitalWrite(in2, LOW); |
|
| 66 | + } |
|
| 67 | + analogWrite(ena, abs(speed)); |
|
| 68 | +} |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-aircraft-dat/SDR1064-1.ino
| ... | ... | @@ -0,0 +1,94 @@ |
| 1 | +// Define pins for each RC channel |
|
| 2 | +int aileronPin = 14; // Channel 1 (Throttle) |
|
| 3 | +int elevatorPin = 12; // Channel 2 (Steering) |
|
| 4 | + |
|
| 5 | +const int ENA = 5; // PWM for speed for Motor 1 |
|
| 6 | +const int ENB = 4; // PWM for speed for Motor 2 |
|
| 7 | + |
|
| 8 | +const int IN1 = 0; // Direction for Motor 1 |
|
| 9 | +const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 10 | + |
|
| 11 | +long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 12 | +long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 13 | + |
|
| 14 | +// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 15 | +long readAileronControlSignal() { |
|
| 16 | + unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 17 | + // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 18 | + if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 19 | + return 50; // Mid-point for 0-100 scale |
|
| 20 | + } |
|
| 21 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 22 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 23 | +} |
|
| 24 | + |
|
| 25 | +// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 26 | +long readElevatorControlSignal() { |
|
| 27 | + unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 28 | + // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 29 | + if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 30 | + return 50; // Mid-point for 0-100 scale |
|
| 31 | + } |
|
| 32 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 33 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 34 | +} |
|
| 35 | + |
|
| 36 | +void setup() { |
|
| 37 | + pinMode(aileronPin, INPUT); |
|
| 38 | + pinMode(elevatorPin, INPUT); |
|
| 39 | + |
|
| 40 | + pinMode(ENA, OUTPUT); |
|
| 41 | + pinMode(ENB, OUTPUT); |
|
| 42 | + pinMode(IN1, OUTPUT); |
|
| 43 | + pinMode(IN2, OUTPUT); |
|
| 44 | + |
|
| 45 | + // Initialize motors to off |
|
| 46 | + digitalWrite(IN1, LOW); |
|
| 47 | + digitalWrite(IN2, LOW); |
|
| 48 | + analogWrite(ENA, 0); |
|
| 49 | + analogWrite(ENB, 0); |
|
| 50 | +} |
|
| 51 | + |
|
| 52 | +// Helper function to control a single motor |
|
| 53 | +// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 54 | +void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 55 | + if (pwmVal > 0) { // Forward |
|
| 56 | + digitalWrite(dirPin, HIGH); |
|
| 57 | + analogWrite(speedPin, pwmVal); |
|
| 58 | + } else if (pwmVal < 0) { // Backward |
|
| 59 | + digitalWrite(dirPin, LOW); |
|
| 60 | + analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 61 | + } else { // Stop |
|
| 62 | + digitalWrite(dirPin, LOW); |
|
| 63 | + analogWrite(speedPin, 0); |
|
| 64 | + } |
|
| 65 | +} |
|
| 66 | + |
|
| 67 | +void loop() { |
|
| 68 | + // Read mapped control signals from each channel |
|
| 69 | + aileronControl = readAileronControlSignal(); // Throttle (0-100, 50 is neutral) |
|
| 70 | + elevatorControl = readElevatorControlSignal(); // Steering (0-100, 50 is neutral) |
|
| 71 | + |
|
| 72 | + // Map control values directly |
|
| 73 | + // aileronControl (0-100) to throttleValue (-255 to 255) |
|
| 74 | + // 0 -> -255 (full reverse), 50 -> 0 (stop), 100 -> 255 (full forward) |
|
| 75 | + long throttleValue = map(aileronControl, 0, 100, -255, 255); |
|
| 76 | + |
|
| 77 | + // elevatorControl (0-100) to steeringValue (-255 to 255) |
|
| 78 | + // 0 -> -255 (full left turn effect), 50 -> 0 (straight), 100 -> 255 (full right turn effect) |
|
| 79 | + long steeringValue = map(elevatorControl, 0, 100, -255, 255); |
|
| 80 | + |
|
| 81 | + // Mix throttle and steering for differential drive |
|
| 82 | + long motor1Pwm = throttleValue + steeringValue; |
|
| 83 | + long motor2Pwm = throttleValue - steeringValue; |
|
| 84 | + |
|
| 85 | + // Constrain PWM values to the valid range [-255, 255] |
|
| 86 | + motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 87 | + motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 88 | + |
|
| 89 | + // Set motor speeds and directions |
|
| 90 | + setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 91 | + setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 92 | + |
|
| 93 | + delay(20); // Delay for responsiveness |
|
| 94 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-aircraft-dat/SDR1064-2.ino
| ... | ... | @@ -0,0 +1,167 @@ |
| 1 | +#include <Adafruit_NeoPixel.h> |
|
| 2 | + |
|
| 3 | +// Define pins for each RC channel |
|
| 4 | +int aileronPin = 14; // Channel 1 (Throttle) // D5 |
|
| 5 | +int elevatorPin = 12; // Channel 2 (Steering) // D6 |
|
| 6 | + |
|
| 7 | +const int IN1 = 0; // Direction for Motor 1 // D3 |
|
| 8 | +const int IN2 = 2; // Direction pin 1 for Motor 2 // D4 |
|
| 9 | + |
|
| 10 | +// WS2812 LED Strip Configuration |
|
| 11 | +#define LED_PIN 15 // nodemcu pin D8 |
|
| 12 | +#define LED_COUNT 8 |
|
| 13 | +Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); |
|
| 14 | + |
|
| 15 | +long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 16 | +long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 17 | + |
|
| 18 | +// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 19 | +long readAileronControlSignal() { |
|
| 20 | + unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 21 | + // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 22 | + // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 23 | + if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 24 | + return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 25 | + } |
|
| 26 | + // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 27 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 28 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 29 | +} |
|
| 30 | + |
|
| 31 | +// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 32 | +long readElevatorControlSignal() { |
|
| 33 | + unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 34 | + // If signal is lost (timeout) or clearly out of valid RC pulse range, return neutral (50) |
|
| 35 | + // Valid RC pulses are typically 1000-2000us. Values outside ~900-2100us are treated as invalid. |
|
| 36 | + if (rawPWM == 0 || rawPWM < 900 || rawPWM > 2100) { |
|
| 37 | + return 50; // Mid-point for 0-100 scale (1500us equivalent), results in stop |
|
| 38 | + } |
|
| 39 | + // Otherwise, the signal is likely valid; constrain it to the standard 1000-2000us range and map |
|
| 40 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 41 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 42 | +} |
|
| 43 | + |
|
| 44 | +void setup() { |
|
| 45 | + pinMode(aileronPin, INPUT); |
|
| 46 | + pinMode(elevatorPin, INPUT); // Initialize elevator pin |
|
| 47 | + |
|
| 48 | + pinMode(ENA, OUTPUT); |
|
| 49 | + pinMode(ENB, OUTPUT); |
|
| 50 | + pinMode(IN1, OUTPUT); |
|
| 51 | + pinMode(IN2, OUTPUT); |
|
| 52 | + |
|
| 53 | + // Initialize motors to off |
|
| 54 | + digitalWrite(IN1, LOW); |
|
| 55 | + digitalWrite(IN2, LOW); |
|
| 56 | + analogWrite(ENA, 0); |
|
| 57 | + analogWrite(ENB, 0); |
|
| 58 | + |
|
| 59 | + Serial.begin(9600); |
|
| 60 | + |
|
| 61 | + strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) |
|
| 62 | + strip.show(); // Turn OFF all pixels ASAP |
|
| 63 | + strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255) |
|
| 64 | +} |
|
| 65 | + |
|
| 66 | +// Helper function to control a single motor |
|
| 67 | +// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 68 | +void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 69 | + if (pwmVal > 0) { // Forward |
|
| 70 | + digitalWrite(dirPin, HIGH); |
|
| 71 | + analogWrite(speedPin, pwmVal); |
|
| 72 | + } else if (pwmVal < 0) { // Backward |
|
| 73 | + digitalWrite(dirPin, LOW); |
|
| 74 | + analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 75 | + } else { // Stop |
|
| 76 | + digitalWrite(dirPin, LOW); // Or HIGH, doesn't matter much if speed is 0 |
|
| 77 | + analogWrite(speedPin, 0); |
|
| 78 | + } |
|
| 79 | +} |
|
| 80 | + |
|
| 81 | +// Helper function to map RC control input (0-100) to an output range (e.g., -255 to 255) |
|
| 82 | +// with a deadband around the center (e.g., 50). |
|
| 83 | +long mapWithDeadband(long rcValue, int rcMin, int rcMax, int rcCenter, int deadbandRadius, int outMin, int outMax) { |
|
| 84 | + long mappedValue = 0; |
|
| 85 | + int deadbandLower = rcCenter - deadbandRadius; |
|
| 86 | + int deadbandUpper = rcCenter + deadbandRadius; |
|
| 87 | + |
|
| 88 | + if (rcValue < deadbandLower) { |
|
| 89 | + // Map the range [rcMin, deadbandLower - 1] to [outMin, -1] |
|
| 90 | + // Ensure deadbandLower - 1 is not less than rcMin |
|
| 91 | + if (deadbandLower -1 < rcMin) { |
|
| 92 | + mappedValue = outMin; |
|
| 93 | + } else { |
|
| 94 | + mappedValue = map(rcValue, rcMin, deadbandLower - 1, outMin, -1); |
|
| 95 | + } |
|
| 96 | + } else if (rcValue > deadbandUpper) { |
|
| 97 | + // Map the range [deadbandUpper + 1, rcMax] to [1, outMax] |
|
| 98 | + // Ensure deadbandUpper + 1 is not greater than rcMax |
|
| 99 | + if (deadbandUpper + 1 > rcMax) { |
|
| 100 | + mappedValue = outMax; |
|
| 101 | + } else { |
|
| 102 | + mappedValue = map(rcValue, deadbandUpper + 1, rcMax, 1, outMax); |
|
| 103 | + } |
|
| 104 | + } else { |
|
| 105 | + // Inside deadband |
|
| 106 | + mappedValue = 0; |
|
| 107 | + } |
|
| 108 | + return constrain(mappedValue, outMin, outMax); |
|
| 109 | +} |
|
| 110 | + |
|
| 111 | +// Function to create a random blinking effect for WS2812 LEDs |
|
| 112 | +void randomBlinkEffect() { |
|
| 113 | + for (int i = 0; i < LED_COUNT; i++) { |
|
| 114 | + // Turn on a random LED with a random color |
|
| 115 | + if (random(0, 2) == 1) { // 50% chance to turn on this LED |
|
| 116 | + strip.setPixelColor(i, strip.Color(random(0, 256), random(0, 256), random(0, 256))); |
|
| 117 | + } else { |
|
| 118 | + strip.setPixelColor(i, strip.Color(0, 0, 0)); // Turn off |
|
| 119 | + } |
|
| 120 | + } |
|
| 121 | + strip.show(); // Send the updated pixel colors to the hardware. |
|
| 122 | + delay(100); // Wait a short period |
|
| 123 | +} |
|
| 124 | + |
|
| 125 | +void loop() { |
|
| 126 | + // Read mapped control signals from each channel |
|
| 127 | + aileronControl = readAileronControlSignal(); // Throttle (0-100) |
|
| 128 | + elevatorControl = readElevatorControlSignal(); // Steering (0-100) |
|
| 129 | + |
|
| 130 | + // Print the mapped control signal values to the Serial Monitor |
|
| 131 | + Serial.print("Aileron (Throttle): "); |
|
| 132 | + Serial.print(aileronControl); |
|
| 133 | + Serial.print(" Elevator (Steering): "); |
|
| 134 | + Serial.print(elevatorControl); |
|
| 135 | + Serial.println(); |
|
| 136 | + |
|
| 137 | + // Define deadband radius (e.g., +/- 5 around center of 50 for a 0-100 input) |
|
| 138 | + // This means input values from 45 to 55 (inclusive if center is 50 and radius is 5) will be treated as 0. |
|
| 139 | + int deadbandRadius = 15; |
|
| 140 | + float steeringFactor = 3; // Adjust this value to change steering sensitivity |
|
| 141 | + float throttleFactor = 3; // Adjust this value to change throttle sensitivity (e.g., 1.2 for 20% stronger throttle) |
|
| 142 | + |
|
| 143 | + // Map control values with deadband |
|
| 144 | + long rawThrottleValue = mapWithDeadband(aileronControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 145 | + long rawSteeringValue = mapWithDeadband(elevatorControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 146 | + |
|
| 147 | + // Apply sensitivity factors |
|
| 148 | + long throttleValue = rawThrottleValue * throttleFactor; |
|
| 149 | + long adjustedSteeringValue = rawSteeringValue * steeringFactor; |
|
| 150 | + |
|
| 151 | + // Mix throttle and steering for differential drive |
|
| 152 | + long motor1Pwm = throttleValue + adjustedSteeringValue; |
|
| 153 | + long motor2Pwm = throttleValue - adjustedSteeringValue; |
|
| 154 | + |
|
| 155 | + // Constrain PWM values to the valid range [-255, 255] |
|
| 156 | + motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 157 | + motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 158 | + |
|
| 159 | + // Set motor speeds and directions |
|
| 160 | + setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 161 | + setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 162 | + |
|
| 163 | + // Add the LED effect |
|
| 164 | + randomBlinkEffect(); |
|
| 165 | + |
|
| 166 | + delay(20); // Shorter delay for better responsiveness |
|
| 167 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-aircraft-dat/SDR1064-3.ino
| ... | ... | @@ -0,0 +1,136 @@ |
| 1 | +// Define pins for each RC channel |
|
| 2 | +int aileronPin = 14; // Channel 1 (Throttle) |
|
| 3 | +int elevatorPin = 12; // Channel 2 (Steering) |
|
| 4 | + |
|
| 5 | +const int ENA = 5; // PWM for speed for Motor 1 |
|
| 6 | +const int ENB = 4; // PWM for speed for Motor 2 |
|
| 7 | + |
|
| 8 | +const int IN1 = 0; // Direction for Motor 1 |
|
| 9 | +const int IN2 = 2; // Direction pin 1 for Motor 2 |
|
| 10 | + |
|
| 11 | +long aileronControl; // Mapped value from aileron channel (0-100) |
|
| 12 | +long elevatorControl; // Mapped value from elevator channel (0-100) |
|
| 13 | + |
|
| 14 | +// Reads the PWM signal from the aileron channel and maps it to 0-100 |
|
| 15 | +long readAileronControlSignal() { |
|
| 16 | + unsigned long rawPWM = pulseIn(aileronPin, HIGH, 25000); |
|
| 17 | + if (rawPWM == 0) { // Timeout or no signal |
|
| 18 | + return 50; // Mid-point for 0-100 scale (1500us equivalent) |
|
| 19 | + } |
|
| 20 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 21 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 22 | +} |
|
| 23 | + |
|
| 24 | +// Reads the PWM signal from the elevator channel and maps it to 0-100 |
|
| 25 | +long readElevatorControlSignal() { |
|
| 26 | + unsigned long rawPWM = pulseIn(elevatorPin, HIGH, 25000); |
|
| 27 | + if (rawPWM == 0) { // Timeout or no signal |
|
| 28 | + return 50; // Mid-point for 0-100 scale (1500us equivalent) |
|
| 29 | + } |
|
| 30 | + long constrainedPWM = constrain(rawPWM, 1000, 2000); |
|
| 31 | + return map(constrainedPWM, 1000, 2000, 0, 100); |
|
| 32 | +} |
|
| 33 | + |
|
| 34 | +void setup() { |
|
| 35 | + pinMode(aileronPin, INPUT); |
|
| 36 | + pinMode(elevatorPin, INPUT); // Initialize elevator pin |
|
| 37 | + |
|
| 38 | + pinMode(ENA, OUTPUT); |
|
| 39 | + pinMode(ENB, OUTPUT); |
|
| 40 | + pinMode(IN1, OUTPUT); |
|
| 41 | + pinMode(IN2, OUTPUT); |
|
| 42 | + |
|
| 43 | + // Initialize motors to off |
|
| 44 | + digitalWrite(IN1, LOW); |
|
| 45 | + digitalWrite(IN2, LOW); |
|
| 46 | + analogWrite(ENA, 0); |
|
| 47 | + analogWrite(ENB, 0); |
|
| 48 | + |
|
| 49 | + Serial.begin(9600); |
|
| 50 | +} |
|
| 51 | + |
|
| 52 | +// Helper function to control a single motor |
|
| 53 | +// pwmVal: -255 (full backward) to 255 (full forward) |
|
| 54 | +void setMotorOutput(int dirPin, int speedPin, int pwmVal) { |
|
| 55 | + if (pwmVal > 0) { // Forward |
|
| 56 | + digitalWrite(dirPin, HIGH); |
|
| 57 | + analogWrite(speedPin, pwmVal); |
|
| 58 | + } else if (pwmVal < 0) { // Backward |
|
| 59 | + digitalWrite(dirPin, LOW); |
|
| 60 | + analogWrite(speedPin, -pwmVal); // Speed is positive |
|
| 61 | + } else { // Stop |
|
| 62 | + digitalWrite(dirPin, LOW); // Or HIGH, doesn't matter much if speed is 0 |
|
| 63 | + analogWrite(speedPin, 0); |
|
| 64 | + } |
|
| 65 | +} |
|
| 66 | + |
|
| 67 | +// Helper function to map RC control input (0-100) to an output range (e.g., -255 to 255) |
|
| 68 | +// with a deadband around the center (e.g., 50). |
|
| 69 | +long mapWithDeadband(long rcValue, int rcMin, int rcMax, int rcCenter, int deadbandRadius, int outMin, int outMax) { |
|
| 70 | + long mappedValue = 0; |
|
| 71 | + int deadbandLower = rcCenter - deadbandRadius; |
|
| 72 | + int deadbandUpper = rcCenter + deadbandRadius; |
|
| 73 | + |
|
| 74 | + if (rcValue < deadbandLower) { |
|
| 75 | + // Map the range [rcMin, deadbandLower - 1] to [outMin, -1] |
|
| 76 | + // Ensure deadbandLower - 1 is not less than rcMin |
|
| 77 | + if (deadbandLower -1 < rcMin) { |
|
| 78 | + mappedValue = outMin; |
|
| 79 | + } else { |
|
| 80 | + mappedValue = map(rcValue, rcMin, deadbandLower - 1, outMin, -1); |
|
| 81 | + } |
|
| 82 | + } else if (rcValue > deadbandUpper) { |
|
| 83 | + // Map the range [deadbandUpper + 1, rcMax] to [1, outMax] |
|
| 84 | + // Ensure deadbandUpper + 1 is not greater than rcMax |
|
| 85 | + if (deadbandUpper + 1 > rcMax) { |
|
| 86 | + mappedValue = outMax; |
|
| 87 | + } else { |
|
| 88 | + mappedValue = map(rcValue, deadbandUpper + 1, rcMax, 1, outMax); |
|
| 89 | + } |
|
| 90 | + } else { |
|
| 91 | + // Inside deadband |
|
| 92 | + mappedValue = 0; |
|
| 93 | + } |
|
| 94 | + return constrain(mappedValue, outMin, outMax); |
|
| 95 | +} |
|
| 96 | + |
|
| 97 | +void loop() { |
|
| 98 | + // Read mapped control signals from each channel |
|
| 99 | + aileronControl = readAileronControlSignal(); // Throttle (0-100) |
|
| 100 | + elevatorControl = readElevatorControlSignal(); // Steering (0-100) |
|
| 101 | + |
|
| 102 | + // Print the mapped control signal values to the Serial Monitor |
|
| 103 | + Serial.print("Aileron (Throttle): "); |
|
| 104 | + Serial.print(aileronControl); |
|
| 105 | + Serial.print(" Elevator (Steering): "); |
|
| 106 | + Serial.print(elevatorControl); |
|
| 107 | + Serial.println(); |
|
| 108 | + |
|
| 109 | + // Define deadband radius (e.g., +/- 5 around center of 50 for a 0-100 input) |
|
| 110 | + // This means input values from 45 to 55 (inclusive if center is 50 and radius is 5) will be treated as 0. |
|
| 111 | + int deadbandRadius = 5; |
|
| 112 | + float steeringFactor = 1.5; // Adjust this value to change steering sensitivity |
|
| 113 | + float throttleFactor = 1.3; // Adjust this value to change throttle sensitivity (e.g., 1.2 for 20% stronger throttle) |
|
| 114 | + |
|
| 115 | + // Map control values with deadband |
|
| 116 | + long rawThrottleValue = mapWithDeadband(aileronControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 117 | + long rawSteeringValue = mapWithDeadband(elevatorControl, 0, 100, 50, deadbandRadius, -255, 255); |
|
| 118 | + |
|
| 119 | + // Apply sensitivity factors |
|
| 120 | + long throttleValue = rawThrottleValue * throttleFactor; |
|
| 121 | + long adjustedSteeringValue = rawSteeringValue * steeringFactor; |
|
| 122 | + |
|
| 123 | + // Mix throttle and steering for differential drive |
|
| 124 | + long motor1Pwm = throttleValue + adjustedSteeringValue; |
|
| 125 | + long motor2Pwm = throttleValue - adjustedSteeringValue; |
|
| 126 | + |
|
| 127 | + // Constrain PWM values to the valid range [-255, 255] |
|
| 128 | + motor1Pwm = constrain(motor1Pwm, -255, 255); |
|
| 129 | + motor2Pwm = constrain(motor2Pwm, -255, 255); |
|
| 130 | + |
|
| 131 | + // Set motor speeds and directions |
|
| 132 | + setMotorOutput(IN1, ENA, motor1Pwm); // Motor 1 |
|
| 133 | + setMotorOutput(IN2, ENB, motor2Pwm); // Motor 2 |
|
| 134 | + |
|
| 135 | + delay(20); // Shorter delay for better responsiveness |
|
| 136 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-rover-code-dat/SDR1064-rover-code-dat.md
| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | + |
|
| 2 | +# SDR1064-rover-code-dat.md |
|
| 3 | + |
|
| 4 | +## working for |
|
| 5 | + |
|
| 6 | +- [[SDR1064-dat]] - [[nodemcu-dat]] |
|
| 7 | + |
|
| 8 | +- [[serial-motor-1.ino]] - [[motor-1-wifi-ap.ino]] |
|
| 9 | + |
|
| 10 | + |
|
| 11 | + |
|
| 12 | +## ref |
|
| 13 | + |
|
| 14 | +- [[rc-code-dat]] |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-rover-code-dat/motor-1-wifi-ap.ino
| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | +#include <ESP8266WiFi.h> |
|
| 2 | +#include <ESP8266WebServer.h> |
|
| 3 | + |
|
| 4 | +// WiFi AP settings (fixed IP) |
|
| 5 | +const char* ssid = "MotorAP"; |
|
| 6 | +const char* password = "motorpass"; // set to "" for open AP |
|
| 7 | +IPAddress apIP(192, 168, 4, 1); |
|
| 8 | +IPAddress netMsk(255, 255, 255, 0); |
|
| 9 | + |
|
| 10 | +// Define pins for motor control |
|
| 11 | +const int ENA = 5; // PWM for speed for Motor (single motor) |
|
| 12 | +const int IN1 = 0; // Direction pin A for Motor (GPIO0) - be careful at boot |
|
| 13 | +const int IN2 = 2; // Direction pin B for Motor (GPIO2) |
|
| 14 | + |
|
| 15 | +int motorControl = 50; // 0..100, default mid-point |
|
| 16 | + |
|
| 17 | +ESP8266WebServer server(80); |
|
| 18 | + |
|
| 19 | +void applyMotorControl() { |
|
| 20 | + // Deadband: treat 40..60 as stop |
|
| 21 | + if (motorControl > 60) { |
|
| 22 | + // Forward: IN1 = HIGH, IN2 = LOW |
|
| 23 | + digitalWrite(IN1, HIGH); |
|
| 24 | + digitalWrite(IN2, LOW); |
|
| 25 | + |
|
| 26 | + // Map motorControl (61-100) to PWM speed (0-255) |
|
| 27 | + int motorSpeed = map(motorControl, 61, 100, 0, 255); |
|
| 28 | + motorSpeed = constrain(motorSpeed, 0, 255); |
|
| 29 | + analogWrite(ENA, motorSpeed); |
|
| 30 | + } else if (motorControl < 40) { |
|
| 31 | + // Reverse: IN1 = LOW, IN2 = HIGH |
|
| 32 | + digitalWrite(IN1, LOW); |
|
| 33 | + digitalWrite(IN2, HIGH); |
|
| 34 | + |
|
| 35 | + // Map motorControl (0-39) to PWM speed (0-255) |
|
| 36 | + int motorSpeed = map(motorControl, 0, 39, 0, 255); |
|
| 37 | + motorSpeed = constrain(motorSpeed, 0, 255); |
|
| 38 | + analogWrite(ENA, motorSpeed); |
|
| 39 | + } else { |
|
| 40 | + // Stop motor |
|
| 41 | + digitalWrite(IN1, LOW); |
|
| 42 | + digitalWrite(IN2, LOW); |
|
| 43 | + analogWrite(ENA, 0); |
|
| 44 | + } |
|
| 45 | +} |
|
| 46 | + |
|
| 47 | +String pageRoot() { |
|
| 48 | + String html = "<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"; |
|
| 49 | + html += "<title>Motor AP Control</title></head><body>"; |
|
| 50 | + html += "<h2>Motor Control (0-100)</h2>"; |
|
| 51 | + html += "<input type=\"range\" id=\"s\" min=\"0\" max=\"100\" value=\"" + String(motorControl) + "\" oninput=\"update(this.value)\"/>"; |
|
| 52 | + html += "<span id=\"v\">" + String(motorControl) + "</span>"; |
|
| 53 | + html += "<script>function update(v){document.getElementById('v').innerText=v;fetch('/set?val='+v);}setInterval(function(){fetch('/status').then(r=>r.text()).then(t=>{document.getElementById('s').value=t;document.getElementById('v').innerText=t;});},1000);</script>"; |
|
| 54 | + html += "</body></html>"; |
|
| 55 | + return html; |
|
| 56 | +} |
|
| 57 | + |
|
| 58 | +void handleRoot() { |
|
| 59 | + server.send(200, "text/html", pageRoot()); |
|
| 60 | +} |
|
| 61 | + |
|
| 62 | +void handleSet() { |
|
| 63 | + if (!server.hasArg("val")) { |
|
| 64 | + server.send(400, "text/plain", "missing val"); |
|
| 65 | + return; |
|
| 66 | + } |
|
| 67 | + String v = server.arg("val"); |
|
| 68 | + int val = v.toInt(); |
|
| 69 | + val = constrain(val, 0, 100); |
|
| 70 | + motorControl = val; |
|
| 71 | + applyMotorControl(); |
|
| 72 | + server.send(200, "text/plain", String(motorControl)); |
|
| 73 | +} |
|
| 74 | + |
|
| 75 | +void handleStatus() { |
|
| 76 | + server.send(200, "text/plain", String(motorControl)); |
|
| 77 | +} |
|
| 78 | + |
|
| 79 | +void setup() { |
|
| 80 | + // Initialize pins |
|
| 81 | + pinMode(ENA, OUTPUT); |
|
| 82 | + pinMode(IN1, OUTPUT); |
|
| 83 | + pinMode(IN2, OUTPUT); |
|
| 84 | + |
|
| 85 | + // Initialize motor to off |
|
| 86 | + digitalWrite(IN1, LOW); |
|
| 87 | + digitalWrite(IN2, LOW); |
|
| 88 | + analogWrite(ENA, 0); |
|
| 89 | + |
|
| 90 | + Serial.begin(115200); |
|
| 91 | + delay(100); |
|
| 92 | + |
|
| 93 | + // Configure AP with fixed IP |
|
| 94 | + WiFi.softAPConfig(apIP, apIP, netMsk); |
|
| 95 | + WiFi.softAP(ssid, password); |
|
| 96 | + |
|
| 97 | + IPAddress myIP = WiFi.softAPIP(); |
|
| 98 | + Serial.print("AP IP address: "); |
|
| 99 | + Serial.println(myIP); |
|
| 100 | + |
|
| 101 | + // Configure server routes |
|
| 102 | + server.on("/", handleRoot); |
|
| 103 | + server.on("/set", handleSet); |
|
| 104 | + server.on("/status", handleStatus); |
|
| 105 | + server.begin(); |
|
| 106 | + Serial.println("HTTP server started"); |
|
| 107 | + |
|
| 108 | + // Ensure PWM range 0-255 |
|
| 109 | + analogWriteRange(255); |
|
| 110 | + |
|
| 111 | + // Apply initial motor state |
|
| 112 | + applyMotorControl(); |
|
| 113 | +} |
|
| 114 | + |
|
| 115 | +void loop() { |
|
| 116 | + server.handleClient(); |
|
| 117 | + // Optional: keep motor state applied in case other code modifies it |
|
| 118 | + // applyMotorControl(); |
|
| 119 | + delay(10); |
|
| 120 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/RC-code-dat/SDR1064-code-dat/SDR1064-rover-code-dat/serial-motor-1.ino
| ... | ... | @@ -0,0 +1,76 @@ |
| 1 | +// Define pins for motor control |
|
| 2 | +const int ENA = 5; // PWM for speed for Motor (single motor) |
|
| 3 | + |
|
| 4 | +const int IN1 = 0; // Direction pin A for Motor |
|
| 5 | +const int IN2 = 2 // Direction pin B for Motor |
|
| 6 | + |
|
| 7 | +int motorControl = 50; // 0..100, default mid-point |
|
| 8 | + |
|
| 9 | +int readControlSignal() { |
|
| 10 | + // Read control value from Serial if available (expects an integer 0-100 followed by newline) |
|
| 11 | + if (Serial.available()) { |
|
| 12 | + String s = Serial.readStringUntil('\n'); |
|
| 13 | + s.trim(); |
|
| 14 | + if (s.length() > 0) { |
|
| 15 | + int val = s.toInt(); |
|
| 16 | + if (val >= 0 && val <= 100) { |
|
| 17 | + motorControl = val; |
|
| 18 | + } |
|
| 19 | + } |
|
| 20 | + } |
|
| 21 | + return motorControl; |
|
| 22 | +} |
|
| 23 | + |
|
| 24 | +void setup() { |
|
| 25 | + // No RC input pin used — control comes from Serial |
|
| 26 | + |
|
| 27 | + pinMode(ENA, OUTPUT); |
|
| 28 | + pinMode(IN1, OUTPUT); |
|
| 29 | + pinMode(IN2, OUTPUT); |
|
| 30 | + |
|
| 31 | + // Initialize motor to off |
|
| 32 | + digitalWrite(IN1, LOW); |
|
| 33 | + digitalWrite(IN2, LOW); |
|
| 34 | + analogWrite(ENA, 0); |
|
| 35 | + |
|
| 36 | + Serial.begin(9600); |
|
| 37 | + Serial.println("Motor control ready. Send 0-100 via serial to control speed/direction."); |
|
| 38 | +} |
|
| 39 | + |
|
| 40 | +void loop() { |
|
| 41 | + // Read mapped control signal (from Serial) |
|
| 42 | + motorControl = readControlSignal(); |
|
| 43 | + |
|
| 44 | + // Print the mapped control signal values to the Serial Monitor |
|
| 45 | + Serial.print("Control: "); |
|
| 46 | + Serial.print(motorControl); |
|
| 47 | + Serial.println(); // Newline for better readability |
|
| 48 | + |
|
| 49 | + // Deadband: treat 40..60 as stop (adjust if needed) |
|
| 50 | + if (motorControl > 60) { |
|
| 51 | + // Forward: IN1 = HIGH, IN2 = LOW |
|
| 52 | + digitalWrite(IN1, HIGH); |
|
| 53 | + digitalWrite(IN2, LOW); |
|
| 54 | + |
|
| 55 | + // Map motorControl (61-100) to PWM speed (0-255) |
|
| 56 | + int motorSpeed = map(motorControl, 61, 100, 0, 255); |
|
| 57 | + motorSpeed = constrain(motorSpeed, 0, 255); |
|
| 58 | + analogWrite(ENA, motorSpeed); |
|
| 59 | + } else if (motorControl < 40) { |
|
| 60 | + // Reverse: IN1 = LOW, IN2 = HIGH |
|
| 61 | + digitalWrite(IN1, LOW); |
|
| 62 | + digitalWrite(IN2, HIGH); |
|
| 63 | + |
|
| 64 | + // Map motorControl (0-39) to PWM speed (0-255) |
|
| 65 | + int motorSpeed = map(motorControl, 0, 39, 0, 255); |
|
| 66 | + motorSpeed = constrain(motorSpeed, 0, 255); |
|
| 67 | + analogWrite(ENA, motorSpeed); |
|
| 68 | + } else { |
|
| 69 | + // Stop motor (motorControl is between 40 and 60 inclusive) |
|
| 70 | + digitalWrite(IN1, LOW); |
|
| 71 | + digitalWrite(IN2, LOW); |
|
| 72 | + analogWrite(ENA, 0); |
|
| 73 | + } |
|
| 74 | + |
|
| 75 | + delay(100); // Limit output rate |
|
| 76 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/code-dat.md
| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | + |
|
| 2 | +# code-dat.md |
|
| 3 | + |
|
| 4 | +- [[RC-code-dat]] |
|
| 5 | + |
|
| 6 | +- [[wifi-motor-control-dat]] - [[wifi-dat]] - [[SDR1064-dat]] |
|
| 7 | + |
|
| 8 | +- [[motor-driver-code-dat]] |
|
| 9 | + |
|
| 10 | + |
|
| 11 | +## repo |
|
| 12 | + |
|
| 13 | +- [[arduino-dat]] |
|
| ... | ... | \ No newline at end of file |
code-dat/motor-driver-code-dat/PWM-motor-esp-webserver-ap-1.ino
| ... | ... | @@ -0,0 +1,98 @@ |
| 1 | +#include <ESP8266WiFi.h> |
|
| 2 | +#include <ESP8266WebServer.h> |
|
| 3 | + |
|
| 4 | +// ===== WiFi 配置 ===== |
|
| 5 | +const char* ssid = "YOUR_SSID"; |
|
| 6 | +const char* password = "YOUR_PASSWORD"; |
|
| 7 | + |
|
| 8 | +// ===== GPIO 定义 ===== |
|
| 9 | +const int PWM_PIN = D1; // PWM 控制速度 IO5 |
|
| 10 | +const int DIR_PIN1 = D2; // 方向引脚1 IO4 |
|
| 11 | +const int DIR_PIN2 = D3; // 方向引脚2 IO0 |
|
| 12 | + |
|
| 13 | +// ===== Web Server ===== |
|
| 14 | +ESP8266WebServer server(80); |
|
| 15 | + |
|
| 16 | +// ===== HTML Web 控制界面 ===== |
|
| 17 | +const char html_page[] PROGMEM = R"rawliteral( |
|
| 18 | +<!DOCTYPE html><html> |
|
| 19 | +<head><title>ESP8266 Motor Control</title></head> |
|
| 20 | +<body> |
|
| 21 | +<h2>Motor Control</h2> |
|
| 22 | +<form action="/control"> |
|
| 23 | +Speed: <input type="range" name="speed" min="0" max="1023"><br> |
|
| 24 | +Direction: |
|
| 25 | +<select name="dir"> |
|
| 26 | + <option value="fw">Forward</option> |
|
| 27 | + <option value="rv">Reverse</option> |
|
| 28 | +</select><br> |
|
| 29 | +<input type="submit" value="Apply"> |
|
| 30 | +</form> |
|
| 31 | +</body></html> |
|
| 32 | +)rawliteral"; |
|
| 33 | + |
|
| 34 | +// ===== 处理 Web 请求 ===== |
|
| 35 | +void handleRoot() { |
|
| 36 | + server.send(200, "text/html", html_page); |
|
| 37 | +} |
|
| 38 | + |
|
| 39 | +void handleControl() { |
|
| 40 | + if (server.hasArg("speed")) { |
|
| 41 | + int speed = server.arg("speed").toInt(); // PWM 值 0-1023 |
|
| 42 | + analogWrite(PWM_PIN, speed); |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + if (server.hasArg("dir")) { |
|
| 46 | + String d = server.arg("dir"); |
|
| 47 | + if (d == "fw") { |
|
| 48 | + digitalWrite(DIR_PIN1, HIGH); |
|
| 49 | + digitalWrite(DIR_PIN2, LOW); |
|
| 50 | + } else { |
|
| 51 | + digitalWrite(DIR_PIN1, LOW); |
|
| 52 | + digitalWrite(DIR_PIN2, HIGH); |
|
| 53 | + } |
|
| 54 | + } |
|
| 55 | + |
|
| 56 | + server.sendHeader("Location", "/"); |
|
| 57 | + server.send(302, "text/plain", ""); |
|
| 58 | +} |
|
| 59 | + |
|
| 60 | +// ===== 初始化 ===== |
|
| 61 | +void setup() { |
|
| 62 | + Serial.begin(115200); |
|
| 63 | + |
|
| 64 | + pinMode(PWM_PIN, OUTPUT); |
|
| 65 | + pinMode(DIR_PIN1, OUTPUT); |
|
| 66 | + pinMode(DIR_PIN2, OUTPUT); |
|
| 67 | + |
|
| 68 | + // 默认停止 |
|
| 69 | + analogWrite(PWM_PIN, 0); |
|
| 70 | + digitalWrite(DIR_PIN1, LOW); |
|
| 71 | + digitalWrite(DIR_PIN2, LOW); |
|
| 72 | + |
|
| 73 | + // 启动为 WiFi AP 模式,使用固定 IP |
|
| 74 | + WiFi.mode(WIFI_AP); |
|
| 75 | + // 固定 AP 地址(根据需要修改) |
|
| 76 | + IPAddress apIP(192, 168, 50, 1); |
|
| 77 | + IPAddress apGateway(192, 168, 50, 1); |
|
| 78 | + IPAddress apSubnet(255, 255, 255, 0); |
|
| 79 | + if (!WiFi.softAPConfig(apIP, apGateway, apSubnet)) { |
|
| 80 | + Serial.println("softAPConfig failed"); |
|
| 81 | + } |
|
| 82 | + |
|
| 83 | + // 启动软 AP:使用 ssid 和 password(注意:WPA2 密码至少 8 字符) |
|
| 84 | + WiFi.softAP(ssid, password); |
|
| 85 | + delay(500); |
|
| 86 | + Serial.println(""); |
|
| 87 | + Serial.print("AP started, IP: "); |
|
| 88 | + Serial.println(WiFi.softAPIP()); |
|
| 89 | + |
|
| 90 | + // Web 服务 |
|
| 91 | + server.on("/", handleRoot); |
|
| 92 | + server.on("/control", handleControl); |
|
| 93 | + server.begin(); |
|
| 94 | +} |
|
| 95 | + |
|
| 96 | +void loop() { |
|
| 97 | + server.handleClient(); |
|
| 98 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/motor-driver-code-dat/PWM-motor-esp-webserver-sta-1.ino
| ... | ... | @@ -0,0 +1,94 @@ |
| 1 | + |
|
| 2 | + |
|
| 3 | +#include <ESP8266WiFi.h> |
|
| 4 | +#include <ESP8266WebServer.h> |
|
| 5 | + |
|
| 6 | +// ===== WiFi 配置 ===== |
|
| 7 | +const char* ssid = "YOUR_SSID"; |
|
| 8 | +const char* password = "YOUR_PASSWORD"; |
|
| 9 | + |
|
| 10 | +// ===== GPIO 定义 ===== |
|
| 11 | +const int PWM_PIN = D1; // PWM 控制速度 IO5 |
|
| 12 | +const int DIR_PIN1 = D2; // 方向引脚1 IO4 |
|
| 13 | +const int DIR_PIN2 = D3; // 方向引脚2 IO0 |
|
| 14 | + |
|
| 15 | +// ===== Web Server ===== |
|
| 16 | +ESP8266WebServer server(80); |
|
| 17 | + |
|
| 18 | +// ===== HTML Web 控制界面 ===== |
|
| 19 | +const char html_page[] PROGMEM = R"rawliteral( |
|
| 20 | +<!DOCTYPE html><html> |
|
| 21 | +<head><title>ESP8266 Motor Control</title></head> |
|
| 22 | +<body> |
|
| 23 | +<h2>Motor Control</h2> |
|
| 24 | +<form action="/control"> |
|
| 25 | +Speed: <input type="range" name="speed" min="0" max="1023"><br> |
|
| 26 | +Direction: |
|
| 27 | +<select name="dir"> |
|
| 28 | + <option value="fw">Forward</option> |
|
| 29 | + <option value="rv">Reverse</option> |
|
| 30 | +</select><br> |
|
| 31 | +<input type="submit" value="Apply"> |
|
| 32 | +</form> |
|
| 33 | +</body></html> |
|
| 34 | +)rawliteral"; |
|
| 35 | + |
|
| 36 | +// ===== 处理 Web 请求 ===== |
|
| 37 | +void handleRoot() { |
|
| 38 | + server.send(200, "text/html", html_page); |
|
| 39 | +} |
|
| 40 | + |
|
| 41 | +void handleControl() { |
|
| 42 | + if (server.hasArg("speed")) { |
|
| 43 | + int speed = server.arg("speed").toInt(); // PWM 值 0-1023 |
|
| 44 | + analogWrite(PWM_PIN, speed); |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + if (server.hasArg("dir")) { |
|
| 48 | + String d = server.arg("dir"); |
|
| 49 | + if (d == "fw") { |
|
| 50 | + digitalWrite(DIR_PIN1, HIGH); |
|
| 51 | + digitalWrite(DIR_PIN2, LOW); |
|
| 52 | + } else { |
|
| 53 | + digitalWrite(DIR_PIN1, LOW); |
|
| 54 | + digitalWrite(DIR_PIN2, HIGH); |
|
| 55 | + } |
|
| 56 | + } |
|
| 57 | + |
|
| 58 | + server.sendHeader("Location", "/"); |
|
| 59 | + server.send(302, "text/plain", ""); |
|
| 60 | +} |
|
| 61 | + |
|
| 62 | +// ===== 初始化 ===== |
|
| 63 | +void setup() { |
|
| 64 | + Serial.begin(115200); |
|
| 65 | + |
|
| 66 | + pinMode(PWM_PIN, OUTPUT); |
|
| 67 | + pinMode(DIR_PIN1, OUTPUT); |
|
| 68 | + pinMode(DIR_PIN2, OUTPUT); |
|
| 69 | + |
|
| 70 | + // 默认停止 |
|
| 71 | + analogWrite(PWM_PIN, 0); |
|
| 72 | + digitalWrite(DIR_PIN1, LOW); |
|
| 73 | + digitalWrite(DIR_PIN2, LOW); |
|
| 74 | + |
|
| 75 | + // 连接 WiFi |
|
| 76 | + WiFi.mode(WIFI_STA); |
|
| 77 | + WiFi.begin(ssid, password); |
|
| 78 | + while (WiFi.status() != WL_CONNECTED) { |
|
| 79 | + delay(500); |
|
| 80 | + Serial.print("."); |
|
| 81 | + } |
|
| 82 | + Serial.println(""); |
|
| 83 | + Serial.print("Connected, IP: "); |
|
| 84 | + Serial.println(WiFi.localIP()); |
|
| 85 | + |
|
| 86 | + // Web 服务 |
|
| 87 | + server.on("/", handleRoot); |
|
| 88 | + server.on("/control", handleControl); |
|
| 89 | + server.begin(); |
|
| 90 | +} |
|
| 91 | + |
|
| 92 | +void loop() { |
|
| 93 | + server.handleClient(); |
|
| 94 | +} |
|
| ... | ... | \ No newline at end of file |
code-dat/motor-driver-code-dat/motor-driver-code-dat.md
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | + |
|
| 2 | +# motor-driver-code-dat |
|
| 3 | + |
|
| 4 | + |
|
| 5 | + |
|
| 6 | +## drive by wifi and webserver |
|
| 7 | + |
|
| 8 | +- [[PWM-motor-esp-webserver-sta-1.ino]] |
|
| 9 | + |
|
| 10 | +- [[wifi-motor-control-dat]] |
|
| 11 | + |
|
| 12 | +- [[ESP32-rc-car-dat]] |
|
| 13 | + |
|
| 14 | + |
|
| 15 | + |
|
| 16 | + |
|
| 17 | + |
|
| 18 | +## ref |
|
| 19 | + |
|
| 20 | +- [[motor-driver-dat]] |
|
| 21 | + |
|
| 22 | + |