c++ - How do I fix my brushless motor not reversing with my Arduino esp-32 nano? - Stack Overflow

I am coding an RC car in the Arduino IDE.Here are the specs of what I use:Arduino Nano esp-32Wifi pro

I am coding an RC car in the Arduino IDE.

Here are the specs of what I use:

  • Arduino Nano esp-32
  • Wifi protocol: esp-now
  • Motor: AL-2835-10

The receiver and the sender are both the same Arduino and are correctly communicating. Steering and forward is working fine, it is reversing that doesn't work at all.

What do I have to do or am I not seeing?

The code looks as follows:

#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>
#include <ESP32Servo.h>

typedef struct struct_message {
  int steering_stick;
  int accelerating_stick;
} struct_message;

struct_message myReceivedData;
Servo steeringServo;
Servo ESC;

// Keep original pin definitions
const int steeringPin = 4;
const int escPin = 6;

// Maintain original mapping constants for accelerating stick
const int deadzoneLow = 1920;
const int deadzoneHigh = 1940;
const int idlePulse = 850;         // Confirmed neutral pulse is 1000μs
const int forwardMinPulse = 1100;   // Forward begins at this value
const int forwardMaxPulse = 2000;   // Full forward
const int reverseMinPulse = 500;    // Modified: Less aggressive reverse
const int reverseMaxPulse = 950;    // Approach neutral from below

// Keep original steering constants
const int steerMin = 60;
const int steerMax = 130;

// Variables for state tracking
int lastAccel = -1;
int lastSteer = -1;
bool motorBraked = false;          // Track if motor is in braked state
unsigned long brakeStartTime = 0;   // When braking began
const unsigned long brakeHoldTime = 2000; // Hold time in brake/neutral before reverse

// ESC initialization flags
bool escInitialized = false;
bool reverseModeEnabled = false;

void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
  memcpy(&myReceivedData, incomingData, sizeof(myReceivedData));
  
  // Keep the original logging logic
  if (myReceivedData.accelerating_stick != lastAccel || myReceivedData.steering_stick != lastSteer) {
    Serial.println("Received data:");
    Serial.print("Accelerating Stick: ");
    Serial.println(myReceivedData.accelerating_stick);
    Serial.print("Steering Stick: ");
    Serial.println(myReceivedData.steering_stick);
    lastAccel = myReceivedData.accelerating_stick;
    lastSteer = myReceivedData.steering_stick;
  }
  
  // Make sure ESC is initialized
  if (!escInitialized) {
    return;
  }
  
  int escPulse;
  
  // Deadzone handling - stick in neutral position
  if (myReceivedData.accelerating_stick >= deadzoneLow && myReceivedData.accelerating_stick <= deadzoneHigh) {
    escPulse = idlePulse;
    motorBraked = true;
    brakeStartTime = millis();
    
    // In deadzone, reset brake timer only if we weren't already braked
    if (!motorBraked) {
      brakeStartTime = millis();
      motorBraked = true;
    }
  }
  // Stick in reverse position
  else if (myReceivedData.accelerating_stick < deadzoneLow) {
    // Check if we're currently going forward (need to brake first)
    if (!motorBraked) {
      // Need to brake first before reversing
      escPulse = idlePulse;
      motorBraked = true;
      brakeStartTime = millis();
      Serial.println("Braking before reverse...");
    } 
    // If we've been in brake mode long enough, allow reverse
    else if (millis() - brakeStartTime >= brakeHoldTime) {
      // Use double-tap reverse technique (common in brushless ESCs)
      // First tap already happened with the braking
      
      // Now apply reverse signal
      escPulse = map(myReceivedData.accelerating_stick, 0, deadzoneLow, reverseMinPulse, reverseMaxPulse);
      Serial.println("Applying reverse signal after brake period");
    } 
    // Still in braking period
    else {
      escPulse = idlePulse;
      Serial.println("Still in braking period before reverse");
    }
  }
  // Stick in forward position
  else {
    // Mapping for forward motion - keep your original mapping logic
    escPulse = map(myReceivedData.accelerating_stick, deadzoneHigh, 4095, forwardMinPulse, forwardMaxPulse);
    motorBraked = false; // No longer in brake state
  }
  
  // Keep your original steering mapping
  int steerAngle = map(myReceivedData.steering_stick, 0, 4095, steerMin, steerMax);
  
  // Update outputs
  ESC.writeMicroseconds(escPulse);
  steeringServo.write(steerAngle);
  
  // Keep your original debug output
  Serial.print("Mapped ESC Pulse: ");
  Serial.println(escPulse);
  Serial.print("Mapped Steering Angle: ");
  Serial.println(steerAngle);
  
  // Additional debug information about motor state
  if (motorBraked) {
    Serial.print("Motor braked: ");
    Serial.print((millis() - brakeStartTime) / 1000.0);
    Serial.println(" seconds");
  }
  
  Serial.println();
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  
  // Keep your original WiFi and ESP-NOW initialization
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  esp_now_register_recv_cb(OnDataRecv);
  Serial.println("Receiver initialized and waiting for data...");
  
  // Keep original servo setup
  steeringServo.setPeriodHertz(50);
  ESC.setPeriodHertz(50);
  
  // Attach servos with full pulse range
  steeringServo.attach(steeringPin);
  ESC.attach(escPin, 800, 2000);  // Adjusted range for bidirectional operation
  
  // Enhanced ESC initialization for bidirectional mode
  initializeESC();
  
  // Set default positions
  steeringServo.write((steerMin + steerMax) / 2);
  ESC.writeMicroseconds(idlePulse);
  Serial.println("Default positions set: steering centered, ESC idle.");
}

