Go Down

Topic: PWM output to Motor Shield messes with AnalogRead (Read 247 times) previous topic - next topic

maho12345

Hello everyone

I have an Arduino Mega 2560 R3 connected to an Arduino Motor Shield Rev3. I use PWM to control the transistors of the H-bridge which in turn control a DC motor turning a pump that is powered externally (I cut the jumper on the Arduino Motor Shield). Furthermore, I use a flow meter that outputs 4 to 20 mA depending on the flow it measures. I connected a 200 ohms resistor to this current output giving me a voltage between 0.8 and 4 V depending on the flow (according to Ohm's law). This is the voltage I measure at the Arduino AnalogRead pin. I use the flow meter value for feedback control as I want to control the volume that is displaced by the pump. The entire implementation takes place in Matlab Simulink running the Arduino support package, however the same issue I encounter can be reproduced in the normal Arduino IDE.

My issue is as follows:
Every time I change the duty cylce of the PWM signal (for example from 0 to 255) I see a jump in voltage at the AnalogRead pin from the flow meter, even though the pump is not connected, i.e. the flow is still 0 ml/s. So essentially, it suddenly reports a flow of 4 ml/s (although it was 0 ml/s before). Again, the pump is not running, so the fluid is stationary and therefore the measurement of the flow meter should not change. The flow meter can also connect via USB to the computer and the flow can be viewed in the manufacturer's software. In the manufacturer software I don't see this jump in measurement upon applying a different PWM duty cycle. However, I cannot use the data from the manufacturer software as there exists no protocol for Simulink.


What I've tried to resolve the issue:
- using different AnalogRead pins
- using different PWM pins
- Connecting the DC minus of the sensor to the ground of the arduino and then to the ground of the DC power supply I use for the pumps, to avoid having a floating ground somewhere (am not totally sure if I did it correctly, but I saw no effect, no matter how I changed the ground)
- Disconnecting the motor shield from the arduino mega board and running the same code: Then the PWM signal is just at the pin and switches its voltage at 490Hz or so but the transistors of the shield are not switching: this resolved the issue, however I must run the motor shield at the same time to control the pump

Does anybody have an idea how I could resolve this issue? I think the DigitalWrite messes with the AnalogRead somehow, so I might need to use an RC filter somwher, however I don't know exactly where this filter would be needed since I have not identified the problem source yet.

Any help would be highly appreciated and please let me know if any other information is needed.

Thanks,
maho12345

sterretje

#1
May 23, 2020, 06:28 pm Last Edit: May 23, 2020, 06:30 pm by sterretje
Possibly because non-connected inputs are floating and any reading of a floating input can give random numbers. in this case they will probably pick up interference form the motor.

Connect the analogue input in turn to GND, 3.3V and 5V and run your tests again; you should get steady readings (within the specs of the ADC).
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

maho12345

#2
May 23, 2020, 06:51 pm Last Edit: May 23, 2020, 06:52 pm by maho12345
Thanks a lot for your input. Just run a test with the following result

PWM = 255
GND reads 0
3.3V reads 699-700
5V reads 1023
Sensor reads 514

PWM = 0
GND reads 0
3.3V reads 696
5V reads 1023
Sensor reads 511

Although the mismatch is not big, it is definitely there (also for the 3.3V). Might my board be faulty?

The annoying thing is also that a jump of only 1 in the sensor data corresponds to almost 2ml/s. Therefore, I cannot have a changing value, i.e. it must be very steady.

How would I go about solving the issue you mention about the floating, non-connected inputs?

Thanks

maho12345

#3
May 23, 2020, 07:40 pm Last Edit: May 23, 2020, 08:54 pm by maho12345
I could not resolve the actual issue but could increase the sensitivity of my signal. Now a flow change of 1ml/s corresponds to around 25, therefore the change by 2 or 3 caused by the PWM is no longer an issue. Therefore, I will no longer persue the issue.

Thanks

DrDiettrich

Better use the internal ADC reference (1.1V) in order to become independent of the 5V supply voltage. Use voltage dividers to bring down the 3.3V and 5V signals below 1.1V. Also adjust the current shunt to about 1.1/20m ~ 50-56 Ohm.

Take care to route the current loop GND directly to the Arduino (ADC) GND without further branch-off's. Connect all GND directly to the Arduino (star topology) except the motor power supply should be connected directly and only to the motor driver board.

The industry grade 4-20mA current loop is very reliable and insensitive to interference. If you see such a value jump around you have a problem somewhere else in your wiring.

johnwasser

Code: [Select]
// Here is a trick that allows you to check the power rail voltage against the 1.1V +/- 10% internal reference.
// Run the sketch, send 'R' and use a good meter to measure the voltage on the AREF pin.  Put the measured
// voltage in millivolts (should be between 1000 and 1200) into the sketch as 'InternalReferenceMillivolts'.  
// Run the sketch again and send 'V' to read the current "+5V" voltage (should be around 5000 mV).  Compare 
// that to the voltage measured at the +5V pin.  If the answer is not close enough, adjust the 
// InternalReferenceMillivolts to get a closer result.
//
// Now you can use "(getVccMillivolts()/1000.0)" in place of "5.0" in your sketch to get analog readings less
// dependent on fluctuations in the Vcc line.


void setup() {
  Serial.begin(115200);
  while (!Serial); // Wait for USB connection on Leonardo/Micro


  delay(1000);
  Serial.println("Send 'R' to measure reference voltage at AREF pin.");
  Serial.println("Send 'V' to measure supply voltage.");
}


void loop() {
  switch (Serial.read()) {
    case 'r':
    case 'R':
      analogReference(INTERNAL);
      delay(500);
      Serial.println("Now measure the voltage at the AREF pin.");
      Serial.println("Put that value in this sketch as InternalReferenceMillivolts.");
      break;


    case 'v':
    case 'V':
      analogReference(DEFAULT);

      Serial.print("Power rail (millivolts): ");
      Serial.println(getVccMillivolts());
      break;
  }
}


/*VVVVVVVVVVVVV  The part below here goes into your sketch  VVVVVVVVVVVV*/


// Adjust this value to your boards specific internal BG voltage in millivolts
const unsigned long InternalReferenceMillivolts = 1080UL;


// Returns actual value of Vcc in millivolts
int getVccMillivolts() {
  // Set the analog reference to DEFAULT (AVcc == Vcc power rail)
  // REFS1 REFS0          --> 0b01   -Selects DEFAULT (AVcc) reference
  // Set the analog input to channel 14: the INTERNAL bandgap reference (1.1V +/- 10%)
  // MUX3 MUX2 MUX1 MUX0  --> 0b1110 -Selects channel 14, bandgap voltage, to measure
  ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
  
  delay(50);  // Let mux settle a little to get a more stable A/D conversion


  // Start a conversion to measure the INTERNAL reference relative to the DEFAULT (Vcc) reference.
  ADCSRA |= _BV( ADSC );
  // Wait for it to complete
  while (ADCSRA & (1 << ADSC));


  // Calculate the power rail voltage (reference voltage) relative to the known voltage
  return (InternalReferenceMillivolts * 1024UL) / ADC;
}
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

sterretje

The annoying thing is also that a jump of only 1 in the sensor data corresponds to almost 2ml/s. Therefore, I cannot have a changing value, i.e. it must be very steady.

How would I go about solving the issue you mention about the floating, non-connected inputs?
1)
ADCs have an accuracy; you will have to live with that. You can divide the reading by 2 or 4 to get rid of the deviation in readings.

