Project 1 – Intro to Physical Computing: Student Work fall 2019 https://courses.ideate.cmu.edu/60-223/f2019/work Intro to Physical Computing: Student Work Sun, 06 Oct 2019 22:00:59 +0000 en-US hourly 1 https://wordpress.org/?v=5.2.20 Double Transducer: Vibration to Color https://courses.ideate.cmu.edu/60-223/f2019/work/double-transducer-vibration-to-color/ Tue, 24 Sep 2019 06:02:00 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8204 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("****************");

}

 

]]>
Double Transducer: Light-Sound-Rotation https://courses.ideate.cmu.edu/60-223/f2019/work/double-transducer-light-sound-rotation/ Tue, 24 Sep 2019 04:40:31 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8175

Overhead view of the double transducer with parts labeled and scale included.

Side view of the transducer. The signal is transduced from the front-left to the back-right.

Demo video showing the operation of the transducer. The knob is used to adjust to the increasing brightness.

Description

Our double transducer uses a photoresistor to translate light to sound. If the amount of light detected goes over a threshold set by the user using the knob, a buzzer will sound. The duration of the sound then determines how much the servo motor rotates.

Progress

Testing the I/O of the sound domain. This allowed us to determine a value for the volume threshold.

Initial wiring of the transducer. The cluttering made it difficult to debug our wiring issues.

We migrated to a larger breadboard to make the wiring more straightforward and organized the components by medium. The photoresistor (light) is on the left, the buzzer and sound detector in the middle, and the the servo (rotation) is on the right.

The final version required tape to secure the buzzer to the sound detector. This also reduced the interference of ambient noise.

Discussion

We initially planned to have the buzzer output a different volume depending on how bright the light was. We decided not to go this direction because we weren’t sure how to vary the voltage going into the buzzer in order to change the volume, and the amplitude sensor was pretty noisy. It also wouldn’t have worked well with the input since the group with light as an output didn’t vary the brightness of their LED, it was either on or off. We decided to change our approach and make the buzzer sound while the LED was on, since this would work better with the other group’s output and would be easier to detect with the sound detector.

Instead of intensity, we translated light to angular motion using time. This meant that we needed to make several decisions regarding the input/output of the three domains:

  1. The threshold light value to turn the buzzer on. This will be dependent on the ambient light of the room and the previous group’s light intensity.
  2. The volume threshold for the sound detector to consider the buzzer as on. This needs to be high enough to filter out the ambient noise, but low enough to not ignore the buzzer.
  3. The maximum anticipated duration of a buzzer sound. This will determine how responsive the servo is to changes in duration.

Wiring the circuit was fairly straightforward, but we had some trouble with the photoresistor. The analog input we read did not match our expectations, and we realized that it was most likely a wiring issue. We rewired the components in a different position on the board, and this fixed the problem. We believe that either we had originally connected the resistor to the wrong location.

Despite the fact that neither of us had worked with a sound detector before, it was fairly easy to wire up because the on-board electronics handle most of the audio signal processing. We were able to use the serial plotter to determine which input from the sound detector would be best for our project. We decided to use the envelope pin, which outputs the “volume” as an analog signal, and using the serial monitor we decided on a  threshold volume. We did notice that the signal can be noisy, so we also added a minimum duration threshold for the servo to be triggered.

Something we added on towards the end was a potentiometer to set the threshold value for the photoresistor. This allowed us to adjust for the ambient light of the room as we were chaining up our transducer with the other group’s.  It wasn’t much trouble to add it on, but we should have considered it when planning our project. If our circuit was more complicated, it might’ve been harder to add something in. Unfortunately, we did not make the maximum light duration value dynamically adjustable, which meant that we still needed to modify and re-upload a couple of times until our anticipated values matched the previous group’s actual light duration.

Schematic

Code

