Dc motor with PWM and current sensing

I’m a student on a team developing this project. We are attempting to make a balancing system(by reaction wheel) with current and angle PID control. The whole circuit consists of dc motor(24V, 300w), power supply(up to 30A), current sensor(ina260, up to 15A) and mpu6050(for angle). The process of the system is that angle PID control leads the amount of required current(in the form of duty rate for PWM in Arduino) and it passes current PID control to generate the amount of required torque (to keep it from overcurrent).

Now I am working on the current part. To collect current data, i install a current sensor(ina260) in dc motor + line. But the problem is that the current data should be continuous but the motor is controlled by PWM in the motor driver and so, the data has so many noises followed by the PWM signals( i checked it by plotting on PC). I previous used Acs 758 analog current sensor but I failed to manage this problem)

Is there a good way to filter the current data nicely?

*Pwm setting = 3000hz
*MCU = Arduino Uno
*ina260 (current sensor)
*mpu6050 (angle sensor)
*md30c (motor driver)
*SPG300 (300w dc motor)

[Schematic of system]

[Plotted current data]
(true current value = 0.478A)
image
image

[Code]

#include <Wire.h>               
#include <Adafruit_INA260.h>

Adafruit_INA260 ina260 = Adafruit_INA260();

float Current_data;
float offset = 2.5;
float count1;
float duty = 665;  //duty rate set// range = 0~666  

