NEWB trying to work with Nano

so heres my project. im tryingto control a servo using a accelerometer to measure tilt. i can get everythign to work but its twitching like crazy and no matter the direction i move the accel.. it moves the servo. i only want to measure one axis. not all three. how to i make it do that? and how do i stop the twitching effect.?

the whole idea is to mount to a camera and counter tilt a motorcycle to keep the camera level with the horizon.

Are you powering your servo via an external source? USB can only output ~100Ma which is probably not enough for your servo - hence the jittering. Make sure to connect the GND of your external power supply to the arduino GND!

i can get everythign to work but its twitching like crazy and no matter the direction i move the accel.. it moves the servo. i only want to measure one axis. not all three. how to i make it do that? and how do i stop the twitching effect.?

Which accelerometer?

When the bike is leaned into a corner, is it the x axis you want to measure, the y axis, or the z axis? The answer is that you need to measure more than one, and use them to determine how far the bike has leaned. Doing so is not trivial, since the acceleration vector you are measuring is a composite of multiple inputs - gravity and the bikes acceleration/deceleration being the primary inputs, but bumps in the road are going to be measured, too.

inboxjason:
Are you powering your servo via an external source? USB can only output ~100Ma which is probably not enough for your servo - hence the jittering. Make sure to connect the GND of your external power supply to the arduino GND!

im actually powering using a battery pack.

PaulS:

Which accelerometer?

When the bike is leaned into a corner, is it the x axis you want to measure, the y axis, or the z axis? The answer is that you need to measure more than one, and use them to determine how far the bike has leaned. Doing so is not trivial, since the acceleration vector you are measuring is a composite of multiple inputs - gravity and the bikes acceleration/deceleration being the primary inputs, but bumps in the road are going to be measured, too.

well really it dont matter the axis i use to measure. as i can mount the accelerometer in any position. here the link to the acceleromter im using...DE-ACCM 2g Buffered 2 Axis Accelerometer

heres the code im using. i dont know if its right or not. i pasted it here for you guys to modify. i got it to sweep the angles i need but its extremely twitchy. breath on it and it twitches the servo. its a 2g 2axis accelerometer. i posted the link in my last response. i need to smooth it out and get it to read one axis. right now im wired to X axis only.

#define NUM_SERVO 1

int servoPin[NUM_SERVO] = { 2 }; // Control pins for servo motors
int minPulse = -300; // Minimum servo position
int maxPulse = 5000; // Maximum servo position
int pulseRange = maxPulse - minPulse; // Range of the servo position
int pulseWidth[NUM_SERVO] = { 0 }; // Pulse width for the servo motors

long lastPulse = 20; // Time in milliseconds of the last pulse
int refreshTime = 20; // Time needed in between pulses

int analogPin[NUM_SERVO] = { 0 }; // The analog pin that the sensor's on
int minSensorValue[NUM_SERVO] = { 0 }; // Minimum sensor value
int maxSensorValue[NUM_SERVO] = { 1000 }; // Maximum sensor value
int sensorRange[NUM_SERVO] = { maxSensorValue[0] - minSensorValue[0] }; // Range of the sensor values
int sensorValue[NUM_SERVO] = { 0 }; // The value returned from the analog sensor

int phase = 0; // variable to select the servo motor to drive

//------------------------------------------------------------------------------
// convert the pulse width to a range between minPulse and maxPulse
//------------------------------------------------------------------------------
int checkPulseWidth(int pulseWidth)
{
if (pulseWidth < minPulse) return minPulse;
if (pulseWidth > maxPulse) return maxPulse;
return pulseWidth / 25 * 25;
}

