Go Down

Topic: arduino uno oversampling (making steering wheel] (Read 3934 times) previous topic - next topic

lamineovich

hi,
i am making a 900° steering wheel for pc using arduino
i mount a multiturn potentiometer and all is working
but with  8 bits of analog input (value from 0 to 255) the wheel turn is not really smoth (no continues turn) so i need more bits (12 bits or 14 bits). i heard about oversampling but i dont know how it work,
so, i need your help
thank you.

robtillaart

try this (from the archives)

Code: [Select]
//
//    FILE: analogReadN.pde
//  AUTHOR: Rob Tillaart
//    DATE: 2012-05-10
//
// PURPOSE: higher precision analogRead()
//
// http://www.atmel.com/Images/doc8003.pdf
//

void setup()
{
  Serial.begin(115200);

  for (int b=10; b< 17; b++)
  {
    unsigned int val = analogReadN(A0, b);
    Serial.println(val, DEC);
  }
}

void loop()
{
}

uint16_t analogReadN(uint8_t pin, uint8_t bits)
{
  bits = constrain(bits, 10, 16) -10;

  int samples = 1 << (bits << 1);

  uint32_t sum=0;
  for (int i=0; i< samples; i++) sum += analogRead(pin);     
  return sum >> bits;                             
}


note the number of samples increase quite a bit...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

DVDdoug

#2
Jan 23, 2016, 09:38 pm Last Edit: Jan 23, 2016, 10:37 pm by DVDdoug
Oversampling is related to the sample rate (the speed at which you sample), which is not an issue here.

I'm not sure what robtillaart's code is doing, but as far as I know the ATmega analog-to-digital converter only has 10-bits.  I'd be surprised if  you can get better than 10-bit resolution...

Quote
but with  8 bits of analog input (value from 0 to 255)
With 10 bits, you can get values between zero and 1023 (if you turn the pot all the way).

With 900 degrees and 1023 counts, that's about 1 count per degree, and that might be enough resolution.    The problem is, your 10-turn pot turns 3600 degrees...  

