Aziza's double transducer: light to linear position
Nora's double transducer: light to linear position
Daniel's double transducer: light to linear position
A string and a pulley to create linear movement
Taped pancake sensor and accelerometer
Circuits for Arduino
Motor glued to a posicle stick, connected by string to transfer motion
Aziza's final project
Daniel's final project
Nora's final project
On the left side of the board, there is a photoresistor that senses light. The Arduino in the middle receives the light brightness and converts it into vibration. The accelerometer and the vibration pancake are taped together at the top left. The accelerometer detects the vibration and sends the data to the Arduino. The vibration is transformed into a rotation angle for the rotation motor on the bottom right. The rotation motor is connected to a pulley that creates linear movement.
A block diagram for the circuit for vibration pancake.
A test run to verify to make sure that the vibration pancake runs correctly .
A test run to verify to make sure that the photoresistor runs correctly .
This is a small wooden box housing an accelerometer and a vibration pancake for precise motion detection. Although in the end we found it easier to just tape pancake and accelerometer.
We are testing the motor by adjusting light brightness.
We are building the final three projects, expanding on the original demo.
At first, we planned to build a wooden box to hold the accelerometer and vibration pancake, thinking it would keep them stable for better data collection. But after testing, we realized that simply taping them together gave us more accurate results. The box added extra vibration, which affected the data in unexpected ways. Sometimes a simpler solution works better.
One major difficulty with this double transducer was that it was difficult to get a consistent value reading from the pancake motor to the accelerometer. The value that were being read was very jumpy which translated to our servomotor which also jumped around. However, when we used the button to skip the middle step, the translation from photoresistor to servomotor was very smooth. Using a buzzer as the middle step was a difficult task to read a consistent value.
An aspect that was very successful in this project was the translation from rotation movement to a linear one through our pulley system. At first we were worried that the change in linear position wasn't great enough. Even though the servo motor would rotate drastically, the linear position movement was minimal. We solved this issue through attaching a popsicle stick to the servo motor arm which allowed the arm to pull the string with greater distance.
Our code for this project is below:
/*
Double Transducer, Light to Linear Position
Team 1 Members: Aziza, Nora, Daniel
Description: Our code is an Arduino-based control system
that uses multiple sensors and actuators. It reads data
from a photoresistor, an accelerometer, and a button.
Based on the inputs, it decides how to actuate a servo motor
and a vibrating motor. If the button is pressed,
the servo motor moves based on the light intensity detected
by the photoresistor, and the LCD screen displays input and output values.
If the button is not pressed, the vibrating motor is activated based
on the photoresistor’s reading, and the servo motor moves based on
detected vibrations from the accelerometer.
The LCD screen continuously updates with sensor values and actuator outputs.
Pin mapping:
Arduino pin | role | details
------------------------------
3 output Servo Motor Pin
A3 input reads light intensity
A0 input Accelerometer X-axis
A1 input Accelerometer Y-axis
A2 input Accelerometer Z-axis
10 output controls the vibration motor
8 input reads button
A couple of sources were referenced to understand how better to use the accelerometer and the way it is calibrated. After reading online forums, we set the output voltage of the accelerometer (a variable named zeroGValue below) to 1.35 voltage because others found that to be the best constant value for analog accelerometers when no acceleration is applied. In terms of sensitivity, we chose a value that would give more stable readings but at the same time not pick up any outside noise that was happening, a value usually between 0.165 and 0.660. These two values were then used to convert the raw voltage from the accelerometer into an acceleration value (g-units) with the formula acceleration(g) = (voltage reading - zeroGValue) / senstivity. Once this was calculated, we took the cubed root of the 3 values for a single read that can be fed into a vibration level.
1.https://forum.arduino.cc/t/how-to-calibrate-an-accelerometer/961066
3.https://learn.adafruit.com/adafruit-analog-accelerometer-breakouts/calibration-and-programming
4. https://docs.arduino.cc/built-in-examples/sensors/ADXL3xx/
For the rest of the code, including the photoresistor, screen, and servo motor, videos from the class was utilized as well as trial and error when putting together the project so we knew what was happening visually.
*/
#include <Arduino.h>
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Create an LCD display object with I2C address 0x27, 16 columns, and 2 rows
LiquidCrystal_I2C screen(0x27, 16, 2);
// Create a Servo object to control the motor
Servo doorMotor;
// Define pin assignments
const int servoMotorPin = 3;
const int photoresistorPin = A3;
const int Xpin = A0;
const int Ypin = A1;
const int Zpin = A2;
const int vibratingPin = 10;
const int buttonPin = 8;
// Accelerometer calibration constants
const float zeroGValue = 1.35;
const float sensitivity = 0.330;
void setup() {
pinMode(photoresistorPin, INPUT);
pinMode(vibratingPin, OUTPUT);
pinMode(buttonPin, INPUT);
Serial.begin(115200);
doorMotor.attach(servoMotorPin);
setUpScreen(); // Initialize LCD screen
}
void loop() {
// Gather data from the world (read inputs)
int buttonValue = digitalRead(buttonPin);
if (buttonValue == HIGH) {
int photoresistorValue = analogRead(photoresistorPin);
// Compute and/or make decisions
int motorRotation = map(photoresistorValue, 0, 1023, 10, 170);
// Actuate actuators (drive outputs)
doorMotor.write(motorRotation);
LCDPlusButton(photoresistorValue, motorRotation);
} else {
int photoresistorValue = analogRead(photoresistorPin);
int mappedPRValue = photoToVibrator(photoresistorPin);
// Compute and/or make decisions
float vibrationLevel = accelerometerInputToOutput(Xpin, Ypin, Zpin);
int motorRotation = mapFloat(vibrationLevel, 1, 2.9, 10, 170);
// Actuate actuators (drive outputs)
tone(vibratingPin, mappedPRValue);
doorMotor.write(motorRotation);
int updatedVibration = mapFloat(vibrationLevel, 0, 6, 0, 99);
Serial.println(updatedVibration);
LCDPlain(photoresistorValue, mappedPRValue, updatedVibration, motorRotation);
}
}
// Function to map a floating-point number to a new range
float mapFloat(float value, float fromLow, float fromHigh, float toLow, float toHigh) {
return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow;
}
// Convert photoresistor reading to a value suitable for the vibrating motor
float photoToVibrator(int photoresistorPin) {
int photoresistorValue = analogRead(photoresistorPin);
int mappedValue = map(photoresistorValue, 0, 1023, 0, 255);
return mappedValue;
}
// Read accelerometer data and calculate vibration level
float accelerometerInputToOutput(int Xpin, int Ypin, int Zpin) {
int rawX = analogRead(Xpin);
int rawY = analogRead(Ypin);
int rawZ = analogRead(Zpin);
float voltageX = rawX * (3.3 / 1023.0);
float voltageY = rawY * (3.3 / 1023.0);
float voltageZ = rawZ * (3.3 / 1023.0);
float accelX = (voltageX - zeroGValue) / sensitivity;
float accelY = (voltageY - zeroGValue) / sensitivity;
float accelZ = (voltageZ - zeroGValue) / sensitivity;
return sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ);
}
// Initialize and display a welcome message on the LCD screen
void setUpScreen() {
screen.init();
screen.backlight();
screen.home();
screen.print("Team 1:)");
delay(2000);
screen.clear();
}
// Display sensor readings when button is pressed
void LCDPlusButton(int photoresistorValue, int motorRotation) {
screen.home();
screen.print("i:");
screen.print(map(photoresistorValue, 0, 1023, 0, 99));
screen.setCursor(12, 1);
screen.print("o:");
screen.print(map(motorRotation, 10, 170, 0, 99));
delay(100);
}
// Display sensor readings when button is not pressed
void LCDPlain(int photoresistorValue, int mappedPRValue, int vibrationLevel, int motorRotation) {
screen.home();
screen.print("i:");
screen.print(map(photoresistorValue, 0, 1023, 0, 99));
screen.setCursor(6, 0);
screen.print("m:");
screen.print(map(mappedPRValue, 0, 255, 0, 99));
screen.setCursor(6, 1);
screen.print("m:");
screen.print(vibrationLevel);
screen.setCursor(12, 1);
screen.print("o:");
screen.print(map(motorRotation, 10, 170, 0, 99));
delay(100);
screen.clear();
}