Title: Double Transducer: Vibration to Color

Description:

This project senses the frequency of a vibration, which turns a stepper motor a number of steps, which turns a potentiometer, whose value determines the angle that a color wheel spins to.

Progress:

Hooking up servo, accelerometer, and potentiometer connections

Building a stand to hold accelerometer in constant vertical g field along Z axis

Building a stand to hold accelerometer in constant vertical g field along Z axis

First prototype with all components connected and interacting with one another. A shaft coupler was used to connect the potentiometer with the stepper motor.

Discussion:

There were a number of challenges in getting the accelerometer, stepper motor, and potentiometer to all work together cohesively. 

Our initial idea in order to measure the amount of vibration was to average the x-axis, y-axis, and z-axis values from the accelerometer at each point in time. Then, compare those averages to each other to register a “vibration”. However, we realized on initial collection of these values that movement in each axis was counteracting the movement in the other axes, resulting in relatively stagnant average values. We decided to only focus on one axis to track rather than all of them, and thought that the vibration would probably happen mostly up and down. Therefore, we settled on tracking the z-axis. But we still needed to figure out how to register that a vibration occurred.

Initially, we had assumed the input from the vibration motor would come with variable magnitude. With further research, however, we realized that the vibration motor would vary it’s frequency proportionally to its input voltage. This posed the tricky problem of figuring out how to register the frequency of the input analog signal without more complex DSP hardware and software. Our solution was relatively simple and easily adjustable based on the performance we observed. We decided to fix our accelerometer with its z-axis experiencing a constant acceleration of one g. We would then decide on a suitable bias to subtract from the z-input readings and then ‘sample’ the incoming analog signal for a short period of time in our loop() function. Each time the signal was observed to cross a customizable threshold, we would increment a counter and treat this counter as a rough measurement of frequency. 

The results from this method were relatively encouraging with the whole system behaving generally as we would expect it to. It would have been helpful however to actually stimulate the accelerometer with a vibration motor rather than our hands to allow us to more accurately provide input frequency with a wider range.

We had some issues attaching the stepper motor to the potentiometer in the first place. We first primitively tried it with masking tape, and then when that didn’t work, duct tape. In both cases, the axis of the stepper motor merely shifted itself under the tape without moving the potentiometer at all. We ended up using shaft couplers we found in the lab to do the job, which worked well. However, there were still certain things we needed to take care of in order for the stepper motor and potentiometer to function together.

We also realized that during the set-up part of the code execution, the stepper motor would jitter for a while before resting at the 0 position. If it was already attached to the potentiometer, it could possibly lift it out of its place. This means that during set-up the stepper would have to remain detached from the potentiometer, and then connected after. We resolved this by leaving a small delay after the set-up code, in which it was understood that we would quickly attach the stepper to the potentiometer after the jitter in that timeframe. Not the most elegant solution, but we were unclear as to why the stepper was moving around in the first place. 

One of our unsolved issues and a place in which our machine could have used improvement was debugging and removing some of the noise which seemed to cause the stepper motor to rotate or jitter at unexpected times. Some of the places we suspect it could have been coming from includes some vibrational feedback from the motor to the accelerometer, loose connections at the pins of the potentiometer, or perhaps incorrectly assuming that the stepper motor “zeroed” its relative position on startup.

The accelerometer is mounted to help isolate it from outside vibrations.

An Overview of the Layout

Wire management would need to be improved on later iterations to cut down on clutter.

Shaft couplers were used to attach the different motors together.

A servo turns 180 degrees to allow a stationary color reader to sense different wavelengths.

The accelerometer roughly measures the frequency of input vibrations to the accelerometer. This turns the stepper which allows the potentiometer to re-encode the rotation into the rotational displacement of the servo and color wheel.

Schematic:

Code:

/*
 * Project 1 (Vibration -> Color)
 * Neeharika Vogety (nvogety) and Nicholas Toldalagi(ntoldala)
 * ~4 hours
 *
 * Collaboration: Code was written together. Portions of Servo and Stepper Motor 
 * code was taken from starter code provided in the Tutorials section of the 60-223 
 * webpage.
 * 
 * Next time: In other projects, we will start much earlier and plan ahead before
 * starting.
 * 
 * Summary: Vibration(changes in z axis from accelerometer) -> Turn Stepper 
 * Motor -> Turn Potentiometer -> Move Servo Motor(on which a color wheel 
 * is attached)
 * 
 * Inputs:
 *  Arduino pin | input
 *  A2            X Axis Accelerometer
 *  A1            Y Axis Accelerometer
 *  A0            Z Axis Accelerometer
 *  A3            Potentiometer
 * 
 * Outputs:
 *  Arduino pin | output
 *  2             Stepper Motor Driver Step Pin
 *  3             Stepper Motor Driver Direction Pin
 *  5             Servo Motor Pin
 */

