본문 바로가기

ESP32

esp32 자동차 무선 제어

반응형

 

여기에서 코드, 회로도 및 3D 모델을 찾을 수 있습니다 "https://github.com/RED9030/ESP_NOW_RC_CONTROL" 이것은 프로토타입일 뿐이며 3D 모델은 골판지 또는 우리가 가지고 있는 다른 재료로 만들 수 있는 아이디어를 얻기 위한 것임을 상기시켜 드립니다. 

 

자료 Github 주소

 

https://github.com/RED9030/ESP_NOW_RC_CONTROL?fbclid=IwZXh0bgNhZW0CMTAAAR3Kc75zvwmgSl6V_SHb1D8N1Yssz6NkIkofY3kuOWYpj0rkNueRbXrtpUg_aem_RM3PQ0vuNHe8BUXwnYZz5A

 

 

송신부

 

 

TX_RC_ESPNOW_CARS_ESP8266

 

 

수신부

 

 

RX_RC_ESPNOW_CARS_ESP32

 

 

RX_RC_ESPNOW_CARS_ESP32

 

 

 

ESP32 Car RX Code

 

/*
  MODDER: @RED9030
*/
/*
  Title: ESPNOW ESP32 CAR RX
  Este sketch permite la recepción de los datos mediante la comunicación ESP-NOW
  Carro control remoto usando protocolo espNOW 2.4GHz, 4 motores tracción trasera/delantera y giros.
  
  HardWare: ESP32
*/

/*
 *****************************************************
 *    LIBRERIAS
 *****************************************************
*/
#include <esp_now.h>
#include <WiFi.h>

/*
 *****************************************************
 *    VARIABLES
 *****************************************************
*/
//Right motor
int enableRightMotor=15;    //Enable Motor B 
int rightMotorPin1=19;      //In 3
int rightMotorPin2=18;      //In 4
//Left motor
int enableLeftMotor=5;     //Enable Motor A
int leftMotorPin1=22;      //In 1
int leftMotorPin2=21;      //In 2

#define MAX_MOTOR_SPEED 200

const int PWMFreq = 1000;                   // 1 KHz 
const int PWMResolution = 8;                // Resolutions bits "8bits"
const int rightMotorPWMSpeedChannel = 4;    //PWM channel Right motor
const int leftMotorPWMSpeedChannel = 5;     //PWM channel Left motor

#define SIGNAL_TIMEOUT 1000  // This is signal timeout in milli seconds. We will reset the data if no signal
unsigned long lastRecvTime = 0;

struct PacketData
{
  byte xAxisValue;
  byte yAxisValue;
  byte switchPressed;
};
PacketData receiverData;

bool throttleAndSteeringMode = false;

//Lights
#define LDright 4  //Directional right
#define LDleft  2  //Directional Left
#define LStop   6  //Stop Light
#define LNight  7  //Diurn Light
#define Horn 34    //Horn

/*
 *****************************************************
 *    FUNCIONES
 *****************************************************
*/
// Callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) 
{
  if (len == 0)
  {
    return;
  }
  memcpy(&receiverData, incomingData, sizeof(receiverData));
  String inputData ;
  inputData = inputData + "values " + receiverData.xAxisValue + "  " + receiverData.yAxisValue + "  " + receiverData.switchPressed;
  Serial.println(inputData);
  if (receiverData.switchPressed == true)
  {
    if (throttleAndSteeringMode == false)
    {
      throttleAndSteeringMode = true;
    }
    else
    {
      throttleAndSteeringMode = false;
    }
  }

  if (throttleAndSteeringMode)
  {
    throttleAndSteeringMovements();
  }
  else
  {
    simpleMovements();
  }

  lastRecvTime = millis();   
}

//Simple motor movements
void simpleMovements()
{
  if (receiverData.yAxisValue <= 75)       //Move car Forward
  {
    rotateMotor(MAX_MOTOR_SPEED, MAX_MOTOR_SPEED);
    digitalWrite(LDright,LOW);
    digitalWrite(LDleft,LOW);
    digitalWrite(LStop,LOW);
  }
  else if (receiverData.yAxisValue >= 175)   //Move car Backward
  {
    rotateMotor(-MAX_MOTOR_SPEED, -MAX_MOTOR_SPEED);
    digitalWrite(LStop,HIGH);
    digitalWrite(LDright,LOW);
    digitalWrite(LDleft,LOW);
  }
  else if (receiverData.xAxisValue >= 175)  //Move car Right
  {
    rotateMotor(-MAX_MOTOR_SPEED, MAX_MOTOR_SPEED);
    digitalWrite(LStop,LOW);
    blinkingLed(LDright);
  }
  else if (receiverData.xAxisValue <= 75)   //Move car Left
  {
    rotateMotor(MAX_MOTOR_SPEED, -MAX_MOTOR_SPEED);
    digitalWrite(LStop,LOW);
    blinkingLed(LDleft);
  }
  else                                      //Stop the car
  {
    rotateMotor(0, 0);
    digitalWrite(LDright,LOW);
    digitalWrite(LDleft,LOW);
    digitalWrite(LStop,LOW);
    digitalWrite(LNight,LOW);
    
  }   
}

