Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Servo Jitters


  • Please log in to reply
13 replies to this topic

#1 Bendage

Bendage

    Advanced Member

  • Members
  • PipPipPip
  • 153 posts
  • LocationIrvine, CA

Posted 04 March 2012 - 07:38 AM

So I'm messing around with a 3 axis accelerometer controlling a couple of servos on a pan/tilt. The code works fine but the servos get a bit jittery due to hand shakiness. I tried to smooth it out by getting an average of the last 5 readings but it really doesn't work. Any ideas?

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using Servo_API;

namespace Accelerometer_Example
{
    public class Program
    {
        // Define our accelerometer inputs
        static AnalogInput accX;
        static AnalogInput accY;
        static AnalogInput accZ;

        static Servo servoX;
        static Servo servoY;

        static ArrayList stackX;
        static ArrayList stackY;

        static int capacity = 5;

        public static void Main()
        {
            // Create the Inputs
            accX = new AnalogInput(Pins.GPIO_PIN_A0);
            accY = new AnalogInput(Pins.GPIO_PIN_A1);
            accZ = new AnalogInput(Pins.GPIO_PIN_A2);

            servoX = new Servo(Pins.GPIO_PIN_D5);
            servoY = new Servo(Pins.GPIO_PIN_D6);

            stackX = new ArrayList();
            stackY = new ArrayList();

            servoY.inverted = true;

            while (true)
            {
                
                Debug.Print("X:" + accX.Read().ToString() + " Y:" + accY.Read().ToString() + " Z:" + accZ.Read().ToString());
   
                
                MoveAvgX(accX.Read());
               
                MoveAvgY(accY.Read());

                Thread.Sleep(10);
            }
        }

        public static void MoveAvgX(int x)
        {
            stackX.Add(x);
            if (stackX.Count > capacity) stackX.RemoveAt(0);
            int avg = 0;
            for (int i = 0; i < stackX.Count; i++)
            {
                avg += int.Parse(stackX[i].ToString());
            }
            avg = avg / stackX.Count;
            servoX.Degree = servoX.map(avg, 400, 600, 0, 180);
        }

        public static void MoveAvgY(int y)
        {
            stackY.Add(y);
            if (stackY.Count > capacity) stackY.RemoveAt(0);
            int avg = 0;
            for (int i = 0; i < stackY.Count; i++)
            {
                avg += int.Parse(stackY[i].ToString());
            }
            avg = avg / stackY.Count;
            servoY.Degree = servoY.map(avg, 400, 600, 0, 180);
        }      
    }
}


#2 Paul Newton

Paul Newton

    Advanced Member

  • Members
  • PipPipPip
  • 724 posts
  • LocationBerkshire, UK

Posted 04 March 2012 - 02:23 PM

Hi Bendage, I think you were on the right track with the averaging. I see that your main loop is reading the sensors approximately every 10ms, so the average is only over 50ms (20Hz). My guess is that 50ms is not long enough to average out any shake in your hand. I just did a quick test seeing how many times I can hita key on the keyboard in 5 seconds, I managed 41 - so that's about 8Hz. What happens if you keep the same period in the main loop (10ms), but up the averages to 20 to give 200ms (5Hz)? Paul

#3 Bendage

Bendage

    Advanced Member

  • Members
  • PipPipPip
  • 153 posts
  • LocationIrvine, CA

Posted 04 March 2012 - 06:15 PM

Thank you for your response. I'm afraid that didn't help. Still shaky but now extremely slow. When I avg out 20 and make a very large incremental move, the avg pretty kills it and it takes about 3 seconds to move from one end of the spectrum to the other while still shaking. I've tried looking this up in other place on the web and I really have not found anything yet. I'm sure there is a solution I'm just wondering if I'm going about it completely wrong. Also if I use anything other then 10 ms to read the accelerometer I get a lot more spikes. The numbers jump all over +-50. 10 ms seems to keep it steady.

#4 Paul Newton

Paul Newton

    Advanced Member

  • Members
  • PipPipPip
  • 724 posts
  • LocationBerkshire, UK