/*
 * Project 1: Light -> Sound -> Rotation Double Transducer
 * 
 * Description: A transducer that translates light from a
 * photoresistor into sound, and output the duration
 * of the sound as an angle [0, 180] on a servo motor
 * 
 * Inputs: Switch, button, potentiometer, photoresistor
 *  Arduino pin |  input
 *  A2             Potentiometer (Adjust light threshold)
 *  A1             Sound Detector
 *  A0             Photoresistor
 *  
 *  Outputs: Speaker, serial, servo
 *  Arduino pin |  output
 *  11             Piezo Buzzer
 *  10             Servo
 *  
 */
#include <Servo.h>
const int POT_PIN = A2;
const int SOUND_PIN = A1;
const int PHOTO_PIN = A0;
const int SERVO_PIN = 10;
const int BUZZER_PIN = 11;

//Threshold for detecting if buzzer is on
const int VOL_THRESHOLD = 300;

//Threshold ranges for the light/sound durations (ms)
const int MIN_TIME = 50;
const int MAX_TIME = 400;

unsigned long time;

Servo servo;

void setup() {
  Serial.begin(9600);
  pinMode(SOUND_PIN, INPUT);
  pinMode(PHOTO_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  servo.attach(SERVO_PIN);
}

void loop() {
  
  int brightnessVal = analogRead(PHOTO_PIN);

  // Adjust potentiometer to calibrate what is ambient light
  // and what brightness will turn on the buzzer.
  int lightThreshold = analogRead(POT_PIN);

  // Turn buzzer on if light is above threshold
  if (brightnessVal > lightThreshold) {
    tone(BUZZER_PIN, 440);
  } else {
    noTone(BUZZER_PIN);
  }

  // If sound stopped on this loop, calculate how long sound
  // had previously been on
  unsigned long elapsed = 0;
  if(analogRead(SOUND_PIN) < VOL_THRESHOLD) {
    elapsed = millis() - time;
    time = millis();
  }
  
  //Use the serial plotter to help calibrate against ambient light
  Serial.print(brightnessVal);
  Serial.print(" ");
  Serial.println(lightThreshold);

  //Rotate servo arm based on duration
  if (elapsed > MIN_TIME) {
    servo.write(map(elapsed, 0, MAX_TIME, 0 ,180));
  }
}

 

]]>
Double Transducer: Rotation to Magnetic Field https://courses.ideate.cmu.edu/60-223/f2019/work/double-transducer-rotation-to-magnetic-field/ Tue, 24 Sep 2019 03:08:07 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8178

Double transducer: rotation to magnetic field

Title: Double Transducer – Rotation to Magnetic Field

Description:

Our group has the input domain of rotation, and an output domain of magnetic field. We decided to use the middle domain as light. A small servo motor is attached to a mechanism that moves the slider of a linear potentiometer. The potentiometer is connected to an LED which gets brighter and dimmer. The LED is placed closed to a photo resistor. If the resistance value is higher than a certain set point, the servometer with the magnet attached moves to a 175 degree angle. If it is less than the set point, it moves to a 0 degree angle. The magnet on the servo motor constantly gets rotated to face another magnet, which creates a magnetic field. When the servo motor is rotated away from the magnet, there is no magnetic field.

The magnet attached to the servomotor to create a magnetic field.

The LED is positioned right up to the photoresistor for the best reading of values underneath the tape.

The mechanism that converts rotational movement into linear movement is attached to a potentiometer.

Rotation to magnetic field double transducer.

 

Process:

Our first attempt using popsicles sticks to create the mechanism that converts rotational movement into linear movement. It failed many times.

Revising the mechanism to become simpler and less fragile.

Success! The rotation-to-linear movement mechanism at two different positions.

 

Discussion:

An important problem that we needed to solve as a team was converting the rotation of the incoming servo motor to an analog electronic signal.  We found that the most effective way to achieve this was through a rotational to linear converter. The servo arm was attached to a linear sliding variable resistor with a rigid arm .  The arm had the ability to rotate freely so that the arm could always be attached to both points, and the rotation of the servo will push and pull the resistor, changing the voltage value in a voltage divider.