#include <AccelStepper.h>
#include <Servo.h>

//
const int X_PIN = A2;
const int Y_PIN = A1;
const int Z_PIN = A0;
const int POT_PIN = A3;
const int STEP_PIN = 2; 
const int DIR_PIN = 3; 
const int SERV_PIN = 5;

// Create AccelStepper and Servo objects
AccelStepper myMotor(1, STEP_PIN, DIR_PIN);
Servo s1;


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

  // Set up pins
  pinMode(X_PIN, INPUT);
  pinMode(Y_PIN, INPUT);
  pinMode(Z_PIN, INPUT);
  pinMode(POT_PIN, INPUT);

  // Set up servo with pin
  s1.attach(SERV_PIN);

  // Set up stepper motor 
  myMotor.setMaxSpeed(200);
  myMotor.setAcceleration(100);

  // Set stepper motor to move to position 0
  myMotor.moveTo(0);

  // Move stepper motor to position 0
  while (myMotor.distanceToGo() != 0) { // while there is still a distance to go,
    myMotor.run(); // make the motor run
  }

  /* Because it has to wiggle around a little to find that 0th position, stepper
   *  must start out dettached from potentiometer. Give about a 7 second delay
   *  to attach stepper to potentiometer after 0th position is found.*/
  delay(7000);

}

void loop(){
    // Set some important values
    int threshold = 10; // How much above or below bias we want to register as a change in position
    int bias = 390; // What a motionless accelerometer reads
    int samplePeriod = 1000; // How many total samples to take
    int maxFreq = 100; // Maximimum number of position changes registered - completely arbitrary
    int minFreq = 0; // Min number of position changes registered - always 0

    // Read accelerometer
    int x_val = analogRead(X_PIN);
    int y_val = analogRead(Y_PIN);
    int z_val = analogRead(Z_PIN);

    /* We want to calculate how many times the position of the accelerometer in the 
     *  z axis changes significantly. Specifically, we want the frequency.  
     *  We get this by sampling 1000 times, and within each sample registering
     *  whether the recorded z position is above a certain large number or below a small number.
     *  This large number and small number is calculated by either adding or subtracting a threshold
     *  from the bias (see above int defs). The number of times this occurs is our frequency.
     */
    Serial.println("start z collection");
    int sampleCounter = 0;
    int zValCounter = 0;
    int currzVal;
    while(sampleCounter < samplePeriod){
      currzVal = analogRead(Z_PIN);
      if(currzVal < (bias - threshold) || currzVal > (bias + threshold)){
        zValCounter++;
        Serial.println("z Val Counter increased");
      }
      sampleCounter++;
    }

 
    Serial.print("Z Total Count: ");
    Serial.println(zValCounter);

    /* Map the frequency calculated to the total amount of samples taken, creates the position
     *  the stepper motor has to go to. Playing around with minFreq and maxFreq will make this
     *  more or less sensitive*/
    int step_pos = map(zValCounter, minFreq, maxFreq, 0, samplePeriod);
    Serial.print("MOVE TO: ");
    Serial.println(step_pos);
    
    // Move the stepper motor to calculated position
    myMotor.moveTo(step_pos);
    
    while (myMotor.distanceToGo() != 0) { 
      myMotor.run(); 
    }

    Serial.println("DELAY.......");
    delay(500);

    // Moving stepper should have also moved potentiometer, read this value
    int pot_val = analogRead(POT_PIN);
    Serial.print("POT VAL: ");
    Serial.println(pot_val);

    // Map potentiometer value to a degree the servo must turn to
    int servo_degree = map(pot_val, 0, 1023, 0, 180);
    Serial.print("SERVO DEGREE: ");
    Serial.println(servo_degree);

    // Move servo motor
    s1.write(servo_degree);

    delay(250);

    Serial.println("****************");

}