Arduino tutorial 30 - Draw Spectrum

Welcome to the "Draw Spectrum" project! In this project, we will transmit light sensor data read from an Arduino to Processing in real-time and visualize it. You will learn how to calculate the average light intensity to reduce noise interference. Additionally, you will create a simple interface in Processing to display the fluctuating spectrum as the light changes. Now, let's embark on this exciting journey!

 

COMPONENT LIST

 

 

HARDWARE

 

Please connect the hardware according to the following diagram.

 

fig 1 Draw Spectrum Circuit

 

CODE

 

Processing Sample Code:

CODE
// Project - Draw Spectrum
import processing.serial.*;
int[] Ypoint; // Coordinates on the vertical direction

Serial myPort; 
int val; // Data received from the serial port

void setup()
{
size(640, 360);
colorMode(HSB, 1000); 
Ypoint = new int[width]; 
String portName = "COM5"; // Open the port you are using.
myPort = new Serial(this, portName, 9600); 
print(portName); 
}

void draw()
{
background(900); // Set the background to gray

// Shift the Ypoint array to the left
for (int i = 1; i < width; i++) {
Ypoint[i - 1] = Ypoint[i];
}

if (myPort.available() > 0) {
val = myPort.read(); // Read the data and store it in val
}

int x = 1; 
Ypoint[width - 1] = val; 

// Draw the curve
for (int i = 0; i < width - 1; i++) {
x++; 
line(i, height, i, map(Ypoint[i], 0, 255, 0, height)); // Convert light intensity to Y coordinate
stroke(x, 800, 800); 
}

println(val); // Print the received value
}

Arduino Sample Code:

CODE
//project - Draw Spectrum
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int lightSensorPin;

const int numReadings = 10;
int readings[numReadings];
int readIndex = 0;
long total = 0;
int average = 0.0;

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

  for (int thisReading = 0; thisReading < numReadings; thisReading++) {//build the list
    readings[thisReading] = 0;
  }

  lightSensorPin = 0;
  pinMode(lightSensorPin, INPUT);

}

void loop() {

  readings[readIndex] = analogRead(lightSensorPin);
  total = total + readings[readIndex];
  readIndex = (readIndex + 1) % numReadings;
  average = total / numReadings;
  total = total - readings[readIndex];//substract th eold readings

  delay(50);
  average = map(average, 0, 1023, 0, 255);
  Serial.write(average);
  
}

Uploading the code to Arduino, then open the Processing software, and click to run it. Wait for the data transmission to stabilize (about 5 seconds). You can then shine a flashlight on the ambient light sensor or move it away, and observe that the spectral curve on the computer adjusts according to the light intensity.

 

CODE REVIEW

 

This project primarily utilizes Arduino to receive and process light intensity data, and sends the processed brightness values to Processing for visualization through serial communication. Specifically, Arduino captures the ambient light brightness in real-time through a light sensor and converts it into digital values. Subsequently, these brightness values undergo necessary processing to ensure data accuracy and reliability. The processed brightness values are then sent to Processing in real-time through serial communication. In Processing, based on the received brightness values, a dynamic spectral area is drawn, with its ups and downs intuitively representing real-time changes in light brightness. This provides users with an intuitive and real-time monitoring tool for changes in light brightness.

 

Processing

 

In the setup() function:


The window size and color are set. The Ypoint array is also initialized with a length equal to the window's width (i.e., 640), which is used for drawing vertical lines.

 

size(640, 360);

colorMode(HSB,1000);

Ypoint = new int[width];

 

Set up serial communication and print the serial port name.

 

String portName = "COM6"; 

myPort = new Serial(this, portName, 9600);

print(portName);

}

 

In the draw() function:

 

Shift the elements in the Ypoint array one position forward to make space for new data.

 

for (int i = 1; i < width; i++) { 

   Ypoint[i-1] = Ypoint[i]; 

  }

 

If there is data available to read from the serial port, read one byte of data from the serial port and store it in the variable val.

 

   if ( myPort.available() > 0) { 

   val = myPort.read(); 

  }

 

Assign the newly read value to the last element of the Ypoint array.

 

 Ypoint[width-1] = val; 

 

The purpose of this code segment is to draw a series of vertical lines based on each element value in the array Ypoint[]. The x-coordinates of these lines correspond to their indices in the array, while the y-coordinates are converted from the range of 0 to 255 of Ypoint[i] to the vertical range of the window (from 0 to height) using the map() function. Additionally, the self-incrementing x value is utilized to achieve color variation for each vertical line.

 

 int x=1;

 for(int i = 0; i < width-1; i++) {

   x++;

   line(i, height, i, map(Ypoint[i], 0, 255, 0, height)); 

   stroke(x,800,800);

  }

 

Arduino

 

In the setup() function, initialize the readings array in a loop, setting all elements to 0.

 

for (int thisReading = 0; thisReading < numReadings; thisReading++) {

    readings[thisReading] = 0;

  }

 

In the loop(),

 

int newReading = analogRead(lightSensorPin); 

 

Read the current analog value of the light and store it in the current index position of the readings array.

 

total = total - readings[readIndex] + newReading;

 

Update the value of total by first subtracting the old reading that is being replaced and then adding the new reading.

 

readings[readIndex] = newReading;

 

Store the new reading in the current index position of the readings array.

 

readIndex = (readIndex + 1) % numReadings;

 

Update the value of readIndex to point to the next array position, and if it reaches the end of the array, loop back to the beginning.

 

average = total / numReadings;

 

Calculate the average of all readings and assign it to the average variable.

 

int mappedValue = map(average, 0, 1023, 0, 255);

Serial.write(mappedValue);

 

Since Serial.write can only write 8-bit binary values, which range from 0 to 255, the map function is used to map the average value from the range of 0 to 1023 to the range of 0 to 255. Then, the integer part of mappedValue is sent through the serial port (to be used in conjunction with the corresponding data receiving statement in Processing).

icon Draw_Spectrum.ino.zip 1KB Download(0)
icon Draw_Spectrum_processing.pde.zip 1KB Download(0)
License
All Rights
Reserved
licensBg
0