Interfacing electronics with the physical domain was a challenging part of our project.  This was apparent when incorporating the linear sliding potentiometer. Originally, a popsicle stick casing was created to fix the potentiometer, but the hot glue used broke the electronic component. To solve this problem, we placed the potentiometer in a breadboard, and applied force at an angle that would not remove it.  For future projects we will consider the fragility of electronics components before hand to save time and effort.

One of the more difficult parts was to get a clear relationship between the changing rotation input and the magnetic field output. We had imagined that the photoresistor would have resistance values that would be mappable directly to the rotation of the end servomotor. However, the readings on the photoresistor were very noisy. We tried to eliminate external lights using tape. The servomotor would twitch to angles that seemed random.  It made it difficult to tell the relationship between the input rotation and the output rotation. Therefore we decided to divide the values from the photoresistor according to a certain setpoint. The result may be a little less fun than having a range of values, but we think it makes for a clearer system. 

Another difficult part that is related to the point above is deciding what the set point should be. We had to test several points, which often had a result of the servometer and the end twitching constantly because the resistance values were stuck in between the points we had decided. When we had come to a conclusion of points that seemed to work, we learned that we had to make sure that the physical factors were all unchanging, for example the position of the LED and photoresistor, and the lighting of the environment we were in.

Schematic:

The schematic for this double transducer.

 

/* Project: Rotation to Light to Magnetic Field Double Transducer
 *
 * Summary: Our code takes the input from a voltage divder
 * with a potentiometer and lights up an LED with a brightness determined
 * by the position of the potentiometer.  A voltage divider with a 
 * photoresistor sensing the light is read by the code, and a servo motor is
 * turned to one of two positions depending on the light level. The code
 * also prints the brightness and potentiometer value to the serial monitor 
 * to make debugging easier
 * 
 * Inputs:
 *  Arduino pin | input
 *  A0            sliding potentiometer
 *  A1            photoresistor
 *  
 * Outputs:
 *  Arduino pin | output
 *  3             blue LED
 *  5             servo motor
 */


#include <Servo.h>

//analog sensors
const int POT_PIN = A0;
const int PHOTO_PIN = A1;

//digital sensors
const int LED_PIN = 3;
const int SERVO_PIN = 5;


Servo myServo; // creates motor

void setup() {

  //input pins
  pinMode(POT_PIN, INPUT);
  pinMode(PHOTO_PIN, INPUT);

  //pin outputs
  pinMode(LED_PIN, OUTPUT);
  pinMode(SERVO_PIN, OUTPUT);

  //attach servomotor 
  myServo.attach(SERVO_PIN);



 
  Serial.begin(9600);

}

void loop() {



  int potVal = analogRead(POT_PIN);

  Serial.println(potVal);

  int Brightness = map(potVal, 0, 1023, 0, 255);

  analogWrite(LED_PIN, Brightness);

  int BrightnessVal = analogRead(PHOTO_PIN);


  Serial.println(BrightnessVal);

  // motor responds to brightness level, the lack of a hard dividing point
  // prevents rapid twitches in the servo.  We picked these values experimentally through best judgement
  
  if (BrightnessVal < 400) {
    myServo.write(5);
  } 
  else if (BrightnessVal > 850) {
    myServo.write(175);
  }

  delay(200);
}

 

]]>
Double Transistor: Sound – Motion – Light https://courses.ideate.cmu.edu/60-223/f2019/work/double-transistor-sound-motion-light/ Sun, 22 Sep 2019 21:29:55 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8116 Project Desription

When a sound is made, this project rotates a motor with an accelerometer attached. When the accelerometer is rotated, a LED light blinks.

Our project in action

Detail Photos

Microphone Piece

Motor and accelerometer

LED Light

Process Photos

Potential LEDS

