Title: Double Transducer: Color to Linear Position
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:
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); }
Comments are closed.