Posted 04 March 2012 - 06:36 PM

Hi again, You have not said anything about the construction of your circuit. Is there anything else connected to the Netduino? (other shields, etc.) If so, try without them in-case they are causing a problem. Do you have any capacitors fitted to the power supply lines close to the sensor? These would help get rid of any noise on the supply lines that could cause noise on the analogue outputs. The data sheet for the sensor will probably specify some combination of decoupling capacitors. Are you powering the servos and the sensors from the same supply? It may be that as the servo motors turn, the voltage is dropping slightly and the Netduino is measuring a slight dip on the analogue inputs because of this. Depending on the dynamics of the system, you can end up with an oscillator! If you can, try powering the servos from their own battery supply. That way the motors will not add noise to the Netduino and sensor power supply. Another thing to try is to use some potentiometers as analogue inputs instead of your sensor. Check if you still get shaky servos then. If you do, it is not a problem with the sensor. Keep trying - Paul

#5 Paul Newton

Paul Newton

    Advanced Member

  • Members
  • PipPipPip
  • 724 posts
  • LocationBerkshire, UK

Posted 04 March 2012 - 06:43 PM

Did you spot this recent topic: Can PWM interfere with I2C

The issues are similar.

Paul

#6 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 04 March 2012 - 06:44 PM

Still shaky but now extremely slow.

I have not measured it, but IMHO you can speed up the code a little bit by replacing Parse() with cast:

avg += (int)stackX[i];
Also, you might consider changing avg type to long to avoid overflow and Queue instead of Stack.

What accelerometer do you use?

#7 Bendage

Bendage

    Advanced Member

  • Members
  • PipPipPip
  • 153 posts
  • LocationIrvine, CA

Posted 05 March 2012 - 05:10 AM

Paul, I like your idea of separate power supply. You may have a point there. I'll try it. Basically I'mm just powering 2 micro servos via board power so there could be a surge. I'm a software guy not a hardware guy so I'll have to look up how to plug in some capacitors. Any ideas? CW2, Its an ADL335. The stack object is actually an Arraylist. Long won't matter due to a array capacity count of 10 an avg val * max val 0f 600 = 6000. I'll try your casting instead of parsing to make it faster. Thanks for the ideas!

#8 Stefan W.

Stefan W.

    Advanced Member

  • Members
  • PipPipPip
  • 153 posts

Posted 05 March 2012 - 06:38 AM

There's other ways to make it faster (don't push/pop from a list, instead use a plain array and cycle the index that you are using). However, your main problem is that you only have an accelerometer to measure the orientation of your setup, and accelerometers are jittery in itself - also, for an accelerometer gravity is indistinguishable from you accelerating your hand, so it's expected that your readings are off when you move your hand. What you'd need to do would be to couple the accelerometer with a gyro, and then combine the measurements e.g. complementary filtering - see this Presentation for example.
I believe that no discovery of fact, however trivial, can be wholly useless to the race, and that no trumpeting of falsehood, however virtuous in intent, can be anything but vicious.
-- H.L. Mencken, "What I Believe"

#9 Paul Newton

Paul Newton

    Advanced Member

  • Members
  • PipPipPip
  • 724 posts
  • LocationBerkshire, UK

Posted 05 March 2012 - 06:41 AM

For the capacitors, take a look at the data that came with the sensor. (You may need to download a datasheet from the place you bought it or the manufacturer.) If the sensor is on a shield or a breakout board, it may already have them. Paul

#10 Bendage

Bendage

    Advanced Member

  • Members
  • PipPipPip
  • 153 posts
  • LocationIrvine, CA

Posted 05 March 2012 - 04:12 PM

Paul,

Here is the sensor link...

http://www.adafruit.com/products/163

It takes me to a data sheet with the following image...

Posted Image

I'm not very intuitive in reading electronic symbol diagrams, but those resistors look built in to me. Looks like 4 capacitors needed? will ceramic 0.1uf do the trick?

