Go Down

Topic: Motor PID Position Controller using Magnetic Rotary Encoder (Read 399 times) previous topic - next topic


So I know there's about a thousand of these topics floating around, and I have been reading through as many as I can but I'm still not sure where I'm going wrong with this project.

As in the title I'm building a rotating drum which I need to accurately control the angle of. This angle will eventually need to be >±360 but for now I'm focusing of just getting it working between 0-360.

Due to the small space I have to fit this in DC electric motors are the only feasible option.

I've only been doing this a short time so most of my coding knowledge has come from looking at forums...

I'm just using an Uno with a L298N motor controller and the magnetic sensor is an AMS-AS5048b.

I found a nice header for using the sensor (link) which allows you to just pull the angle between 0-360.

For now I'm just using push buttons to increase or decrease the target angle but my main issue is that the drum just keeps bouncing backwards and forward. I've tried using a wide variety of PID constant values and the problem persists.

I'm not sure if the issue is my arduino code, my pid controller, or hardware.

All help appreciated.

Code: [Select]
/*  Motor PID Controller V1
     Aim: Recieve a position from button presses incrementing 10 degrees. The motor then turns to this angle using
     the position sensor and a pid controller to position itself.

     Hardware: Tested with Arduino Uno, 6v DC electric motor, L298N H_Bridge controller, AMS-AS5048b Magnetic Rotary Encoder.


//Required Headders
#include <PID_v1.h>
#include <ams_as5048b.h>

//Motor Pins
#define EN    9    //Motor Enable(Speed) Pin
#define CW   10
#define CCW  11

//Button Pins
#define Up_Butt 2
#define Dn_Butt 3

int delta = 1;

//Set up AS504b (required constants)
#define U_RAW 1
#define U_TRN 2
#define U_DEG 3
#define U_RAD 4
#define U_GRAD 5
#define U_MOA 6
#define U_SOA 7
#define U_MILNATO 8
#define U_MILSE 9
#define U_MILRU 10

AMS_AS5048B sensor1(0x40); //0x40 is this partiuclar sensors i2c address.

//Set up PID
double Setpoint = 0, Input, Output; //Setpoint = Target, Input = Measured Value, Output = Motor speed??
double Kp = 5, Ki = 1, Kd = 0.01;    //PID Constants (Just guesses at this point)

PID pid1(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup() {

  pinMode(CW, OUTPUT);
  pinMode(CCW, OUTPUT);
  pinMode(EN, OUTPUT);

  pinMode(Up_Butt, INPUT);
  pinMode(Dn_Butt, INPUT);

  sensor1.setZeroReg();   //Current Position is set as 0 angle.

  TCCR1B = TCCR1B & 0b11111000 | 1;  // set 31KHz PWM to prevent motor noise
  pid1.SetMode(AUTOMATIC);   //set PID in Auto mode
  pid1.SetSampleTime(1);  // refresh rate of PID controller
  pid1.SetOutputLimits(-255, 255); // this is the MAX PWM motor value


void loop() {
  //Start by getting target position (setpoint)
  if (digitalRead(Up_Butt) == HIGH) Setpoint = Setpoint + delta;
  if (digitalRead(Dn_Butt) == HIGH) Setpoint = Setpoint - delta;

  //Limit value between 0-360
  if (Setpoint > 360) Setpoint = 360;
  if (Setpoint < 0) Setpoint = 0;

  //Get current angle (input)
  Input = sensor1.angleR(U_DEG, true);

  //Run Pid

  //Send To Motor
  if (Output > 0) {
    analogWrite(EN, abs(Output));
  else if (Output < 0) {
    analogWrite(EN, abs(Output));
  else  {

  //Print Numbers for tracking
  Serial.print("Target Angle:  "); Serial.print(Setpoint);
  Serial.print("   Measured Angle:   "); Serial.print(Input);
  Serial.print("   Calculated Motor Speed:   "); Serial.println(Output);

/////////Motor Control////////////
void clockwise() {
  digitalWrite(CW, HIGH);
  digitalWrite(CCW, LOW);

void anticlockwise() {
  digitalWrite(CW, LOW);
  digitalWrite(CCW, HIGH);

void motor_off() {
  digitalWrite(CW, LOW);
  digitalWrite(CCW, LOW);

Go Up