//------------------------------------------------------------------------------
// setup function
//------------------------------------------------------------------------------
void setup()
{
for (int i = 0; i < NUM_SERVO; i++) {
// Set servo pin as an output pin
pinMode(servoPin*, OUTPUT);*

  • // Set the motor position value to the minimum*
    _ pulseWidth = minPulse;_
    * }*

* Serial.begin(9600); // Start serial communication*
}
//------------------------------------------------------------------------------
// loop function
//------------------------------------------------------------------------------
void loop()
{
* for (int i = 0; i < NUM_SERVO; i++) {
sensorValue _= analogRead(analogPin); // read the analog input*
pulseWidth = (int)((float)(sensorValue - minSensorValue*) /*
sensorRange * pulseRange) + minPulse;
pulseWidth = checkPulseWidth(pulseWidth*); // convert the pulse width*
* }*_

* // pulse the servo again if the refresh time (20ms) have passed:*
* if (millis() - lastPulse >= refreshTime) {*
* digitalWrite(servoPin[phase], HIGH); // Turn the motor on*
* delayMicroseconds(pulseWidth[phase]); // Length of the pulse sets the motor position*
* digitalWrite(servoPin[phase], LOW); // Turn the motor off*
* lastPulse = millis(); // Save the time of the last pulse*

* // display the data*
* if (phase == 1) {*
* for (int i = 0; i < NUM_SERVO; i++) {
_ Serial.print("SV");
Serial.print(i);
Serial.print(": ");
Serial.print(sensorValue);
Serial.print(" ");
Serial.print("PW");
Serial.print(i);
Serial.print(": ");
Serial.print(pulseWidth);
Serial.print(" ");
}
Serial.println();
}*_

* // update the phase variable*
* phase++;*
* if (phase > NUM_SERVO-1) phase = 0;
_ }
}*_

To keep things as simple as possible, there are only 4 pins - two for power, and two for the X and Y analog outputs.

You have the two pins connected to analog pins 0, 1, and 2, do you?

i need to smooth it out and get it to read one axis. right now im wired to X axis only.

So, why are you reading three pins?

Do you know what the output from an accelerometer corresponds to, in real life? Acceleration and tilt are not even close to the same thing. You seem to be treating the output from the accelerometer as though it was reporting lean angle. It is not.

sorry man, i had to repost my code. for some reson it posted an old code from something else. weird. but my previous post has the updated code.

Because you failed to properly post your code, this doesn't make any sense.
for (int i = 0; i < NUM_SERVO; i++) {
sensorValue = analogRead(analogPin); // read the analog input

The analogPin array is of length two, with both elements containing 0. It doesn't make sense to read from the same pin twice every time the loop iterates.

Post the code properly, using the # icon.

PaulS:
Because you failed to properly post your code, this doesn't make any sense.
for (int i = 0; i < NUM_SERVO; i++) {
sensorValue = analogRead(analogPin); // read the analog input

The analogPin array is of length two, with both elements containing 0. It doesn't make sense to read from the same pin twice every time the loop iterates.

Post the code properly, using the # icon.

i have no idea what your talking about. as the subject says NEWB!!!! i didnt write the code it was a compilation of codes that other wrote that said would work. it seems to work too. just very jittery.

as the subject says NEWB!!!!

There are three kinds of NEWBs. Those that haven't learned yet, those that don't want to learn, and those that can't learn. I'm going to assume that you fall into the first category. Above the box where I am typing now, and that you have used in the past, there are several buttons. One of them has a # key on it. Select that icon before pasting code.

Without doing that, the forum software assumes that [ i ] (without the spaces) means to start italicizing text.

i didnt write the code it was a compilation of codes that other wrote that said would work.

I'm sure that the original code did work. It is the compilation that is wrong.

You have an array of pins, analogPin. The size of the array and the number of initializers do not match, so the compiler sets the remaining values to 0. Since your one initializer was also 0, all the pin numbers in the array refer to the same pin (pin 0).

It hardly makes sense that this is what you want. Either you want to read from just one pin, in which case the size of the array is wrong, or you want to read from more than one pin, in which case you need to provide more initializers.

Have you read the note about the output of the accelerometer NOT being lean angle? The fact that you keep trying to fix the code so somehow the accelerometer output magically transforms into something else implies that you haven't.

PaulS:

as the subject says NEWB!!!!

There are three kinds of NEWBs. Those that haven't learned yet, those that don't want to learn, and those that can't learn. I'm going to assume that you fall into the first category. Above the box where I am typing now, and that you have used in the past, there are several buttons. One of them has a # key on it. Select that icon before pasting code.

Without doing that, the forum software assumes that [ i ] (without the spaces) means to start italicizing text.

i didnt write the code it was a compilation of codes that other wrote that said would work.

I'm sure that the original code did work. It is the compilation that is wrong.

You have an array of pins, analogPin. The size of the array and the number of initializers do not match, so the compiler sets the remaining values to 0. Since your one initializer was also 0, all the pin numbers in the array refer to the same pin (pin 0).

It hardly makes sense that this is what you want. Either you want to read from just one pin, in which case the size of the array is wrong, or you want to read from more than one pin, in which case you need to provide more initializers.

Have you read the note about the output of the accelerometer NOT being lean angle? The fact that you keep trying to fix the code so somehow the accelerometer output magically transforms into something else implies that you haven't.

#define NUM_SERVO	1

int servoPin[NUM_SERVO] = { 2 };     // Control pins for servo motors
int minPulse = -300;                               // Minimum servo position
int maxPulse = 5000;				// Maximum servo position
int pulseRange = maxPulse - minPulse;  // Range of the servo position
int pulseWidth[NUM_SERVO] = { 0 };  // Pulse width for the servo motors

long lastPulse = 20;    // Time in milliseconds of the last pulse
int refreshTime = 20;  // Time needed in between pulses

int analogPin[NUM_SERVO] = { 0 };   // The analog pin that the sensor's on
int minSensorValue[NUM_SERVO] = { 0 };  // Minimum sensor value
int maxSensorValue[NUM_SERVO] = { 1000 };  // Maximum sensor value
int sensorRange[NUM_SERVO] = { maxSensorValue[0] - minSensorValue[0] };  // Range of the sensor values
int sensorValue[NUM_SERVO] = { 0 };  // The value returned from the analog sensor

int phase = 0;    // variable to select the servo motor to drive


//------------------------------------------------------------------------------
// convert the pulse width to a range between minPulse and maxPulse
//------------------------------------------------------------------------------
int checkPulseWidth(int pulseWidth)
{
    if (pulseWidth < minPulse) return minPulse;
    if (pulseWidth > maxPulse) return maxPulse;
    return pulseWidth / 25 * 25;
}

//------------------------------------------------------------------------------
// setup function
//------------------------------------------------------------------------------
void setup()
{
    for (int i = 0; i < NUM_SERVO; i++) {
        // Set servo pin as an output pin
        pinMode(servoPin[i], OUTPUT);
        // Set the motor position value to the minimum
        pulseWidth[i] = minPulse;
    }
    
    Serial.begin(9600);    // Start serial communication
}

//------------------------------------------------------------------------------
// loop function
//------------------------------------------------------------------------------
void loop()
{
    for (int i = 0; i < NUM_SERVO; i++) {
        sensorValue[i] = analogRead(analogPin[i]);  // read the analog input
        pulseWidth[i] = (int)((float)(sensorValue[i] - minSensorValue[i]) / 
                              sensorRange[i] * pulseRange) + minPulse;
        pulseWidth[i] = checkPulseWidth(pulseWidth[i]);  // convert the pulse width
    }
    
    // pulse the servo again if the refresh time (20ms) have passed:
    if (millis() - lastPulse >= refreshTime) {
        digitalWrite(servoPin[phase], HIGH);   // Turn the motor on
        delayMicroseconds(pulseWidth[phase]);  // Length of the pulse sets the motor position
        digitalWrite(servoPin[phase], LOW);    // Turn the motor off
        lastPulse = millis();    // Save the time of the last pulse
        
        // display the data
        if (phase == 1) {
            for (int i = 0; i < NUM_SERVO; i++) {
                Serial.print("SV");
                Serial.print(i);
                Serial.print(": ");
                Serial.print(sensorValue[i]);
                Serial.print("   ");
                Serial.print("PW");
                Serial.print(i);
                Serial.print(": ");
                Serial.print(pulseWidth[i]);
                Serial.print("   ");
            }
            Serial.println();
        }
        
        // update the phase variable
        phase++;
        if (phase > NUM_SERVO-1) phase = 0;
    }
}

did it post right this time? i used the # icon that says "code" when you hover the mouse over it.

so if the accelerometer cant be used to determine lean angle then how is it that when i youtube it, tons of people are doing it with an accelerometer? even when they list the things they used to do it, it clearly says accelerometer. i figured a gyro or a filter will be needed but they arent using one. so, what do i do now then?

im more than willing to learn this stuff but the issue is im a visual learner. i cant read alot of details and get whats happening. its part of my A.d.d.

look any help will be greatly appreciated. if you think rewritting it is what has to happen then help me out and tell me how to do it. i know theres a shit load of info out there but it either doesnt pertain to my needs or the code is generallized and i dont know what to change. i dont know anyone that knows how to do this stuff or can even explain it in laymens terms kindly...

o3dodgesrt4:
the whole idea is to mount to a camera and counter tilt a motorcycle to keep the camera level with the horizon.

Could you clarify how you plan to detect the roll angle using the accelerometer? It does not seem feasible to me without a gyro to measure changes in roll angle, and some means to detect long term drift. (I imagine you could correct for long drift by assuming that the bike is upright on average and just have your system slowly creep back to the mid position.)

did it post right this time?

Yes, you did. Thank you.

An accelerometer measures the rate of change of velocity. Velocity has a speed and direction component. So, the accelerometer, if oriented correctly, can be used to measure the amount of change in direction about an axis. But, that must be integrated over time to get anything meaningful. The accelerometer does not do the integration for you. And, certainly, the instantaneous change value that the accelerometer reports bears not relationship to lean angle.

What you are trying to do is like looking at the speedometer at one point in time, and trying to figure out where you are from that one piece of data. If you look at the speedometer frequently, and use those frequent values AND the time that the value was observed, you can do a reasonable approximation of location, IF you also note the direction at each reading. Just knowing speed at some point in time is not enough.

The accelerometer is telling you how much the speed has changed. As you can see, without knowing what the speed was before, and how long ago the previous speed was noted, you can't tell what the current speed is.

ok so you think i need a gyro as well. ok thats not an issue but i dont know how to write the code to integrate it and make it communicate with the accelerometer and arduino to get the right output i want. i think you get the idea of what i want. just a matter of how. what kind of gyro should i get?

it just erks me that i can make it do what i want and hold its position but not be able to eliminate the twitching.

someone else said to use a gyro and a filter? kalman filter or something to that effect?

is there a combo gyro/filter/accel... in one? that would make this really easy.

To me, 'accelerometer' means a linear accelerometer. From previous posts I imagined you trying to detect the direction of the net thrust vector from the wheels to determine whether it was aligned with the direction of gravity. I'm sure you realise now that isn't feasible.

What you really need is a rotary accelerometer i.e. something to detect the bike accelerating into or out of a roll. This is essentially what a gyro sensor does. It doesn't detect angular position or speed but it detects acceleration (in roll) and if you know the initial position / speed you can integrate the roll acceleration to work out the position and speed at any moment. This type of integration approach is vulnerable to cumulative errors (drift) so you need a way to keep the device aligned with 'upright' over the long term. Since the bike will probably spend most of its time close to upright, you could just arrange your control algorithm to slowly creep towards the center position to counteract cumulative errors.

Detecting the lean angle of a motorcycle is difficult, especially at higher speeds. It requires an expensive gyro, not an accelerometer. A few companies have spent millions of dollars trying to find a better solution. It would be much easier if there were no vibration nor extreme changes in angle. There is an alternative using GPS data. Unfortunately it will not react nearly fast enough to keep a video camera stable or level.

I love motorcycles and video photography. You're going to want image stabilization in post production anyway to reduce the vibration in the video. As long as you're doing that, use a wide angle lens and set the parameters to keep the horizon level. This will work great at angles up to 30 deg, as long as you're not racing.