//Direction and aceleration Movements
void throttleAndSteeringMovements()
{
  int throttle = map( receiverData.yAxisValue, 254, 0, -255, 255);
  int steering = map( receiverData.xAxisValue, 0, 254, -255, 255);  
  int motorDirection = 1;
  
  if (throttle < 0)       //Move car backward
  {
    motorDirection = -1;    
  }

  int rightMotorSpeed, leftMotorSpeed;
  rightMotorSpeed =  abs(throttle) - steering;
  leftMotorSpeed =  abs(throttle) + steering;
  rightMotorSpeed = constrain(rightMotorSpeed, 0, 255);
  leftMotorSpeed = constrain(leftMotorSpeed, 0, 255);

  rotateMotor(rightMotorSpeed * motorDirection, leftMotorSpeed * motorDirection);
}

//Rotación del vehículo
void rotateMotor(int rightMotorSpeed, int leftMotorSpeed)
{
  if (rightMotorSpeed < 0)
  {
    digitalWrite(rightMotorPin1,LOW);
    digitalWrite(rightMotorPin2,HIGH);    
  }
  else if (rightMotorSpeed > 0)
  {
    digitalWrite(rightMotorPin1,HIGH);
    digitalWrite(rightMotorPin2,LOW);      
  }
  else
  {
    digitalWrite(rightMotorPin1,LOW);
    digitalWrite(rightMotorPin2,LOW);      
  }
  
  if (leftMotorSpeed < 0)
  {
    digitalWrite(leftMotorPin1,LOW);
    digitalWrite(leftMotorPin2,HIGH);    
  }
  else if (leftMotorSpeed > 0)
  {
    digitalWrite(leftMotorPin1,HIGH);
    digitalWrite(leftMotorPin2,LOW);      
  }
  else
  {
    digitalWrite(leftMotorPin1,LOW);
    digitalWrite(leftMotorPin2,LOW);      
  } 

  ledcWrite(rightMotorPWMSpeedChannel, abs(rightMotorSpeed));
  ledcWrite(leftMotorPWMSpeedChannel, abs(leftMotorSpeed));    
}

//Configuraciones de los pines
void setUpPinModes()
{
  //Right Motors
  pinMode(enableRightMotor,OUTPUT);
  pinMode(rightMotorPin1,OUTPUT);
  pinMode(rightMotorPin2,OUTPUT);
  //Left Motors  
  pinMode(enableLeftMotor,OUTPUT);
  pinMode(leftMotorPin1,OUTPUT);
  pinMode(leftMotorPin2,OUTPUT);
  //Lights & Horn
  pinMode(LDright,OUTPUT);
  pinMode(Left,OUTPUT);
  pinMode(LStop,OUTPUT);
  pinMode(LNight,OUTPUT);
  pinMode(Horn,OUTPUT);

  //Set up PWM for motor speed
  ledcSetup(rightMotorPWMSpeedChannel, PWMFreq, PWMResolution);
  ledcSetup(leftMotorPWMSpeedChannel, PWMFreq, PWMResolution);  
  ledcAttachPin(enableRightMotor, rightMotorPWMSpeedChannel);
  ledcAttachPin(enableLeftMotor, leftMotorPWMSpeedChannel); 
  
  rotateMotor(0, 0);
}

//Función para hacer brillar un led
blinkingLed(const int Pin)
{
    digitalWrite(Pin,HIGH);
    delay(500);
    digitalWrite(Pin,LOW);
    delay(500);
  }

/*
 *****************************************************
 *    INICIO
 *****************************************************
*/
void setup() 
{
  setUpPinModes();
  
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  esp_now_register_recv_cb(OnDataRecv);
}

/*
 *****************************************************
 *    REPETICIÓN
 *****************************************************
*/
void loop() 
{
  //Check Signal lost.
  unsigned long now = millis();
  if ( now - lastRecvTime > SIGNAL_TIMEOUT ) 
  {
    rotateMotor(0, 0);
  }
}

 

 

ESP32 Car TX Code

 

 

