Help: Accelerometer-actuated servo for science project

Hello dear Arduino community!

I'm working on a science project that requires a 3d-printed gear to turn when a sensor box looks up at the sky and then turns the gear back the way it came when it looks at or below the horizon (kept simple and vague for the purposes of the arduino-focused situation).

Board: Nano 33 BLE Sense
Servo: Hitec HS-318 (not continuous rotation)
Degree of movement: from 0 (start) to 65 degrees (when box is tilted up) and then back to 0 (when box is pointing at or below the horizon).
Level of experience: beginner/intermediate (limited arduino programming, lots of hardware experience)

The Nano 33 BLE Sense was chosen to substitute our cheap, sensorless Nanos that don't work due to unfortunate software/firmware compatibility issues...
Anyways, our hope is that the accelerometer/gyro (LSM9DS1) will suffice.

After many hours of trying to cobble together some code based on forums and blog posts, I produced the code below. At first I tried IF/ELSE IF statements, but that didn't seem to work well, so I tried IF &&, then finally ended up with the Boolean "switch" since the IF statements did not work properly (servo would react to tilt-up, but then would immediately revert back to original position without the device being tilted below the stated threshold).

#include <Arduino_LSM9DS1.h>
#include <Servo.h>
Servo myservo;
int pos = 0;
bool diffuser = false;

void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("Started");

myservo.attach(PIN_A6);
myservo.write(0)

if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}

Serial.print("Accelerometer sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println(" Hz");
Serial.println();
Serial.println("Acceleration in G's");
Serial.println("XtYtZ");

}

void loop() {
float x, y, z, delta = 0.35;

if (IMU.accelerationAvailable()) {
IMU.readAcceleration(x, y, z);

Serial.print(x);
Serial.print('\t');
Serial.print(y);
Serial.print('\t');
Serial.println(z);

if ((x >= delta) && (diffuser = false)){
  //for (pos = 0; pos == 65; pos += 1) {
  myservo.write(65);
  diffuser = !diffuser;
  Serial.println(diffuser);  // for the sake of identifying whether or not the boolean value changes (no luck)
  delay(1000);}  // arbitrary value - up for suggestions

else if ((x < delta) && (diffuser = !diffuser)) {
  //for (pos = 65; pos == 0; pos -= 1) {
  myservo.write(0);
  diffuser = !diffuser;
  Serial.println(diffuser);
  delay(1000);}
else delay(1000);
}
  delay(3000);
}

Since I'm unfamiliar with servo actuation and the servo position for loop, I decided to try the more direct route with the servo.write function, but that didn't work either.

Any and all help would be much appreciated :sweat_smile: I thought this would be straightforward and simple, but I'm having such a hard time getting accelerometer data to actuate a servo... I'm hoping there will be a quick fix and a beautiful "aha!" moment.

Thanks for your time and support!

  • bobthebobster

Nice You use code tags. If You would use the Autoformat function in the IDE it would really look like code, not poetry, and be much easier to read.
Any picture of the rigging? It sounds strange to use an accelerometer to control a servo.

  //for (pos = 0; pos == 65; pos += 1) {
  myservo.write(65);
  diffuser = !diffuser;

Shouldn't that be something like:

 for (pos = 0; pos <= 65; pos += 1) {
  delay(10);
}
  diffuser = true;

And:

 for (pos = 65; pos >= 0; pos -= 1) {
  delay(10);
}
  diffuser = false;

Sounds more like a job for a tilt switch than an accelerometer... after all there are just two positions for the tilt that you care about, and two positions for the servo.

Code would basically be as simple as:

if (position == HORIZONTAL) { // or tilt angle less than a certain number
  myServo.write(0);
}
else {  // it's not horizontal so it's tilted
  myServo.write(65);
}

As you have the accelerometer you can use it to measure the box's tilt angle, and that allows for hysteresis around the tilt point.

if (angle < 10) { // tilted below 10 degrees off the horizontal
  myServo.write(0); // horizontal position
}
else if (angle > 20) {  // tilted over 20 degrees off the horizontal
  myServo.write(65); // up position
}

It would make sense to use the accelerometer to measure a tilt angle, and use that to steer the servo.

