DC Motor Angle Control with H-bridge and Arduino

Hi all!

I’m using this video from DroneBot Workshop that allows for sensing the DC motor RPM with a rotary encoder(attached to the DC motor). It measures the RPM of the motor, and it reflects the value changing as you physically try to stop the motor from turning.

I’ve been trying to create a program that works on angle control, similar to this video that uses PID. I’m not necessarily invested in using PID but was wondering what steps I should take if I just want to control the angle (set it to a specific value).

I’d ideally want it to act as a sort of control system in the sense that if I move the DC motor shaft, it would try to return to the original angle set. My current thinking is creating a program that would constantly compare the actual angle value to the set value and if it’s less than the set value then increase it (rotate CW), and if it’s greater than the set value then decrease it (rotate CCW).

I have attached the setup I have at the moment (from the DroneBot Workshop video).

Thank you all!

Is there something you wanted help with?

I would start with the sketch from the video and remove the PID library:

const byte MotEnable = 6; //Motor Enamble pin Runs on PWM signal
const byte MotFwd = 4;  // Motor Forward pin
const byte MotRev = 7; // Motor Reverse pin


int User_Input = 0; // This while convert input string into integer


const byte  encoderPin1 = 2; //Encoder Output 'A' must connected with intreput pin of arduino.
const byte  encoderPin2 = 3; //Encoder Otput 'B' must connected with intreput pin of arduino.
volatile int lastEncoded = 0; // Here updated value of encoder store.
volatile long encoderValue = 0; // Raw encoder value
const int PPR = 1600;  // Encoder Pulse per revolution.
int angle = 360; // Maximum degree of motion.
int REV = 0;          // Set point REQUIRED ENCODER VALUE
int lastMSB = 0;
int lastLSB = 0;


// double kp = 5 , ki = 1 , kd = 0.01;             // modify for optimal performance
// double input = 0, output = 0, setpoint = 0;
int input = 0, output = 0, setpoint = 0;


void setup()
{
  pinMode(MotEnable, OUTPUT);
  pinMode(MotFwd, OUTPUT);
  pinMode(MotRev, OUTPUT);
  Serial.begin(9600); //initialize serial comunication


  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);


  //call updateEncoder() when either pin changes
  attachInterrupt(digitalPinToInterrupt(encoderPin1), updateEncoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encoderPin2), updateEncoder, CHANGE);

  TCCR1B = (TCCR1B & 0b11111000) | 1;  // set 31KHz PWM to prevent motor noise
}


void loop()
{
  if (Serial.available())   //Check if the serial data is available.
  {
    User_Input = Serial.parseInt();
    while (Serial.available())
      Serial.read(); // Empty the remainder of the input buffer


    REV = map (User_Input, 0, 360, 0, PPR); // mapping degree into pulse


    Serial.print("this is REV - ");
    Serial.println(REV);               // printing REV value
  }


  setpoint = REV;               // PID while work to achive this value consider as SET value


  Serial.print("encoderValue - ");
  Serial.println(encoderValue);
  input = encoderValue;         // data from encoder consider as a Process value


  // Simple proportional control
  output = constrain(setpoint - input, -255, 255);




  if (output == 0)
  {
    finish();  // Stop
  }
  else if (output > 0)  // if setpoint > input, move in forward direction.
  {
    analogWrite(MotEnable, output);
    forward();
  }
  else    // if setpoint < input, move in reverse direction.
  {
    analogWrite(MotEnable, -output);
    reverse();
  }
}


void updateEncoder()
{
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit


  int encoded = (MSB << 1) | LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value


  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;


  lastEncoded = encoded; //store this value for next time
}


void forward ()
{
  digitalWrite(MotFwd, HIGH);
  digitalWrite(MotRev, LOW);
}


void reverse ()
{
  digitalWrite(MotFwd, LOW);
  digitalWrite(MotRev, HIGH);
}


void finish ()
{
  digitalWrite(MotFwd, LOW);
  digitalWrite(MotRev, LOW);
}

I have tried Johnwasser sketch but unfortunately, my input controls speed not degree.

There is only one signal wire from encoder. How would you know which way the motor turned?