/*
  MODDER: @RED9030
*/
/*
  Title: ESPNOW ESP32 CAR TX
  Este sketch permite la transmición de dos datos mediante la comunicación ESP-NOW
  Carro control remoto usando protocolo espNOW, 4 motores tracción trasera/delantera y giros.

  HardWare: ESP32
*/

/*
 *****************************************************
 *    LIBRERIAS
 *****************************************************
*/
#include <esp_now.h>
#include <WiFi.h>

/*
 *****************************************************
 *    VARIABLES
 *****************************************************
*/
#define X_AXIS_PIN 32
#define Y_AXIS_PIN 33
#define SWITCH_PIN 25

// RECEIVER MAC Address
uint8_t receiverMacAddress[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};  //Here mac for Receptor (RX)

struct PacketData
{
  byte xAxisValue;
  byte yAxisValue;
  byte switchPressed;
};
PacketData data;

/*
 *****************************************************
 *    FUNCIONES
 *****************************************************
*/
//This function is used to map 0-4095 joystick value to 0-254. hence 127 is the center value which we send.
//It also adjust the deadband in joystick.
//Jotstick values range from 0-4095. But its center value is not always 2047. It is little different.
//So we need to add some deadband to center value. in our case 1800-2200. Any value in this deadband range is mapped to center 127.
int mapAndAdjustJoystickDeadBandValues(int value, bool reverse)
{
  if (value >= 2200)
  {
    value = map(value, 2200, 4095, 127, 254);
  }
  else if (value <= 1800)
  {
    value = map(value, 1800, 0, 127, 0);  
  }
  else
  {
    value = 127;
  }

  if (reverse)
  {
    value = 254 - value;
  }
  return value;
}

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
  Serial.print("\r\nLast Packet Send Status:\t ");
  Serial.println(status);
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Message sent" : "Message failed");
}

/*
 *****************************************************
 *    INICIO
 *****************************************************
*/
void setup() 
{
  
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  else
  {
    Serial.println("Succes: Initialized ESP-NOW");
  }

  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  esp_now_peer_info_t peerInfo;
  memset(&peerInfo, 0, sizeof(esp_now_peer_info_t));
  memcpy(peerInfo.peer_addr, receiverMacAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK)
  {
    Serial.println("Failed to add peer");
    return;
  }
  else
  {
    Serial.println("Succes: Added peer");
  } 

  pinMode(SWITCH_PIN, INPUT_PULLUP);   
}

/*
 *****************************************************
 *    REPETICIÓN
 *****************************************************
*/ 
void loop() 
{
  data.xAxisValue = mapAndAdjustJoystickDeadBandValues(analogRead(X_AXIS_PIN), false);
  data.yAxisValue = mapAndAdjustJoystickDeadBandValues(analogRead(Y_AXIS_PIN), false);  
  data.switchPressed = false; 

  if (digitalRead(SWITCH_PIN) == LOW)
  {
    data.switchPressed = true;
  }
  
  esp_err_t result = esp_now_send(receiverMacAddress, (uint8_t *) &data, sizeof(data));
  if (result == ESP_OK) 
  {
    Serial.println("Sent with success");
  }
  else 
  {
    Serial.println("Error sending the data");
  }    
  
  if (data.switchPressed == true)
  {
    delay(500);
  }
  else
  {
    delay(50);
  }
}

 

 

 

ESP8266 Car RX Code

 

/*
  MODDER: @RED9030
*/
/*
  Title: ESPNOW ESP8266 CAR RX
  Este sketch permite la recepción de los datos mediante la comunicación ESP-NOW
  Carro control remoto usando protocolo espNOW 2.4GHz, 4 motores tracción trasera/delantera y giros.
  
  HardWare: ESP8266
*/
 
/*
  PINES: Luces D0,D7,D8 MOTOR_ENABLES ENA-D5 ENB-D6
*/

/*
 *****************************************************
 *    LIBRERIAS
 *****************************************************
*/
#include <espnow.h>
#include <ESP8266WiFi.h>

/*
 *****************************************************
 *    VARIABLES
 *****************************************************
*/
//Rear motor
int enableRightMotor=5; 
int rightMotorPin1=3;
int rightMotorPin2=4;
//Front motor
int enableLeftMotor=6;
int leftMotorPin1=1;
int leftMotorPin2=2;

#define MAX_MOTOR_SPEED 200

const int PWMFreq = 1000; /* 1 KHz */
const int PWMResolution = 8;
const int rightMotorPWMSpeedChannel = 4;
const int leftMotorPWMSpeedChannel = 5;

#define SIGNAL_TIMEOUT 1000  // Este es el tiempo de espera de la señal en milisegundos. Restableceremos los datos si no hay señal
unsigned long lastRecvTime = 0;

