效果:
https://weixin.qq.com/sph/AAt2I3ZAP
硬件接线参考:

L298N模块两边连接两个电机,输入12V与GND,5V输出不用连接

Arduino 5V 接JoyStick5V
Arduino GND 接L298N的GND及JoyStick的GND
Arduino VIN 接 电池输入12V
A0,A1分别接JoyStick的JRX,JRY
Arduino 的4,5,6,7 分别接L298N 的IN4,IN3,IN2,IN1
Arduino 的9,10分别接L298N的ENA,ENB




公共点接入电源的正负极,橙色12V,黑色GND

Arduino USB连接电脑,用于写入控制程序

电池准备3个18650 3.7V的

通电写入程序后,JoyStick可控制电机前进,后退,左右转,停止

UNO_L298N_JOYSTICK.ino
/*
* Arduino UNO + L298N + Joystick 控制双直流电机
* 引脚配置(更新版):
* 电机A:ENA=D9, IN1=D4, IN2=D5
* 电机B:ENB=D10, IN3=D6, IN4=D7
* 摇杆:VRx=A0, VRy=A1
*/
// ============= L298N引脚定义(更新) =============
// 电机A(左侧电机)
const int ENA = 9; // PWM速度控制 - D9
const int IN1 = 4; // 方向1 - D4
const int IN2 = 5; // 方向2 - D5
// 电机B(右侧电机)
const int ENB = 10; // PWM速度控制 - D10
const int IN3 = 6; // 方向1 - D6
const int IN4 = 7; // 方向2 - D7
// ============= 摇杆引脚定义 =============
const int JOYSTICK_X = A0; // X轴 - 左右转向
const int JOYSTICK_Y = A1; // Y轴 - 前后移动
const int JOYSTICK_BUTTON = 2; // 摇杆按钮(可选)
// ============= 全局变量 =============
int xValue = 0; // 摇杆X轴值 (0-1023)
int yValue = 0; // 摇杆Y轴值 (0-1023)
int xMapped = 0; // 映射后的X值 (-255到255)
int yMapped = 0; // 映射后的Y值 (-255到255)
int deadZone = 15; // 死区范围,防止摇杆微小漂移
int maxSpeed = 200; // 最大速度(PWM值),锂电池11V建议不超过200
// ============= 初始化设置 =============
void setup() {
Serial.begin(115200);
// 设置L298N引脚为输出
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// 特别注意:D10需要设置PWM频率,防止电机啸叫
// 调整PWM频率为31.25kHz(可选,如电机有噪音可启用)
// setPWMFrequency10();
// 设置摇杆按钮(如果使用)
pinMode(JOYSTICK_BUTTON, INPUT_PULLUP);
// 初始停止电机
stopMotors();
Serial.println("=== L298N + Joystick 控制系统 ===");
Serial.println("引脚配置:");
Serial.println(" 电机A: ENA=9, IN1=4, IN2=5");
Serial.println(" 电机B: ENB=10, IN3=6, IN4=7");
Serial.println(" 摇杆: X=A0, Y=A1");
Serial.println("摇杆控制说明:");
Serial.println(" ↑ 向前推:前进");
Serial.println(" ↓ 向后拉:后退");
Serial.println(" ← 向左推:左转");
Serial.println(" → 向右推:右转");
Serial.println(" ○ 松开:停止");
Serial.println("================================");
}
// ============= 主循环 =============
void loop() {
// 1. 读取摇杆值
readJoystick();
// 2. 处理控制逻辑
processJoystickControl();
// 3. 检查摇杆按钮(紧急停止)
checkJoystickButton();
// 4. 显示调试信息(每秒显示一次)
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 1000) {
debugOutput();
lastPrint = millis();
}
// 5. 小延迟稳定读取
delay(15);
}
// ============= 摇杆读取函数 =============
void readJoystick() {
// 读取原始值(多次采样取平均,减少噪声)
int xSum = 0, ySum = 0;
for (int i = 0; i < 3; i++) {
xSum += analogRead(JOYSTICK_X);
ySum += analogRead(JOYSTICK_Y);
delay(2);
}
xValue = xSum / 3;
yValue = ySum / 3;
// 映射到-255到255范围
// 注意:摇杆原始值中间位置通常是512,但不同摇杆可能不同
xMapped = map(xValue, 0, 1023, 255, -255); // 注意:有的摇杆需要反转
yMapped = map(yValue, 0, 1023, -255, 255); // Y轴:向前推是负值,向后拉是正值
// 应用死区,防止微小漂移
if (abs(xMapped) < deadZone) xMapped = 0;
if (abs(yMapped) < deadZone) yMapped = 0;
}
// ============= 摇杆控制逻辑 =============
void processJoystickControl() {
// 情况1:摇杆在中心位置 - 停止
if (xMapped == 0 && yMapped == 0) {
stopMotors();
return;
}
// 计算速度和转向的合成
int forwardSpeed = yMapped; // Y轴控制前后
int turnSpeed = xMapped; // X轴控制转向
// 差速转向计算
int leftSpeed = forwardSpeed + turnSpeed;
int rightSpeed = forwardSpeed - turnSpeed;
// 限制最大速度
int maxOutput = maxSpeed;
leftSpeed = constrain(leftSpeed, -maxOutput, maxOutput);
rightSpeed = constrain(rightSpeed, -maxOutput, maxOutput);
// 控制电机
controlMotorA(leftSpeed);
controlMotorB(rightSpeed);
}
// ============= 电机控制函数 =============
// 控制电机A(左侧)
void controlMotorA(int speed) {
speed = constrain(speed, -maxSpeed, maxSpeed);
if (speed > 0) {
// 正转
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, speed);
} else if (speed < 0) {
// 反转
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, -speed);
} else {
// 停止
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
analogWrite(ENA, 0);
}
}
// 控制电机B(右侧)
void controlMotorB(int speed) {
speed = constrain(speed, -maxSpeed, maxSpeed);
if (speed > 0) {
// 正转
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENB, speed);
} else if (speed < 0) {
// 反转
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENB, -speed);
} else {
// 停止
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENB, 0);
}
}
// 简化控制函数(兼容旧代码)
void forward(int speedVal) {
speedVal = constrain(speedVal, 0, maxSpeed);
controlMotorA(speedVal);
controlMotorB(speedVal);
}
void backward(int speedVal) {
speedVal = constrain(speedVal, 0, maxSpeed);
controlMotorA(-speedVal);
controlMotorB(-speedVal);
}
void turnLeft(int speedVal) {
speedVal = constrain(speedVal, 0, maxSpeed);
controlMotorA(-speedVal); // 左轮后退
controlMotorB(speedVal); // 右轮前进
}
void turnRight(int speedVal) {
speedVal = constrain(speedVal, 0, maxSpeed);
controlMotorA(speedVal); // 左轮前进
controlMotorB(-speedVal); // 右轮后退
}
// 停止所有电机
void stopMotors() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
// 紧急刹车
void brakeMotors() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, 255); // 快速放电
analogWrite(ENB, 255);
delay(50);
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
// ============= 辅助函数 =============
// 检查摇杆按钮(紧急停止)
void checkJoystickButton() {
if (digitalRead(JOYSTICK_BUTTON) == LOW) {
Serial.println("[紧急停止] 摇杆按钮被按下!");
brakeMotors();
delay(1000); // 锁定1秒防止误触
}
}
// 调试信息输出
void debugOutput() {
Serial.print("摇杆: X=");
Serial.print(xValue);
Serial.print("(");
Serial.print(xMapped);
Serial.print(") Y=");
Serial.print(yValue);
Serial.print("(");
Serial.print(yMapped);
Serial.println(")");
// 读取电机使能引脚状态(调试用)
int enaState = digitalRead(ENA) ? 255 : 0;
int enbState = digitalRead(ENB) ? 255 : 0;
Serial.print("ENA:");
Serial.print(enaState);
Serial.print(" ENB:");
Serial.println(enbState);
}
// 调整D10的PWM频率(减少电机噪音)
void setPWMFrequency10() {
// 设置Timer1的PWM频率为31.25kHz(用于D9,D10)
// 注意:这会影响millis()和delay()的精度
TCCR1A = 0b00000001; // 8位相位修正PWM
TCCR1B = 0b00000001; // 无预分频
}
833

被折叠的 条评论
为什么被折叠?



