Help reading analog pins

Hi

I have an Arduino Yun and I want to connect a radio receiver to it.
I only have the analog pins left, but my problem happens with both analog pins AND PWM pins (tried both ways).

When I use pulseIn to read the values, I get oscillations (for example when my joystick is in the 0 position, values oscillate around 1045, but with a difference +- 50... which is pretty big).
Does anyone know how can I get rid of these oscillations? :slight_smile:

Thank you

I only have the analog pins left, but my problem happens with both analog pins AND PWM pins (tried both ways).

The analog pins are just analog if they are inputs and PWM is only an output functionality. Please define how you want to use them as a replacement.

When I use pulseIn to read the values, I get oscillations (for example when my joystick is in the 0 position, values oscillate around 1045, but with a difference +- 50... which is pretty big).

How do you read a joystick with pulseIn()? Please post a wiring diagram.

the joystick is from a radio remote. it is connected to a radio receiver, which has channels 1,2,3,4 plugged into arduino's ports A0, A1, A2, A3.

Right now I am focusing on port A2. When I use pulseIn(A2,HIGH,25000) I print the values in a serial monitor. I'll paste them over here:

Throttle: 1016
Throttle: 1016
Throttle: 1012
Throttle: 1018
Throttle: 1041
Throttle: 1026
Throttle: 1020
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1044
Throttle: 1036
Throttle: 1043
Throttle: 1035
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1044
Throttle: 1043
Throttle: 1041
Throttle: 1044
Throttle: 1041
Throttle: 1043
Throttle: 1027
Throttle: 1026
Throttle: 1024
Throttle: 1018
Throttle: 1043
Throttle: 1018
Throttle: 1018
Throttle: 1044
Throttle: 1018
Throttle: 1018
Throttle: 1043
Throttle: 1027
Throttle: 1027
Throttle: 1044
Throttle: 1037
Throttle: 1044
Throttle: 1036
Throttle: 1043
Throttle: 1044
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1044
Throttle: 1041
Throttle: 1044
Throttle: 1043
Throttle: 1043
Throttle: 1043
Throttle: 1033
Throttle: 1043
Throttle: 1044
Throttle: 1044
Throttle: 1043
Throttle: 1041
Throttle: 1043
Throttle: 1027
Throttle: 1027
Throttle: 1043
Throttle: 1018
Throttle: 1018
Throttle: 1043
Throttle: 1018
Throttle: 1018
Throttle: 1044
Throttle: 1018

This is WITHOUT moving the joystick. I need values to be stable...

forgot to mention that my receiver has 1000us pulse on it's lowest position and 2000us on highest.

Sounds like the hardware is not able to produce more precision. Can you draw a wiring diagram and provide links to the used hardware? Also post your sketch.

can't draw it right now..

but it's rather simple.. 1 cable connecting the receiver from 5V, one from GND, and one from it's channel to A2.

The hardware IS capable of accurate values. The problem is with reading the information.
I think it is something related to this RCArduino: How To Read an RC Receiver With A Microcontroller - Part 1

but I would like to find a more simple solution...

The hardware IS capable of accurate values. The problem is with reading the information.
I think it is something related to this RCArduino: How To Read an RC Receiver With A Microcontroller - Part 1

I don't think that your problem is related to this. They don't say that pulseIn() is not accurate but that it wastes a lot of resources (what it does). In your case it may be sometimes interrupted by the Timer0 interrupt (counting milliseconds). You can try using noInterrupts() and interrupts() around your pulseIn() call.

How accurate is your hardware? 1%, 5%, 0.1%?

Thanks a lot!!!! Owe ya one :smiley:

It worked by surrounding with noInterrupts() and interrupts() !!!

got into some other trouble...

Now if i'm surrounding that part of the code with "noInterrupts()" and "interrupts()", I can't command any servos (even if the code for the servos is outside the interrupts part)...
Why is that?

Because that code probably relies on the interrupts. If you're disabling interrupts for more than 1 millisecond the PWM signal for the servos is not generated as it should.

I guess you should post your complete sketch, maybe we have another solution for you that better fits your needs. Also post the wiring diagram.

#include <Servo.h>

Servo m1;
int ch1;

void setup() {

m1.attach(5);
Serial.begin(115200);
}

void loop()
{
getValues();
comanda_THROTTLE = to100(ch1);    //to100 is a function so I can see a percentage of the command I send

Serial.print("Throttle: "); Serialprintln(comanda_THROTTLE);
m1.write(toMotor(comanda_THROTTLE)); //toMotor is the command, scaled in the motor range (50-125)
}


void getValues()
{
ch1 = pulseIn(A0,HIGH,25000);
}

int to100(int a)
{
return map(a, 1056, 1885, 0, 100);
}

int toMotor(int a)
{
return map(a, 0, 100, 50, 125);
}

If I use the noInterrupt in my getValues() function, then I can read the values perfectly, but my servo won't work anymore.
Is there a way to use pulseIn with another timer than the one used by the interrupts?

no one?...nothing?

Is there a way to use pulseIn with another timer than the one used by the interrupts?

pulseIn() doesn't use a timer. It waits for the state to change or for millis() to have advance far enough. Since millis() doesn't advance when you have interrupts disabled, it's hard to believe that disabling interrupts allows pulseIn() to work. Not hard, actually. Impossible. Unless the thing that enables pulseIn() to return is that the signal actually changes.