Hey all,

Thanks for the feedback and help.
The issues remains unresolved.
I'll try to answer all posts below.

I purposely placed the // for (pos = [...] ) because it did not work and I was hoping I could get help figuring out a solution, especially because the servo.write( ) did not work either.

A tilt switch has been ruled out because the other team that used one found it unreliable for our application as the sensor box moves a lot and gave false readings - hence our choice to go with an accelerometer.

In response to wvmarle's post - the code you wrote will not work unless angle is specified as a variable, however, if you review the code I provided, the if statements do exactly what you suggest as the delta value represents 0.35 / 1.00 tilted upwards (x value).
The issue with that code configuration involved the loop forcing the servo to continuously reset and rotate over and over, hence my attempt to use the boolean value to act as a toggle/switch.

So I'm still at a loss here for what to do... I'm open to changing up the logic, as I have tried several variations, but I'm not sure what will work.

Also, regarding the setup, I'll be in the lab this evening to take photos of the entire system - but I don't think that will change anything since the application is straightforward, I simply need to figure out the code aspect to make it work.

Thanks again for all your input!
I hope to resolve this matter soon.

In response to wvmarle's post - the code you wrote will not work unless angle is specified as a variable

The angle IS a variable, which is easily measured with an accelerometer.

What is the real problem?

I'm not sure how to respond...

... but I can say that the libraries I included do not specify "angle" as a variable.

Github references:
Arduino_LSM9DS1
Arduino Servo

The entire point of this post is that I'm not sure what is the problem... anything I've tried with the code examples I've supplied does not work. I'm hoping that perhaps the logic in my code is faulty and someone can help figure out how to better structure it to get it to do the simple task I'm trying to accomplish.

Railroader:
Nice You use code tags. If You would use the Autoformat function in the IDE it would really look like code, not poetry, and be much easier to read.
Any picture of the rigging? It sounds strange to use an accelerometer to control a servo.

I tried the auto format function and it broke my code...
So i've reverted back to what worked :sweat_smile:

bobthebobster:
I tried the auto format function and it broke my code...

The autoformat function in the IDE does not break any code. It only makes the indentation. If that indentation looks wrong to You the code is messed up in some way.

but I can say that the libraries I included do not specify "angle" as a variable.

The libraries do not do everything for you. If you want to calculate a tilt angle using the accelerometer, you could follow the tutorial I linked in reply #4. You have to add just a few lines of code, starting like this:

IMU.readAcceleration(x, y, z);

Serial.print(x);
Serial.print('\t');
Serial.print(y);
Serial.print('\t');
Serial.println(z);
  float roll = atan2(y , z) * 57.3;  //tilt about X in degrees
  float pitch = atan2((- x) , sqrt(y * y + z * z)) * 57.3; //tilt about NEW Y in degrees

If you wish to have code written for you, post on the Gigs and Collaborations forum section. You might be asked to pay for the help.

In the code example that i gave it is still your job to declare the variable angle, and to place the reading of the accelerometer in it. That may require some additional calculations from your side as well.

Of course you're free to give that variable another name, if you like. It really can be anything. I do recommend to give it a descriptive name, so when you come back to this code half a year or so later you can still easily understand what it does. That's also why you add comments to your code.

Thanks for the Gigs recommendation.

I'm not sure if I wrote too much in my original post or if my code really is that hard to read, but I have done all that has been recommended in the last two posts.
Also, my code worked just fine before the auto format.
You can't deny my experience using the auto format function that broke my code (had to revert to previous save).

I appreciate the replies and willingness to support, but I feel like somehow I have not properly presented my case because so far no one has brought up anything new/worthwhile...
Plus if you took the time to review my code, you'll notice I have defined variables and even got the function to trigger when the tilt angle was appropriate. I'm not stellar with comments in my code, so I suppose I'll practice that more.

Thanks again for all your help, not sure how to close this thread, but have a nice day.

bobthebobster:
Also, my code worked just fine before the auto format.

That is completely nonsense. The autoformat rearranges the text displayed on the screen and it does not do anything alteration of the code being compiled. I have no idea what kind of/where You fond Your autoformat function.
[/quote]

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.