struct PacketData
{
  byte xAxisValue;
  byte yAxisValue;
  byte switchPressed;
};
PacketData receiverData;

bool throttleAndSteeringMode = false; //Habilita la Dirección y aceleración 

/*
 *****************************************************
 *    FUNCIONES
 *****************************************************
*/
// callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) 
{
  if (len == 0)
  {
    return;
  }
  memcpy(&receiverData, incomingData, sizeof(receiverData));
  String inputData ;
  inputData = inputData + "values " + receiverData.xAxisValue + "  " + receiverData.yAxisValue + "  " + receiverData.switchPressed;
  Serial.println(inputData);
  if (receiverData.switchPressed == true)
  {
    if (throttleAndSteeringMode == false)
    {
      throttleAndSteeringMode = true;
    }
    else
    {
      throttleAndSteeringMode = false;
    }
  }

  if (throttleAndSteeringMode)
  {
    throttleAndSteeringMovements();
  }
  else
  {
    simpleMovements();
  }

  lastRecvTime = millis();   
}

//Simple motor movements
void simpleMovements()
{
  if (receiverData.yAxisValue <= 75)       //Move car Forward
  {
    rotateMotor(MAX_MOTOR_SPEED, MAX_MOTOR_SPEED);
  }
  else if (receiverData.yAxisValue >= 175)   //Move car Backward
  {
    rotateMotor(-MAX_MOTOR_SPEED, -MAX_MOTOR_SPEED);
  }
  else if (receiverData.xAxisValue >= 175)  //Move car Right
  {
    rotateMotor(-MAX_MOTOR_SPEED, MAX_MOTOR_SPEED);
  }
  else if (receiverData.xAxisValue <= 75)   //Move car Left
  {
    rotateMotor(MAX_MOTOR_SPEED, -MAX_MOTOR_SPEED);
  }
  else                                      //Stop the car
  {
    rotateMotor(0, 0);
  }   
}

//Direction and aceleration Movements
void throttleAndSteeringMovements()
{
  int throttle = map( receiverData.yAxisValue, 254, 0, -255, 255);
  int steering = map( receiverData.xAxisValue, 0, 254, -255, 255);  
  int motorDirection = 1;
  
  if (throttle < 0)       //Move car backward
  {
    motorDirection = -1;    
  }

  int rightMotorSpeed, leftMotorSpeed;
  rightMotorSpeed =  abs(throttle) - steering;
  leftMotorSpeed =  abs(throttle) + steering;
  rightMotorSpeed = constrain(rightMotorSpeed, 0, 255);
  leftMotorSpeed = constrain(leftMotorSpeed, 0, 255);

  rotateMotor(rightMotorSpeed * motorDirection, leftMotorSpeed * motorDirection);
}


//Rotación del vehículo
void rotateMotor(int rightMotorSpeed, int leftMotorSpeed)
{
  if (rightMotorSpeed < 0)
  {
    digitalWrite(rightMotorPin1,LOW);
    digitalWrite(rightMotorPin2,HIGH);    
  }
  else if (rightMotorSpeed > 0)
  {
    digitalWrite(rightMotorPin1,HIGH);
    digitalWrite(rightMotorPin2,LOW);      
  }
  else
  {
    digitalWrite(rightMotorPin1,LOW);
    digitalWrite(rightMotorPin2,LOW);      
  }
  
  if (leftMotorSpeed < 0)
  {
    digitalWrite(leftMotorPin1,LOW);
    digitalWrite(leftMotorPin2,HIGH);    
  }
  else if (leftMotorSpeed > 0)
  {
    digitalWrite(leftMotorPin1,HIGH);
    digitalWrite(leftMotorPin2,LOW);      
  }
  else
  {
    digitalWrite(leftMotorPin1,LOW);
    digitalWrite(leftMotorPin2,LOW);      
  } 

  analogWrite(rightMotorPWMSpeedChannel,abs(rightMotorSpeed));
  analogWrite(leftMotorPWMSpeedChannel,abs(leftMotorSpeed));    
}

void setUpPinModes()
{
  pinMode(enableRightMotor,OUTPUT);
  pinMode(rightMotorPin1,OUTPUT);
  pinMode(rightMotorPin2,OUTPUT);
  
  pinMode(enableLeftMotor,OUTPUT);
  pinMode(leftMotorPin1,OUTPUT);
  pinMode(leftMotorPin2,OUTPUT);

 /*
 //No necessary for esp8266
  //Set up PWM for motor speed
  ledcSetup(rightMotorPWMSpeedChannel, PWMFreq, PWMResolution);
  ledcSetup(leftMotorPWMSpeedChannel, PWMFreq, PWMResolution);  
  ledcAttachPin(enableRightMotor, rightMotorPWMSpeedChannel);
  ledcAttachPin(enableLeftMotor, leftMotorPWMSpeedChannel); 
 */
  rotateMotor(0, 0);
}