Turning interrupts off disables servo pulses, so it's no surprise that the servo doesn't move.

So, why are you turning interrupts off?

PaulS:
So, why are you turning interrupts off?

I only just read the thread, but I believe it is because he believes that interrupts are causing the times returned by pulseIn() to be inaccurate.

And pulseIn() does not use millis(). It counts clock cycles and converts to microseconds. The source is below. I think it should still work with noInterrupts(). I know that micros() still works with interrupts disabled, so I don't see why not.

/*
  wiring_pulse.c - pulseIn() function
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2005-2006 David A. Mellis

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA

  $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/

#include "wiring_private.h"
#include "pins_arduino.h"

/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
 * or LOW, the type of pulse to measure.  Works on pulses from 2-3 microseconds
 * to 3 minutes in length, but must be called at least a few dozen microseconds
 * before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
	// cache the port and bit of the pin in order to speed up the
	// pulse width measuring loop and achieve finer resolution.  calling
	// digitalRead() instead yields much coarser resolution.
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);
	uint8_t stateMask = (state ? bit : 0);
	unsigned long width = 0; // keep initialization out of time critical area
	
	// convert the timeout from microseconds to a number of times through
	// the initial loop; it takes 16 clock cycles per iteration.
	unsigned long numloops = 0;
	unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
	
	// wait for any previous pulse to end
	while ((*portInputRegister(port) & bit) == stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to start
	while ((*portInputRegister(port) & bit) != stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to stop
	while ((*portInputRegister(port) & bit) == stateMask) {
		if (numloops++ == maxloops)
			return 0;
		width++;
	}

	// convert the reading to microseconds. The loop has been determined
	// to be 20 clock cycles long and have about 16 clocks between the edge
	// and the start of the loop. There will be some error introduced by
	// the interrupt handlers.
	return clockCyclesToMicroseconds(width * 21 + 16); 
}

trika03:
no one?...nothing?

I believe that PWM requires timers, and timers are disabled when you call noInterrupts(). I think you will need to come up with some other solution. For example:

NoInterrupts()
Read from receiver
Interrupts()
Output PWM values

The problem, I think, is that your PWM outputs will stop during the noInterrupts() period, which will make your servos behave oddly. You may be able to get around this with an external PWM generation IC that you interface via I2C or something. That way the PWM signals to the servos will continue to be generated while the Arduino "goes away" to read from the receiver, and you can update the values when the Arduino "comes back". As long as you can read and update fast enough, you should get usable precision. For example, your pulses in your example below are about 1 ms long. If you were reading four channels, it would take minimum 4 ms, realistically maybe 10 ms on the outside to finish the read. This would give you approximately 100 Hz update frequency to your servos.

Disclaimer: I'm not an expert on interrupts, timers, or servos, but since you were starving for an answer, I thought I'd do my best. If I'm wrong, hopefully that will "inspire" someone else to pop up and correct me.

Also, if you are feeling ambitious, you could try to solve this problem in the analog domain, with something like this:

Then just analogRead() and Bob's your uncle. This approach would probably be non-trivial to actually implement, for the average Arduino hobbyist, but I did want to point out that it's available.

The radio signals seem to be standard RC servo signals. Can you access the signal before it is divided into 4 separate streams. That is how they would be sent from the originating transmitter. That would allow you to read all the pulses on a single pin and would allow you to write your own interrupt code to measure them if pulseIn() isn't suitable. I wrote some code to identify model railway DCC signals and it relied on using a specific pin that triggers interrupts so that it would not be possible to use that technique for multiple signals. I think it could be amended for your purpose.

Perhaps you could multiplex the 4 pulses with a few logic gates - maybe they "accidentally" retain the channel spacing that would have been in the transmitted multiplexed signal.

...R

PaulS:

Is there a way to use pulseIn with another timer than the one used by the interrupts?

pulseIn() doesn't use a timer. It waits for the state to change or for millis() to have advance far enough. Since millis() doesn't advance when you have interrupts disabled, it's hard to believe that disabling interrupts allows pulseIn() to work. Not hard, actually. Impossible. Unless the thing that enables pulseIn() to return is that the signal actually changes.

Turning interrupts off disables servo pulses, so it's no surprise that the servo doesn't move.

So, why are you turning interrupts off?

Turning interrupts off and then on actually helped for the PulseIn function. My input was clear, with no oscillations.

Thank you for your answers.
I wanted to clarify that using noInterrupts(), code, Interrupts() actually WORKS for my receiver signal, but messes up my PWM command to the servos.

I want to find a way to read my input without messing the other stuff up (maybe use another timer and do something similar to pulseIn() ?? ).

I'm looking for ideas online, but I haven't found anything useful yet... I refuse to believe that I'm the only one who's trying to make an RC device using Arduino.

If I use the noInterrupt in my getValues() function, then I can read the values perfectly, but my servo won't work anymore.
Is there a way to use pulseIn with another timer than the one used by the interrupts?

You can use the external interrupt to replace the pulseIn() call. Set it to CHANGE mode and store the value of micros() on the first edge, then take the difference between the stored value and the current value of micros() to get the pulse length. This way you don't have to deactivate the interrupts and your servos still work.
Another way is to just deactivate the Timer0 interrupt but then you have to be careful in programming, because you must not use millis(), micros(), delay() and other functions being dependent on them.