One of the earliest decisions we had to make was what LED to use to blink light. We liked the idea of using the LED with the bars in order to show different levels of input, but realized that it would be more difficult for the group whose input was light to detect the changes.

 

 

 

First Iteration of our project

In our initial iteration of this project, we stuck to simpler parts and worked with one input at a time. We used a smaller servo motor and taped a popsicle stick to the end, with the accelerometer taped on top of that to detect motion. We also used a basic 5V LED light. Once we got these smaller parts to work with our software, we changed some of the parts to refine the project. For example, we used a bigger servo motor to both create a greater range of motion and to reduce the noise interference with the sound input (the small servo motors are quite noisy!).

first iteration of project with popsicle stick motor arm

In our later iterations of this project, we added better and more secure wiring (not just using long streams of female-male parts) and mounted the parts to cardboard to make it more secure and standardized (which was important for detecting motion).

More refined iteration of our project

Discussion

Our initial approach was to start with the parts we knew and had learned about in the class and make sure they worked with the software we wrote before upgrading the parts to make the project more refined. We thought this approach was really helpful for us, and helped us to really perfect our software before having to fiddle with the hardware. For future projects, we think that this iterative, simplified approach will be a helpful guideline to follow.

One of the hardest parts of this project was defining the threshold for sound and motion. It was really difficult to test sound due to the noise of the rooms we were in, the noise coming from our parts, and due to the overall noisy nature of detecting analog input. We were able to find a good threshold only through multiple series of testing and iterating, in which we watched the serial plotter religiously and tried to identify peaks in the data points. We followed this same process for detecting motion with the accelerometer; we watched and used the data we saw on the serial plotter to inform our decisions for thresholds. We found that the data gained from the accelerometer was not at all what we expected as the largest peaks were shown through the z-axis. Rather than relying on our intuition, it was really important for us to rely on the empirical data we saw through testing, and to use that to write our code.

One of the easier parts of this project was implementing the light output, as we were familiar with the LED part and had used it for multiple previous projects. We considered using a neo-pixel diffused LED, which could take inputs and change color based on those inputs, but we found the library difficult to use and ultimately decided that, since the output was sound and not color, using the simple LED would suffice.

Because we stuck to the parts and signals that we were relatively familiar with, we may have limited ourselves in the project we were able to produce. While our project ultimately fulfilled the task handed to us, there may have been ways that we could have made our project “cooler” or more interesting had we gone more out of our comfort zones and experimented with new parts and signals. In the future projects for this class, we both hope to think more creatively and try new and wildly different things to create really interesting projects.

Schematic

schematic

Code

// Double Transistor from Sound - Motion - Light
//
// Every half of a second, the program reads the input from a mic
// if the mic input is greater than a certain threshold (entered here as 725)
// it moves the servo motor
// within the loop the code is always checked the input from the accelerometer
// if the z-axis moves above a threshold, we turn on a LED light
//
//ARDUINO INPUTS
//  A2 | MIC INPUT
//  A3 | ACCELEROMETER INPUT
//
//ARDUINO OUTPUTS
//  A1 | SERVO MOTOR
//   5 | LED LIGHT


#include <Servo.h>

const int MIC_IN = A2;
const int SERVO_OUT = A1;
const int LED_IN = 5;

// For this device, we only read the Z PIN
const int ZPIN = A5;

int servoSwitch = 0;

Servo servo;

void setup() {
  pinMode(MIC_IN, INPUT);
  pinMode(LED_IN, OUTPUT);
  pinMode(SERVO_OUT, OUTPUT);

  pinMode(XPIN, INPUT);
  pinMode(YPIN, INPUT);
  pinMode(ZPIN, INPUT);

  servo.attach(SERVO_OUT);
}

void loop() {
  //check if z-axis of the accelerometer is above threshold
  if (analogRead(ZPIN) > 300) {
    digitalWrite(LED_IN, HIGH);
  }
  else {
    digitalWrite(LED_IN, LOW);
  }
  //checking mic input for half a second every second
  if (millis() % 1000 < 500) {
    if (analogRead(MIC_IN) > 725) {
      servoMove();
    }
  }
}