2)
Don't read floating inputs; your initial test was flawed because nothing was connected to the input.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

DrDiettrich

Don't read floating inputs; your initial test was flawed because nothing was connected to the input.
A 200 Ohm resistor is not floating at all.

sterretje

OOPS, must have misunderstood the opening post.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

maho12345

Thank you everyone for your answers. As soon as I need more measuring accuracy I might change to the interal reference. I will also try to redirect the GND in the star topology.

For my purpose, I resolved the issue to an extent that it's useable. Also, I figured that I can resolve the issue by adding a certain gain to the AnalogRead value depending on the PWM cycle. Maybe not the best solution to hard code like that, but might work for somebody else experiencing this.

Wawa

Don't see a (required) schematic diagram, pictures, or code.

I guess you did not switch to one of the stable internal references of the A/D.
The Mega has a 2.56volt reference, so you should use a 120 ohm sense resistor for that 4-20mA sensor.
Of course with surrounding pin protection parts.

I also assume you didn't use A0-A3, because that motor shield is using them for motor current feedback.
Leo..

maho12345

Hi

Please find a drawing I made of the setup attached.

The code I use is as follows

Code: [Select]


void setup() {
 
  Serial.begin(9600);
 
  pinMode(12,OUTPUT);
  digitalWrite(12, HIGH);
  analogWrite(3, 255); //PWM value changes the analogRead
  delay(1000);
}

void loop() {
  float current = analogRead(A5);
  Serial.println(current);
  delay(5);
}

Go Up