#11 Paul Newton

Paul Newton

    Advanced Member

  • Members
  • PipPipPip
  • 724 posts
  • LocationBerkshire, UK

Posted 05 March 2012 - 07:39 PM

Hi,

Yes you are correct - the resistors are actually part of the chip.

Are you using the breakout board shown at the link?
Posted Image
I am guessing that you are as that device would be a bugger to solder on its own!

If not then congratulations on the soldering skills, and yes you will have to add the four capacitors. The diagram does not show polarised capacitors (no + symbol) - so ceramic should be OK. They should be fitted near the device.

The breakout board has all the capacitors fitted already, so assuming that is what you are using, you don't need to add anything else. It also has a voltage regulator.

3Vo is the output from the on-board regulator, you could use it to drive the Aref input on the Netduino. Once the jitters are fixed, using the 3Vo to drive Aref would give a better range on the ADCs. (To use the Aref signal for the ADCs instead of the on board 3.3V, there is a setting to make in the Netduino - I can't remember what it is off hand.)

EDIT: sorry the regulator is actually 3.3V so it will not give an improvement in range. I read 3Vo as three volts not 3.3 Volts :blink:

A few questions that might help spot a problem with your setup:

What have you done with the test pin? The data sheet says to either leave it unconnected or to tie it to ground.

What voltage have you connected to Vin (3.3V or 5V)? I think 5V would be better, I am not sure that 3.3V will give enough voltage for the regulator to work correctly.

How long are the wires from the board back to the Netduino? If they are long, they will be susceptible to noise, and the chip may not be able to drive enough current into them.

Remember to enjoy yourself - it is a hobby after all :)

Regards - Paul

#12 Bendage

Bendage

    Advanced Member

  • Members
  • PipPipPip
  • 153 posts
  • LocationIrvine, CA

Posted 05 March 2012 - 07:47 PM

LOL, ya I use this board, not a custom. So am I understanding you correctly? This board HAS capacitors built in or I need to add them? I do nothing with the Test lead and the sensor is on top of a proto shield with 3 inch test leads using onboard 3.3v. You sure I won't damage the board with 5v? And you are right... it is a hobby, one that is not supposed to pull my hair out. As a 40+ hour .Net developer, you'd think I would have chosen tennis. Hahaha

#13 Paul Newton

Paul Newton

    Advanced Member

  • Members
  • PipPipPip
  • 724 posts
  • LocationBerkshire, UK

Posted 05 March 2012 - 08:38 PM

Glad I made you laugh. I guess you aren't going to put the accelerometer on your tennis racquet :rolleyes: Yep - the board already has the capacitors so you don't need to add any more. 3 inches is fine. (I was a little worried that you might have long leads of several feet so that the Netduino could be on the desk and the accelerometer in your hand.) Yes, I'm sure 5V is OK, the web page says: "The VCC takes up to 5V in and regulates it to 3.3V with an output pin." Sounds like the sensor end is almost perfect. Do have a go at using separate supplies for the servos. My buggy project (that I get to spend about an hour a month on) rebooted every time the motors spun up until I used a separate supply for them! Paul

#14 Bendage

Bendage

    Advanced Member

  • Members
  • PipPipPip
  • 153 posts
  • LocationIrvine, CA

Posted 05 March 2012 - 08:46 PM

There's other ways to make it faster (don't push/pop from a list, instead use a plain array and cycle the index that you are using). However, your main problem is that you only have an accelerometer to measure the orientation of your setup, and accelerometers are jittery in itself - also, for an accelerometer gravity is indistinguishable from you accelerating your hand, so it's expected that your readings are off when you move your hand. What you'd need to do would be to couple the accelerometer with a gyro, and then combine the measurements e.g. complementary filtering - see this Presentation for example.


Stefan,

I'm sorry I did not see this post. I just ordered a sensor with Nine axis modules (three-axis gyro + three axis acceleration + tri-axial magnetic field)

I'll give it a go with that one. Thank you.

And Paul, thanks again for your insight as well.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.