There are a couple of solutions (before you resort to an external ADC with higher resolution).    You can increase the voltage on the pot, so that 0-900 degrees gives you 0-5V.  (You'd might need to protect the Arduino from excessive voltage in case the steering wheel somehow gets turned too far.)

Or, switch to the optional 1.1V ADC reference.   The ADC should max-out (1023) at slightly less than 900 degrees giving you slightly less useable rotation, but about 5 times the resolution.   in this case, you don't have to worry about protection...   You can go over 1.1V (up to 5V) and the ADC will simply stay pegged at 1023.


P.S.
If you add a resistor in series with the pot to make a voltage divider, you can make 900 degrees put-out 1.1V, and then you'd get the full 900 degree range.

jremington

@DVDdoug: you can read about how to increase the effective ADC resolution by oversampling in this Atmel application note.

dwightthinker

It order to make oversampling work, you need to introduce
noise to the input. It is best if you can use a synchronous noise
so that you can filter it out later with a notch filter.
It also is best if the A/D also has good differential non-linearity.
If it isn't good it will just add noise.
In a real quiet A/D, oversampling usually has no advantage.
The data will still step at the same rate but with synchronous
noise, such a A/D can often be expanded quite a bit.
Do realize that if the noise is at a frequency higher than 1/2
the sampling rate that it will reflect into the sampled data that
once acquired can not be removed. Input filtering is a must.
The A/D used in the Arduino does us a sample/hold input. This
helps to reduce spurious noise but also means that it as a secondary
sampling rate to consider that can also add noise from vary high
frequencies, such as the processors clock or digital lines running
near your inputs.
Tinker Dwight


lamineovich

thanks you  for all your reply, i will try your solution

robtillaart

Oversampling is related to the sample rate (the speed at which you sample), which is not an issue here.

I'm not sure what robtillaart's code is doing, but as far as I know the ATmega analog-to-digital converter only has 10-bits.  I'd be surprised if  you can get better than 10-bit resolution...
...
The oversampling only works if the voltage is stable as it takes samples over a much longer period.
From the AVR notes, every bit extra needs 4x as much samples.

So the accuracy in amplitude is "paid for" in duration

10 bit -> 1x  ==> ~0.12 millisec (~8KHz)
12 bit -> 16x ==> ~20 millisec. (~500Hz)
16 bit -> 1024x  ==> ~ 0.13 seconds. (~7Hz)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

aarg

The actual resolution can never be better than the accuracy of the highest bit. That is why you can not "cascade" two 8 bit D/A to make one 16 bit D/A.
  ... with a transistor and a large sum of money to spend ...
Please don't PM me with technical questions. Post them in the forum.

dwightthinker

The oversampling only works if the voltage is stable as it takes samples over a much longer period.
From the AVR notes, every bit extra needs 4x as much samples.

So the accuracy in amplitude is "paid for" in duration

10 bit -> 1x  ==> ~0.12 millisec (~8KHz)
12 bit -> 16x ==> ~20 millisec. (~500Hz)
16 bit -> 1024x  ==> ~ 0.13 seconds. (~7Hz)

Did you read the article posted about over sampling.
It only works if you have noise added to the input.
You want the input or the reference to have some noise to work.
Tinker Dwight

robtillaart

#9
Jan 24, 2016, 03:27 pm Last Edit: Jan 24, 2016, 03:27 pm by robtillaart
AVR121: Enhancing ADC resolution by oversampling - http://www.atmel.com/Images/doc8003.pdf -

1 Introduction
Atmel's AVR controller offers an Analog to Digital Converter with 10-bit resolution.
In most cases 10-bit resolution is sufficient, but in some cases higher accuracy is
desired. Special signal processing techniques can be used to improve the
resolution of the measurement. By using a method called 'Oversampling and
Decimation' higher resolution might be achieved, without using an external ADC.
This Application Note explains the method, and which conditions need to be
fulfilled to make this method work properly.



3.2 Noise
To make this method work properly, the signal-component of interest should not vary
during a conversion. However another criteria for a successful enhancement of the
resolution is that the input signal has to vary when sampled. This may look like a
contradiction, but in this case variation means just a few LSB. The variation should be
seen as the noise-component of the signal. When oversampling a signal, there should
be noise present to satisfy this demand of small variations in the signal. The
quantization error of the ADC is at least 0.5LSB. Therefore, the noise amplitude has
to exceed 0.5 LSB to toggle the LSB. Noise amplitude of 1-2 LSB is even better
because this will ensure that several samples do not end up getting the same value.
Criterias for noise, when using the decimation technique:
• The signal-component of interest should not vary significantly during a conversion.
• There should be some noise present in the signal.
• The amplitude of the noise should be at least 1 LSB.
Normally there will be some noise present during a conversion. The noise can be
thermal noise, noise from the CPU core, switching of I/O-ports, variations in the
power supply and others. This noise will in most cases be enough to make this
method work
. In specific cases though, it might be necessary to add some artificial
noise to the input signal.


So yes
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

lamineovich

#10
Jan 24, 2016, 09:23 pm Last Edit: Jan 25, 2016, 07:40 pm by lamineovich
plz,
i am using yhis sketch to use arduino as joystick


Code: [Select]


#undef DEBUG

#define NUM_BUTTONS  40 // you don't need to change this value
#define NUM_AXES  8 // 6 axes to UNO, and 8 to MEGA. If you are using UNO, don't need to change this value.

typedef struct joyReport_t {
int16_t axis[NUM_AXES];
uint8_t button[(NUM_BUTTONS+7)/8]; // 8 buttons per byte
} joyReport_t;

joyReport_t joyReport;

uint8_t btn[12];
int fulloff = 0;
void setup(void);
void loop(void);
void setButton(joyReport_t *joy, uint8_t button);
void clearButton(joyReport_t *joy, uint8_t button);
void sendJoyReport(joyReport_t *report);

void setup()
{
//set pin to input Button
for( int portId = 02; portId < 13; portId ++ )
{
pinMode( portId, INPUT_PULLUP);
}
Serial.begin(115200);
delay(200);

for (uint8_t ind=0; ind<8; ind++) {
joyReport.axis[ind] = ind*1000;
}
for (uint8_t ind=0; ind<sizeof(joyReport.button); ind++) {
joyReport.button[ind] = 0;
}
}

// Send an HID report to the USB interface
void sendJoyReport(struct joyReport_t *report)
{
#ifndef DEBUG
Serial.write((uint8_t *)report, sizeof(joyReport_t));
#else
// dump human readable output for debugging
for (uint8_t ind=0; ind<NUM_AXES; ind++) {
Serial.print("axis[");
Serial.print(ind);
Serial.print("]= ");
Serial.print(report->axis[ind]);
Serial.print(" ");
}
Serial.println();
for (uint8_t ind=0; ind<NUM_BUTTONS/8; ind++) {
Serial.print("button[");
Serial.print(ind);
Serial.print("]= ");
Serial.print(report->button[ind], HEX);
Serial.print(" ");
}
Serial.println();
#endif
}

// turn a button on
void setButton(joyReport_t *joy, uint8_t button)
{
uint8_t index = button/8;
uint8_t bit = button - 8*index;

joy->button[index] |= 1 << bit;
}

// turn a button off
void clearButton(joyReport_t *joy, uint8_t button)
{
uint8_t index = button/8;
uint8_t bit = button - 8*index;

joy->button[index] &= ~(1 << bit);
}

/*
* Read Digital port for Button
* Read Analog port for axis
*/
void loop()
{
// Create Matriz with value off switch button
for(int bt = 1; bt < 13; bt ++)
{
btn[bt]= digitalRead(bt+1);
}
// Power ON button if it is press. buton 17 at 28
for(int on=01; on < 13; on++)
{
if (btn[on] == LOW)
{
setButton(&joyReport, on+16);
// Serial.println("botao ON");
// Serial.println(on+16);
}else{
fulloff = fulloff++;
} //Power off all Button, if all button are not press
if(fulloff == 13)
{
for(uint8_t cont=0; cont<40; cont++)
{
clearButton(&joyReport, cont);
}
// Serial.println("Every buttons is off");
}
}

/* Move all of the Analogic axis */
/* Arduino UNO have only 6 port. Will be necessary set to 0; the not used port */
/* In this example, i will use just 3 axis. X, Y, Z */
/* if you will use all 6 analog ports, set axis < 3, to axis < 5 */
for (uint8_t axis = 0; axis < 3; axis++) {
joyReport.axis[axis] = map(analogRead(axis), 0, 1023, -32768,32767 );
}
//Set to 0; the not used analog port.
//if you will use all 6 analog ports, exclude the lines, axis[3] at axis [5] */
joyReport.axis[3] = 0;
joyReport.axis[4] = 0;
joyReport.axis[5] = 0;
joyReport.axis[6] = 0;
joyReport.axis[7] = 0;
joyReport.axis[8] = 0;



//Send Data to HID
sendJoyReport(&joyReport);

delay(100);
fulloff = 0;
}





can you help me to add smooth function to this sketch

AWOL

It's probably a good idea to start using code tags

robtillaart

And CTRL-T to auto-indent the code BEFORE copying
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

dwightthinker

Should anyone want to make a white noise generator, here is
a way to do it.
We used to use this method to determine S/N in receivers and look at
bandwidth ( with things like AVC turned on ).
It seems that zeners have two modes of operation, one is a knee, which
is a soft change from conducting to not conducting.
Typically zeners below about 6.8V are knee type action.
Above this above, it tends to be avalanche breakdown. This means the voltage
will go a little above the zener voltage and will then conduct.
The voltage will snap back to the zener voltage.
It turns out that if you run a 6.8V zener with a light current, you
can have it dancing back and forth, making nice noise. It may need
a little amplification for the A/D use.
One can play with the bias current to get the maximum amplitude.
Using such noise has many purposes.
Making truly random numbers is one of them.
Another source of such a zener is the reverse bias of the emitter base
junction of a silicon transistor.
So, should one ever need noise, you now know how to find it.
Dwight

lamineovich

hi,
i plugged a multi turn pot to arduino(10turn) with a full angle of 3600° which make read of value really bad knowing arduino has only 10bits ADC (3600°-1023)
there is anyway to have better resolution like 14 or 16bits??
thanks you

Go Up