void setup(){
 currentsetup();
 Timer1_setup();
 pinMode(9, OUTPUT);// PWM output
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user-defined function supplied by attachInterrupt
{
  digitalWrite(2, HIGH);        // Motor direction (HIGH or LOW)
 OCR1A = duty*0.5; //   50% dutyrate
 count1 ++;
}

void loop()
{ 
 Currentloop();
 }

void Timer1_setup() {
   //Fast PWM 3000Hz overflow setting start for motordriver
 noInterrupts();           // disable all interrupts
 TCCR1A = 0;
 TCCR1B = 0;
 TCNT1 = 0;            
 TCCR1A=bit(COM1A1)|bit(COM1B1); //set none-inverted mode
 TCCR1A|=bit(WGM11);
 TCCR1B=bit(WGM12)|bit(WGM13); //set Fast PWMmode using ICR1 as TOP
 TCCR1B|=bit(CS11); //start the timer with  prescaler=8
 ICR1 = 666; //16Mhz/8/3000hz = 666/    
 TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
 interrupts();             // enable all interrupts 
 //Fast PWM 3000Hz setting finish 
}

void currentsetup() {
   Serial.begin(115200);
  // Wait until serial port is opened
  while (!Serial) { delay(10); }
  Serial.println("Adafruit INA260 Test");
  if (!ina260.begin()) 
  {
    Serial.println("Couldn't find INA260 chip");
    while (1);
  }
  Serial.println("Found INA260 chip");
}

void Currentloop(){
  if (count1 > 10)      // slower sammping frequency
  {
  Current_data = ina260.readCurrent() + offset;
  Current_data = Current_data/1000;     // mA -> A
  Serial.print("Current: ");
  Serial.print(Current_data);
  Serial.println(" A");
    if (Current_data > 14*1000)   // Current saturation (ina260 is up to 15A)   
    { 
      duty = 0;       // when closed to max, operating stop
    } 
    count1 = 0;    
  }
}

Welcome, this is an interesting and perplexing problem. I will take a SWAG: The only way you can get a good current value is to read the peak current, time your read when the PWM is on. This is very hard to do with the Arduino, You can use a shunt and a low pass filter in the analog domain and achieve close results. Others will also give you some good suggestions.

Take the signal you get and smooth it.
There are two ways to do this

  1. use an RC filter from the sensor into the analogue reading input.
  2. take a running average over a number of samples.

Thanks for your reply i am so glad.
If Arduino is hard to come by this problem, is it possible to set up ADC resisters in this Arduino Uno(which means Atmega 328)? Or should I be with another microprocessor(ex, Atmega32)?

And current sensors I have are a hall sensor which outputs analog domain and a shunt resister sensor with i2c protocol.
I have not enough knowledge to build a sensor circuit on my own. So that, i would be very pleased if you let me know about how to put RC filter on my shunt current sensor. Or should i buy another sensor working in domain?

So in order to tell you more details, we need more details about your hardware first.
We need a schematic of what you have, a link to exactly what current sensor you use and the code you are trying to use,

Replace the ina260 with a acs713. Its datasheet explains quite clearly what value integration cap you can use. Read the analog output with an adc pin on the microcontroller or an external adc if more resolution is needed.

You can use a lock in amplifier to extract the signal. Expensive to buy but easy to build

I appreciate your clear advice. very thanks.
At your recommendation, I decide to buy ACS713ELCR-20A-T and will make a circuit.
But it is going to be my first time to make it on my own, not by a built-in module.
So that, I wonder the way I am projecting is right or not. please give me some advice about it

First, Specs my system operates is here

  • MCU board = Arduino Uno
  • Arduino PWM = 2000Hz (to follow ACS713 datasheet)
  • Max current = 20A

Second, according to datasheet i need Cf(47nF) and Cout(10nF)

Third, then does my current sensing circuit seem to be (Cf = 47nF / Cout = 10nF) like this?
image

below is typical application datasheet suggests

Thanks for your reply.
Here is a specific schematic of my current sensing system.

and below is my code

#include <Wire.h>               
#include <Adafruit_INA260.h>

Adafruit_INA260 ina260 = Adafruit_INA260();

float Current_data;
float offset = 2.5;
float count1;
float duty = 665;  //duty rate set// range = 0~666  

void setup(){
 currentsetup();
 Timer1_setup();
 pinMode(9, OUTPUT);// PWM output
}

ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user-defined function supplied by attachInterrupt
{
  digitalWrite(2, HIGH);        // Motor direction (HIGH or LOW)
 OCR1A = duty*0.5; //   50% dutyrate
 count1 ++;
}

void loop()
{ 
 Currentloop();
 }

void Timer1_setup() {
   //Fast PWM 3000Hz overflow setting start for motordriver
 noInterrupts();           // disable all interrupts
 TCCR1A = 0;
 TCCR1B = 0;
 TCNT1 = 0;            
 TCCR1A=bit(COM1A1)|bit(COM1B1); //set none-inverted mode
 TCCR1A|=bit(WGM11);
 TCCR1B=bit(WGM12)|bit(WGM13); //set Fast PWMmode using ICR1 as TOP
 TCCR1B|=bit(CS11); //start the timer with  prescaler=8
 ICR1 = 666; //16Mhz/8/3000hz = 666/    
 TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
 interrupts();             // enable all interrupts 
 //Fast PWM 3000Hz setting finish 
}

void currentsetup() {
   Serial.begin(115200);
  // Wait until serial port is opened
  while (!Serial) { delay(10); }
  Serial.println("Adafruit INA260 Test");
  if (!ina260.begin()) 
  {
    Serial.println("Couldn't find INA260 chip");
    while (1);
  }
  Serial.println("Found INA260 chip");
}

void Currentloop(){
  if (count1 > 10)      // slower sammping frequency
  {
  Current_data = ina260.readCurrent() + offset;
  Current_data = Current_data/1000;     // mA -> A
  Serial.print("Current: ");
  Serial.print(Current_data);
  Serial.println(" A");
    if (Current_data > 14*1000)   // Current saturation (ina260 is up to 15A)   
    { 
      duty = 0;       // when closed to max, operating stop
    } 
    count1 = 0;    
  }
}

and I plotted the sensing data
(ture current value = 0.478A)

image

image

I would much appreciate your further advice!

Thank you for your suggestion. But this machine is not affordable to me.

47nF sounds small for a PWM frequency of 2kHz. 2kHz means a period of 500uS, so if you want the RC constant to approximate this, you'd need something like 220nF instead of 47nF (datasheet page 9 bottom left). In fact I'd suggest sampling across more than a single period and use a capacitor of e.g. 470nF.
I personally don't use a capacitor on the output as it offers no benefit over the filter capacitor that this device can use; in fact, it would only degrade performance (see page 12).

Wow! Thanks a ton!!

Then, I'd like to make a circuit like this and choose to prefer cap by the datasheet. is that correct?

[Circuit]
image

[datasheet]

and

In fact I'd suggest sampling across more than a single period and use a capacitor of e.g. 470nF.

what does it mean by?? For this newbie, it's tough to come by...

I have an explanation here

From your data it looks as if simple filtering with a small capacitor as per your circuit above, and averaging repeated measurements will give you a good result.

I'd try to check that but you have posted your readins as an image - can you post them as text?

Absolutely fine! I am so glad for your kindness

Here is the text I corrected!

ina260_current data.zip (8.6 KB)

As you would expect your data shows cyclical variation. I've implemented a simple digital filter (attached) that shows the data converges to a value of around 0.38

excel spreadsheet attached here
ina260_current data.zip (17.4 KB)

Its no surprise that the measurement differs from your "true" value of 0.478 (how did you measure that?)
as you will be aware there are different ways of representing the value of an ac parameter - and your signal is neither a simple dc value nor a simple ac waveform.

Also using a filter (of any type) will delay the availability of the reading which will have an effect on how you implement PID control.

You may wish to look at an analog strategy as described here, followed by a synchronous detector. (AKA lock in amplifier) - but you can easily build such a device,with a few components - you dont need to buy one.

Very thanks!!

as you will be aware there are different ways of representing the value of an ac parameter - and your signal is neither a simple dc value nor a simple ac waveform.

As you can see, my signal has PWM noise I guess. (That's why it creates huge oscillations though DC)

Also using a filter (of any type) will delay the availability of the reading which will have an effect on how you implement PID control.

And Generated delay when I put a filter on the sensor is one of my biggest worries too.
But in fact, i have no idea to deal with it well....

You may wish to look at an analog strategy as described here, followed by a synchronous detector. (AKA lock in amplifier) - but you can easily build such a device,with a few components - you dont need to buy one.

Isn't the way you suggest the same way with using shunt current sensor module??
and can I build a DIY lock - in amp??

Wow... It's so fantastic!!!!

You are so kind and nice! Thank you so much!!!

or use a sample & hold op amp circuit

https://www.analog.com/en/products/lf398n.html#

Some observations:

For good current control a PWM rate of ideally 10kHz or so is a good start, and you should synchronize the measurement of the current with the PWM cycle. The higher
frequency reduces the current ripple, and synchronization should remove the ripple from appearing in the measurements anyway.

Do not low pass filter the current signal. The feedback loop is going to be destabilized if you do this. Low pass filtering introduces delay and delay is the enemy of stability. This is also a reason for high speed sampling of current - reduce any latency in measurement.

Standard approaches to motor control use an inner high-speed current control loop, and the other control loops just set the set-point of the current loop to achieve their output. Outer loops can run slower, perhaps 1kHz, as they only have to deal with mechanical time-constants which are much slower than the electrical time constant of a motor(*).

Say you run at 3kHz as your code suggests, I'd sample in an ISR for timer1 overflow and run the inner PID loop entirely in that ISR.

Here's a really good in depth look at motor control if you want to get deeper into this: https://www.youtube.com/watch?v=fpTvZlnrsP0&t=970s

(*) electrical time constant of a motor is related to the inductance of the windings typically, often around 1ms or so, the time for the current to rise to 63% of stall value on switch-on. Mechanical time-constant relates to the inertia of the motor and is the time to accelerate to 63% of full speed. Typically 100's of ms