采用ESP-NOW实现遥杆控制小车

采用ESP-NOW实现遥杆控制小车

这篇教程会向你展示如何在家中用基础电子零件制作一辆用摇杆控制小车的示例。

废话不多说,先上效果
在这里插入图片描述

车子可以通过遥杆来控制,而且不只限于4个方向。这是一个对于初学者来说非常有趣的项目,占用的完成时间不会很多,通过它不仅可以学习到如何搭建车辆,还可以了解电机对车辆工作的作用,以及一些基本的电子知识、编程实践,甚至一些物理知识。

本篇文章采用ESP-NOW,如果又不懂的小伙伴可以看我的另外一篇文章,传送门:采用ESP-NOW实现ESP32/ESP8266之间的通信
在这里插入图片描述

整辆机器人车的电路图如教程所示,没有使用面包板,而是直接使用跳线在组件之间进行连接。

建立连接之前,确保将电池的地线连接到马达驱动器和ESP8266的GND。电池盒的电池正极连接到马达驱动器的9v插槽,马达驱动器的5v连接到ESP8266板的Vin现在,马达驱动器和ESP8266之间的通信连接如下:

ENA   14          // Enable/speed motors Right        GPIO14(D5)
ENB   12          // Enable/speed motors Left         GPIO12(D6)
IN_1  15          // L298N in1 motors Right           GPIO15(D8)
IN_2  13          // L298N in2 motors Right           GPIO13(D7)
IN_3  2           // L298N in3 motors Left            GPIO2(D4)
IN_4  0           // L298N in4 motors Left            GPIO0(D3)

最后,我们把BO电动机的连线的接口连接到马达驱动器上的电动机连接插槽。这样,马达驱动器就可以控制BO马达的运转了。

esp32代码

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

#define X_AXIS_PIN 32
#define Y_AXIS_PIN 33
#define SWITCH_PIN 15

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x2C,0xF4,0x32,0x13,0x38,0x50};

// Structure example to send data
// Must match the receiver structure
typedef struct PacketData
{
  byte xAxisValue;
  byte yAxisValue;
  byte switchPressed;
};
PacketData data;

esp_now_peer_info_t peerInfo;

/*此功能用于将0-4095操纵手柄值映射到0-254。因此127是我们发送的中心值。

*它还可以调整操纵手柄中的死区。

*Jostick值的范围为0-4095。但它的中心值并不总是2047。这没什么不同。

*所以我们需要在中心值上加一些死区。在我们的案例中是1800-2200。在这个死区范围内的任何值都被映射到中心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");
}
 
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
 
  // Set device as a Wi-Fi Station
  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");
  }

  //一旦ESPNow成功初始化,我们将注册发送CB到
  //获取Trasnmitted数据包的状态
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 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);   
}
 
void loop() {
  // Set values to send
  data.xAxisValue = mapAndAdjustJoystickDeadBandValues(analogRead(Y_AXIS_PIN), false);
  data.yAxisValue = mapAndAdjustJoystickDeadBandValues(analogRead(X_AXIS_PIN), false);  
  data.switchPressed = false; 
  if (digitalRead(SWITCH_PIN) == LOW)
  {
    data.switchPressed = true;
  }
  Serial.println((String)"x:" + data.xAxisValue + " y:"+ data.yAxisValue + " btn:"+ data.switchPressed);

  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (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);
  }
}

在这里插入图片描述
烧录之后会自动打印摇杆值,当拨动摇杆,x、y值会变化,按下摇杆,btn置为1
在这里插入图片描述

注意,笔者这里Message failed是应为笔者关闭了小车,如果开启了小车电源,则提示Success

esp8266代码

#include <ESP8266WiFi.h>
#include <espnow.h>

//Right motor
int enableRightMotor=14; 
int rightMotorPin1=15;
int rightMotorPin2=13;
//Left motorvv
int enableLeftMotor=12;
int leftMotorPin1=2;
int leftMotorPin2=0;

#define MAX_MOTOR_SPEED 1023 // 400 - 1023.

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

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

int speed_Coeff = 3;

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

bool throttleAndSteeringMode = false;

// 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();   
}

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);
  }   
}

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);
}

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, rightMotorSpeed/speed_Coeff);
  analogWrite(leftMotorPWMSpeedChannel, leftMotorSpeed/speed_Coeff);   
}

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

  digitalWrite(rightMotorPin1, LOW);
  digitalWrite(rightMotorPin2, HIGH);
  analogWrite(enableRightMotor, MAX_MOTOR_SPEED);

  digitalWrite(leftMotorPin1, LOW);
  digitalWrite(leftMotorPin2, HIGH);
  analogWrite(enableLeftMotor, MAX_MOTOR_SPEED);

  rotateMotor(0, 0);
}


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);
}
 
void loop() 
{
  //Check Signal lost.
  unsigned long now = millis();
  if ( now - lastRecvTime > SIGNAL_TIMEOUT ) 
  {
    rotateMotor(0, 0);
  }
}

  • 18
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值