//moves the servo back and forth once
void servoMove() {
  if (servoSwitch) {
    servo.write(5);
    servoSwitch = 0;
  }
  else {
    servo.write(85);
    servoSwitch = 1;
  }
  delay(100);
}

 

]]>
Double Transducer: Color to Linear Position https://courses.ideate.cmu.edu/60-223/f2019/work/double-transducer-color-to-linear-position/ Tue, 17 Sep 2019 02:26:10 +0000 https://courses.ideate.cmu.edu/60-223/f2019/work/?p=8094 Title: Double Transducer: Color to Linear Position

Overhead shot of the double transducer. The main components are labelled with names and numbers 1-3 which correspond to the order by which things are transduced.

Servo motor arm close-up. The black pin moves linearly along the track. The pieces were laser cut and attached using pins and glue.

The DIY color sensor without the color insert. RGB LEDs flash in sequence inside the 3D printed cover. The blue LED is on in this instance.

The working sequence. The arm extends when the color sensor detects red; once the red coin is removed, the arm retracts.

Description: A power source powers a color sensor, which sends a signal to generate a magnetic field when it detects a change in color. The presence of a magnetic field will in turn cause the motor to turn, moving an arm linearly along a track.

Progress:

Here we are testing the range of the servo motor arm and the distance this translates to along the track.

The failed first attempt at 3D printing a black-out cover for the color sensor. The tube was too small to cover the 3 LEDs and the photocell. We also chose red and yellow inserts for the final.

Wrapping copper wire to create the coils. This took some experimentation because we didn’t wrap around enough times in the first few attempts.

Discussion:

The makeshift RGB sensor worked surprisingly well after being wired up correctly, although the compact design increased the difficulty of properly wiring 3 LEDs and a photoresistor into the space of a little more than a square centimeter of space. The length of the legs of the LEDs were rather close, so at least one of the LEDs was inserted in the wrong direction initially. Despite minor problems, the RGB signal distinctly changed by about 100 for the red value after the red colored disk was inserted, which was a great success. However, it should be noted that the red signal was comparatively weaker, even with nothing else within the black casing, suggesting the possibility that the light from the previous LED isn’t given enough time to fade away. Admittedly, these were issues for the color sensor that weren’t predicted when designing the code and schematic from a purely theoretical perspective, but it did work as desired; this simple sensor exemplifies how valuable planning ahead was, yet it also reinforces how certain challenges might only be discovered in practice.

The solenoid system was neither simple or ended up working all too well. Numerous challenges arose, some from construction and others from human error. Although advice (thank you Zach for all the help with getting the solenoid circuits set up)  and research produced circuits that would ideally work well with more powerful solenoids,  the initial solenoid wire coils were initially only around a half-centimeter thick. So while the ‘drive coil’ (the coil that’s actively charged/discharged to produce a changing magnetic flux) could produce a tangible ‘pulse’ in a ceramic magnet disc held nearby, no signal could be detected in the receiving coil. After expanding the wire coils to a thickness of well over a centimeter, there still appeared to be no readable signal. This time it was due in part how the code, written beforehand, had used ‘digitalRead()’ instead of ‘analogRead()’, which made it impossible to detect the weak signal. Irregularities with how the Arduino was powered also interfered with consistent results. Overall, this experimental feature was a unique experience to test an unconventional signal transduction method and presented its fair share of challenges. Exercising good caution in design prevented any accidents from happening, though it might’ve been better to remove an existing coil from some motor or other component that was already wrapped and saved that time.

The linear motion servo made for little difficulty on the coding end since a library was available to easily interface with the device, requiring just a little calibration. Coming up with a design to convert its rotation to linear motion and constructing the largely mechanical instead of electrical component was another matter.

Schematic:

Code:

/* Project 1: Double Transducer

   Description: This code detects a color signal with a photoresistor and RGB LEDs, transmits that signal across two inductors,
   and passes out a 'positive' signal by driving a servo arm to extend a linear motion device.

   Resources Referenced:
   https://www.arduino.cc/reference/en/
   http://www.physics-and-radio-electronics.com/electronic-devices-and-circuits/rectifier/bridgerectifier.html
   https://create.arduino.cc/projecthub/mjrobot/arduino-color-detection-57e4ce?ref=tag&ref_id=color-detector&offset=0
   https://www.instructables.com/id/How-to-Control-an-Electromagnet-with-an-Arduino/

   Outputs
   Arduino Pin | Output
   2              Red LED
   3              Green LED
   4              Blue LED
   6              Output inductor Pin
   7              Servo Pin

   Input
   Arduino Pin | Input
   A0            Photoresistor
   A5            Input inductor Pin
*/

#include <Servo.h>

//Linear Motion
const int SERVO_PIN = 7; //OUTPUT, digital. Servo control pin.

const unsigned int rPeriod = 1000; //Parameter: refractory period for servo. Time for which a change to servo state cannot be changed again.

Servo arm; //Servo 'object'

bool moveConfirmed = false; //UTILITY: when true, arm extends at the end of the next refractory period, otherwise it'll retract
unsigned long lastmove = 0; //UTILITY: counter to determine time until refractory ends

//magnetic domain
const int O_MAG_PIN = 6; //OUTPUT, digital. Controls transistor powering the inductor.
const int I_MAG_PIN = A5; //INPUT, analog. Reads the read inductor

//magnetic domain: output
const unsigned long togThresh = 300; //PARAMETER, toggle output frequency in milliseconds. This determines how frequently the output inductor produces flux when it is permitted to do so.

unsigned long lasttoggle = 0; //UTILITY, toggle: Time since magnet signal was last toggled on/off. Only when the magnet is toggled
bool toggle = true; //UTILITY, toggle: used to determine which toggle step, on or off.

//magetic domain: input
const int thresh = 200; //UTILITY, minimum signal from the input pin from the inductor classified as a read
const int readTime = 200; //UTILITY, milliseconds taken by the entire read step
const int readFrq = 20; //UTILITY, number of times reads are taken in the

//Color Sensor
//(light detector)
const int PHOTO_PIN = A0; //INPUT, analog. Photoresistor pin. Signal corresponds to light level.
//(LED colors)
const int R_LED_PIN = 2; //OUTPUT, digital. RED LED pin, flashes first in series.
const int G_LED_PIN = 3; //OUTPUT, digital. GREEN LED pin, flashes second in series.
const int B_LED_PIN = 4; //OUTPUT, digital. BLUE LED pin, flashes last in series.

int target[3] = {300, 460, 230}; //PARAMETER for the RED  disk, must be calibrated based on lighting levels
//NOTE: Pervious testing values: casing has a color of about (195, 380, 295). RED side has about (270, 400, 250)

const int tolerance = 15; //UTILITY, +/- range that color matches target
int color[3]; //UTILITY, virtual RGB container variable representing the reflected color data

void setup() {
  // put your setup code here, to run once:
  //For debugging and viewing the inductor receiving signal
  Serial.begin(19200);

  //Linear Motion
  //OUTPUT
  arm.attach(SERVO_PIN);

  //Magnetic domain
  //INPUT
  pinMode(I_MAG_PIN, INPUT);
  //OUTPUT
  pinMode(O_MAG_PIN, OUTPUT); //To transistor


  //Color Sensor
  //INPUT
  pinMode(PHOTO_PIN, INPUT);
  //OUTPUT
  pinMode(R_LED_PIN, OUTPUT);
  pinMode(G_LED_PIN, OUTPUT);
  pinMode(B_LED_PIN, OUTPUT);

  delay(1000); //wait for the servo arm, as there may be cases where the signal is immediately present as soon as loop goes through
}