/*
 *****************************************************
 *    INICIO
 *****************************************************
*/
void setup() 
{
  setUpPinModes();
  
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) 
  {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  //esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
  esp_now_register_recv_cb(OnDataRecv);
}

/*
 *****************************************************
 *    REPETICIÓN
 *****************************************************
*/
void loop() 
{
  //Check Signal lost.
  unsigned long now = millis();
  if ( now - lastRecvTime > SIGNAL_TIMEOUT ) 
  {
    rotateMotor(0, 0);
  }
}

 

 

ESP8266 Car TX Code

 

 

/*
  MODDER: @RED9030
*/
/*
  Title: ESPNOW ESP8266 CAR TX
  Este sketch permite la transmición de dos datos mediante la comunicación ESP-NOW
  Carro control remoto usando protocolo espNOW, 4 motores tracción trasera/delantera y giros.

  HardWare: ESP8266
*/

/*
 *****************************************************
 *    LIBRERIAS
 *****************************************************
*/
#include <espnow.h>
#include <ESP8266WiFi.h>

/*
 *****************************************************
 *    VARIABLES
 *****************************************************
*/
#define X_AXIS_PIN 32
#define Y_AXIS_PIN 33
#define SWITCH_PIN 25

// RECEIVER MAC Address
uint8_t receiverMacAddress[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};  //Here mac for Receptor (RX)

struct PacketData
{
  byte xAxisValue;
  byte yAxisValue;
  byte switchPressed;
};
PacketData data;

/*
 *****************************************************
 *    FUNCIONES
 *****************************************************
*/
//This function is used to map 0-4095 joystick value to 0-254. hence 127 is the center value which we send.
//It also adjust the deadband in joystick.
//Jotstick values range from 0-4095. But its center value is not always 2047. It is little different.
//So we need to add some deadband to center value. in our case 1800-2200. Any value in this deadband range is mapped to center 127.
int mapAndAdjustJoystickDeadBandValues(int value, bool reverse)
{
  if (value >= 2200)
  {
    value = map(value, 2200, 4095, 127, 254);
  }
  else if (value <= 1800)
  {
    value = map(value, 1800, 0, 127, 0);  
  }
  else
  {
    value = 127;
  }

  if (reverse)
  {
    value = 254 - value;
  }
  return value;
}

// callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus)
{
  Serial.print("\r\nLast Packet Send Status:\t ");
  if(sendStatus == 0){
    Serial.println("Message sent");
  }else{
    Serial.println("Message failed");
    }
}

/*
 *****************************************************
 *    INICIO
 *****************************************************
*/
void setup() 
{
  
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) 
  {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  else
  {
    Serial.println("Succes: Initialized ESP-NOW");
  }
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);  //ESP_NOW_ROLE_CONTROLLER is 6
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  //ESP8266 esp_now_add_peer(uint8 mac_addr, uint8 role, uint8 channel, uint8 key, uint8 key_len)
  bool peerInfo = esp_now_add_peer(receiverMacAddress,ESP_NOW_ROLE_CONTROLLER,0,NULL,0);
  
  // Add peer        
  if (peerInfo != 0)
  {
    Serial.println("Failed to add peer");
    return;
  }
  else
  {
    Serial.println("Succes: Added peer");
  } 

  pinMode(SWITCH_PIN, INPUT_PULLUP);   
}

/*
 *****************************************************
 *    REPETICIÓN
 *****************************************************
*/
void loop() 
{
  data.xAxisValue = mapAndAdjustJoystickDeadBandValues(analogRead(X_AXIS_PIN), false);
  data.yAxisValue = mapAndAdjustJoystickDeadBandValues(analogRead(Y_AXIS_PIN), false);  
  data.switchPressed = false; 

  if (digitalRead(SWITCH_PIN) == LOW)
  {
    data.switchPressed = true;
  }

  bool result = esp_now_send(receiverMacAddress, (uint8_t *) &data, sizeof(data));
  //esp_err_t result = esp_now_send(receiverMacAddress, (uint8_t *) &data, sizeof(data));
  if (result == 0) 
  {
    Serial.println("Sent with success");
  }else{
    Serial.println("Error sending the data");
  }
  
  if (data.switchPressed == true)
  {
    delay(500);
  }
  else
  {
    delay(50);
  }
}

 

 

 

 

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^