I'm using an **Arduino Mega 2560** to control a **DRV8871** motor driver connected to a **DC brushed motor**. The setup includes:
- **Three buttons**: UP, DOWN, and FAST
- **One limit switch input**, where the upper and lower limit switches are connected in series
- **PWM speed control** using slow decay, as explained in [this TI forum post](https://e2e.ti.com/support/motor-drivers-group/motor-drivers/f/motor-drivers-forum/715789/drv8871-q1-how-to-pwm-the-driver)
### Goals:
1. **Speed control**: Run the motor at ~30% speed when UP or DOWN is pressed, and ~70% when UP or DOWN is pressed along with FAST.
2. **Acceleration**: Implement a configurable acceleration curve.
3. **Non-blocking code**: Ensure the program does not use `delay()` or block execution.
### Issue:
I wrote the following code: [GitHub link](https://github.com/luigi-pi/headMotor.git). However, when pressing UP or DOWN, the motor makes noise but doesn't move (possibly stalling, even with `PWM = 100`).
Interestingly, if I bypass PWM control and use:
```cpp
digitalWrite(in1Head, HIGH);
analogWrite(in2Head, LOW);
```
the motor runs correctly.
### Questions:
1. Could this issue be due to **incorrect PWM control**?
2. Is the **motor stalling** due to insufficient startup current?
3. Any suggestions for debugging or improving the code?
Any insights would be greatly appreciated!
###update:
I've updated the code trying to follow suggestions. Please let me know if I understood correctly.
1. I put a while loop on the limitswitch. I want that when limitswitch is hit the motor stops, then reverse the direction and disengage the limitswitch moving for the `disengage_ls` time.
```cpp
//Head motor
int in1Head = 44; //on ARDUINO MEGA
int in2Head = 45;
int limSwHead = 19; //2 normally close limit switches connected in series
int FAST = 16; //push button
int UP = 17; //push button
int DOWN = 15; //push button
volatile bool limSwHeadTriggered = false;
// Direction enum and flag
enum Direction { FORWARD, BACKWARD };
Direction currentDirection = FORWARD; // Initialize with default direction
uint8_t PWM_fast =70; //value in % of motor speed
uint8_t PWM_slow =30; //value in % of motor speed
uint8_t PWM = 20; //min value of PWM (to be changed also below)
unsigned long zero = 0;
uint16_t accel_interval = 10;//time in millis to change the speed in acceleration
uint8_t speedIncrease = 5; //% of speed increase for each accel_interval
uint16_t disengage_ls = 500; //time in millis to disangage Limitswitch when hit
boolean fastState = false;
boolean upState = false;
boolean downState = false;
//----FUNCTIONS----------------------------------------------------------------------------------------
//INTERRUPTS
void headISR() {
limSwHeadTriggered = true;
}
void HeadForward(uint8_t PWM) {
analogWrite(in1Head, 255);
analogWrite(in2Head,(255 * (100 - PWM)) / 100); //inverse of the PWM in range 0-255
currentDirection = FORWARD; // Set direction flag
}
void HeadBackward(uint8_t PWM) {
analogWrite(in1Head,(255 * (100 - PWM))/ 100); //inverse of the PWM in range 0-255
analogWrite(in2Head, 255);
currentDirection = BACKWARD; // Set direction flag
}
void HeadStop() {
analogWrite(in1Head,255);
analogWrite(in2Head, 255);
PWM=20;
}
void HeadCoast() {
analogWrite(in1Head,0);
analogWrite(in2Head, 0);
PWM=20;
}
void limSwHit() {
HeadStop();
if(currentDirection == FORWARD){
HeadBackward(PWM_slow);
}
else if (currentDirection == BACKWARD){
HeadForward(PWM_slow);
}
}
void setup() {
Serial.begin(9600);
//head motor
pinMode(in1Head, OUTPUT);
pinMode(in2Head, OUTPUT);
//limitswitch
pinMode(limSwHead, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(limSwHead), headISR, RISING); // Trigger on HIGH signal
//Buttons
pinMode(FAST,INPUT_PULLUP);
pinMode(UP,INPUT_PULLUP);
pinMode(DOWN,INPUT_PULLUP);
}
void loop() {
if(limSwHeadTriggered){
unsigned long initialMillis = millis();
while(millis()- initialMillis<= disengage_ls){
limSwHit();
}
HeadCoast()
limSwHeadTriggered=digitalRead(limSwHead);
}
// read the state of the pushbutton value, inverted due to pullup resistors:
upState = !digitalRead(UP);
downState = !digitalRead(DOWN);
fastState = !digitalRead(FAST);
if (upState && !downState && (millis()- zero >= accel_interval)){
if (PWM < (fastState ? PWM_fast : PWM_slow)) {
PWM += speedIncrease;
}
HeadForward(PWM);
Serial.println("moving up");
zero = millis();
}
else if(!upState && downState && (millis()- zero >= accel_interval)) {
if (PWM < (fastState ? PWM_fast : PWM_slow)) {
PWM += speedIncrease;
}
HeadBackward(PWM);
Serial.println("moving down:");
zero = millis();
}
else{
HeadCoast();
}
}
```