void loop() {
  // put your main code here, to run repeatedly:

  //Perform detection: check if RGB has changed enough to match some signal color
  colorRead(100); //Color detection; values stored in global array with a delay of 100 between each color.

  //Debugging line: Color input
  Serial.println((String)(color[0]) + " " + (String)(color[1]) + " " + (String)(color[2]));

  //if condition is met, power the inductor
  if (inThreshold()) {
    driveInductor();
  }

  //read the receivor inductor and confirm it has moved
  moveConfirmed = moveConfirmed || readInductor();

  //Attempts to move servo arm. Only proceeds if the refractory period has passed
  moveServoArm();
}

//move servo arm out and in
void moveServoArm() {
  //whenever the refractory period has passed, the arm is allowed to move again
  if (millis() - lastmove > rPeriod) {
    //moves arm when enough time has passed
    arm.write((moveConfirmed) ? 60 : 5); //If a move signal is measured at this step, move the arm out, otherwise pull it back in.
    lastmove = millis();
    moveConfirmed = false;
  }
}

//charge and discharge inductor to produce a varying flux
void driveInductor() {
  //if time since last toggle exceeds the threshold, toggle the inductor drive pin
  if (abs(millis() - lasttoggle) > togThresh) {
    digitalWrite(O_MAG_PIN, (toggle) ? HIGH : LOW);
    lasttoggle = millis();
    toggle = !toggle;
  }

}

//indicates whether there is substantial voltage induced from changing flux in the read inductor
bool readInductor() {
  //records if the signal ever exceeds a threshold
  bool successfulRead = false;
  for (int i = 0; i < readFrq; i++) {
    int fluxread = analogRead(I_MAG_PIN);
    //Debugging: Flux measurement results
    //Serial.println(fluxread);

    //checks if signal exceeds a threshold.
    successfulRead = successfulRead || fluxread > thresh;

    delay(readTime / readFrq); //divides the delay time into readFrq number of segments for a total of readTime worth of time

  }
  return successfulRead;
}

//Checks if light is within the threshold of being a target
bool inThreshold() {
  //loops for 1,2,3 or RGB to check all values are within tolerance threshold
  for (int i = 0; i < 3; i++) {
    if (abs(target[0] - color[0]) > tolerance)return false;
  }
  //if for no color it returns false, then all colors are in tolerance
  return true;
}

//Checks color by flashing each RGB LED color for reflection from chamber and sets value in color array
//frq variable used to control delay between reads, or the speed of the flashes.
//In theory, a longer delay would result in higher accuracy but sacrifice responsiveness and speed
void colorRead(int frq) {
  setLED(0); //reset to no LEDs
  setLED(1); //RED LED ON
  delay(frq);
  color[0] = analogRead(PHOTO_PIN); //read RED
  setLED(0);
  setLED(2); //GREEN LED ON
  delay(frq);
  color[1] = analogRead(PHOTO_PIN); //read GREEN
  setLED(0);
  setLED(3); //BLUE LED ON
  delay(frq);
  color[2] = analogRead(PHOTO_PIN); //read BLUE
  setLED(0);
}

//Sets the LEDs on/off based on a key value. A switch case might work even better, but this function is still perfectly functional.
void setLED(int key) {
  if (key == 0) {
    digitalWrite(R_LED_PIN, LOW);
    digitalWrite(G_LED_PIN, LOW);
    digitalWrite(B_LED_PIN, LOW);
  }
  else if (key == 1)digitalWrite(R_LED_PIN, HIGH);
  //else digitalWrite(R_LED_PIN,LOW);
  else if (key == 2)digitalWrite(G_LED_PIN, HIGH);
  //else digitalWrite(G_LED_PIN,LOW);
  else if (key == 3)digitalWrite(B_LED_PIN, HIGH);
  //else digitalWrite(B_LED_PIN,LOW);
}

 

]]>