void initializeESC() {
  Serial.println("Initializing ESC for bidirectional operation...");
  Serial.println("Step 1: Hold in neutral position");
  
  // First, ensure the ESC is in neutral for a few seconds
  ESC.writeMicroseconds(idlePulse);
  delay(1000);
  
  // Step 2: Programming sequence for bidirectional mode
  // Many brushless ESCs use a specific pattern to enter programming mode
  Serial.println("Step 2: Sending bidirectional mode programming sequence");
  
  // Sequence: neutral → full forward → neutral → full reverse → neutral
  // This is a common pattern to enable bidirectional operation
  
  // Full forward
  ESC.writeMicroseconds(forwardMinPulse);
  delay(1000);
  
  // Back to neutral
  ESC.writeMicroseconds(idlePulse);
  delay(1000);
  
  // Full reverse (as a programming signal)
  ESC.writeMicroseconds(reverseMinPulse);
  delay(1000);
  
  // Back to neutral
  ESC.writeMicroseconds(idlePulse);
  delay(1000);
  
  // Short pulse to forward
  ESC.writeMicroseconds(forwardMinPulse);
  delay(500);
  
  // Back to neutral
  ESC.writeMicroseconds(idlePulse);
  delay(1000);
  
  // Short pulse to reverse
  ESC.writeMicroseconds(reverseMaxPulse);
  delay(500);
  
  // Final neutral position
  ESC.writeMicroseconds(idlePulse);
  delay(1000);
  
  Serial.println("Bidirectional mode initialization complete");
  Serial.println("Note: Most ESCs require double-tap for reverse (brake first, then reverse)");
  
  escInitialized = true;
  reverseModeEnabled = true;
}

void loop() {
  // All updates are handled in the ESP-NOW callback
  
  // Safety feature: if no signal for a while, go to neutral
  static unsigned long lastActivityTime = millis();
  
  if (millis() - lastActivityTime > 5000) {
    // No signal for 5 seconds - safety neutral
    ESC.writeMicroseconds(idlePulse);
    Serial.println("Safety neutral engaged - no activity for 5+ seconds");
    lastActivityTime = millis();
  }
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744770979a4592756.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信