Arduino - Receive Multiple Osc Values at ones - arduino

I am trying to send from max msp some values. I have no problem in receiving them however, when I try to send multiple values at one I have some troubles. Is there a way to get multiple values?
using the code below I am getting :
> pixelNum: 10 pixelState: 0 pixelNum: 1 pixelState: 0
void loop() {
OSCMessage msgIN;
int size;
if((size = Udp.parsePacket())>0){
while(size--)
msgIN.fill(Udp.read());
if(!msgIN.hasError()){
msgIN.route("/pixelAni",pixelAni);
}
}
}
void pixelAni(OSCMessage &msg, int addrOffset){
int pixelNum = msg.getInt(0);
int pixelState = msg.getInt(1);
Serial.println("pixelNum: ");
Serial.println(pixelNum);
Serial.println("pixelState: ");
Serial.println(pixelState);
pixels[pixelNum].R = 255;
pixels[pixelNum].G = 255;
pixels[pixelNum].B = 255;
ledstrip.show(pixels);
}

So many options! The simplest would be the pack object, when it receives an input to its left most inlet it will output. Since max data flows Top to Bottom and Right to Left, this should gaurantee that you allways output both numbers
You could use the buddy or thresh objects to sync up the messages if you cant guarntee they arrive at exactly the same time

Related

How to convert the ANALOG value of a pulse sensor to BPM?

first of all I would like to apologise for not speaking English very well.
My problem is the following: I have an arduino sensor (the iDuino SE049). I need to transform the analog value into BPM value.
So first I have to eliminate the drift (slide, (I don't know the precise word)) that the sensor can encounter. To do this I am advised to :
❶Work on an array of X values
❷Calculate the average
❸Subtract the average from each of the values
After I need to find the optimal value for X with the curve on Arduino IDE (I work on 1.8.19 version).
(Start with X = 50 for the size of the array, my teacher told me that)
Once I have this average, I need to make the system robust to light changes.
Problem: The amplitude varies so we can't work with a fixed threshold.
The heart rate is hidden in temporal information. You just need to be able to measure the characteristic time.
Solution : I can work with a curve that always has maximum amplitude of 1, then find an ideal threshold.
❶Work on the table of X values after eliminating the drift.
❷Look for the maximum
❸Divide all values by this maximum
❹Split by a threshold value
And then I have to do the study to find the threshold value
I tried to do a code that didn't worked well for the drift/slide, and average of the signal. But it didn't worked well because I can't get the value of the average outside of my loop to substract it to the analog value readed by the sensor.
I want to get all the value readed by the sensor during a time of 20 milliseconds, thats why I use the function millis(). And all this values needs to be stored in my array.
#include <Arduino.h>
int Sensor = 0;
//#define start_read 0
float tab[20]={0};
float sum = 0;
int i;
void setup() {
Serial.begin(9600);
}
void loop ()
{
unsigned long currentTime=0;
while (millis() - currentTime > 20)
{
tab[i] = analogRead(Sensor);
i++;
sum += tab[i];
float average = sum/20;
Serial.println(average);
}
currentTime = millis();
i = 0;
}
I have another code to test, I should work but it's not I don't know why : The variable names are in French but you can copy it and change the name to work on it if it's clearer, I'll understand the changes.
#include <Arduino.h>
int sensor=A0, comp=1, var=0;
float bpm=0;
double temps;
const int nbr=50;
float tab[nbr]={0}, moyenne=0, maximum=0;
void setup() {
Serial.begin(9600);
pinMode(sensor, INPUT);
}
void loop() {
maximum=0;
moyenne=0;
for (int i = 0; i < nbr; i++)
{
tab[i]=analogRead(sensor);
moyenne=moyenne+tab[i];
delay(40);
}
moyenne=moyenne/nbr;
for (int i = 0; i < nbr; i++)
{
tab[i]=tab[i]-moyenne;
}
maximum=tab[0];
for (int i = 0; i < nbr; i++)
{
if (tab[i]>maximum)
{
maximum=tab[i];
}
}
for (int i = 0; i < nbr; i++)
{
tab[i]=tab[i]/maximum;
}
for (int i = 0; i < nbr; i++)
{
if (tab[i]>(0.950))
{
bpm++;
}
}
temps=(millis()/1000);
var=15*comp;
if (temps/(var)>=1)
{
bpm=bpm*4;
//Serial.setCursor(0,10);
Serial.print("BPM : ");
Serial.print(bpm);
Serial.println("♥️");
//Serial.display();
//Serial.clearDisplay();
comp=comp+1;
bpm=0;
}
}
I can't get the value of the average outside of my loop
average is declared inside the loop so when an iteration ends it goes out of scope. You should declare it outside the while loop.
I want to get all the value readed by the sensor during a time of 20 milliseconds
You probably want to get something like 1 value per millisecond because all the values readed in 20 milliseconds are not 20 also you may not be able to know the exact number of values as it depends on the sensor's sample rate among other things.
If you need to reed those values to get a fixed threshold (i.e. use the code to study some behavior and get a const that will be used in the second code), put the code in void setup() instead of void loop() otherwise it will loop forever.
void loop ()
{
unsigned long currentTime=0;
while (millis() - currentTime > 20)
{
tab[i] = analogRead(Sensor);
i++;
sum += tab[i];
float average = sum/20;
Serial.println(average);
}
currentTime = millis();
i = 0;
}
Here there are some problems. Every time void loop() ends and executes again currentTime its going to be deleted and declared again holding the value 0. This makes the while loop execute for an infinite amount of time causing i to increment over tab's length leading to memory errors.
Also analogRead() does not return a float (returns an integer between 0 and 1023).
That's what I found about the first code, but about the second one I don't understand what is the problem. It is a compiling error? You don't get the expected output in the serial monitor? If it's the last thing, what is the output?

How can I calculate a moving average in Arduino?

I have to add a moving average to my program which is working now with ultrasonic sensor with Arduino.
First screen of my code
Second screen of my code
The third screen of my code
I hope the following code will help you:
//Parameters
const int aisPin = A0;
const int numReadings = 10;
int readings [numReadings];
int readIndex = 0;
long total = 0;
//Variables
int aisVal = 0;
void setup() {
//Init Serial USB
Serial.begin(9600);
Serial.println(F("Initialize System"));
//Init AnalogSmooth
pinMode(aisPin, INPUT);
}
void loop() {
readAnalogSmooth();
Serial.print(F("ais avg : ")); Serial.println(smooth());
delay(200);
}
void readAnalogSmooth( ) { /* function readAnalogSmooth */
////Test routine for AnalogSmooth
aisVal = analogRead(aisPin);
Serial.print(F("ais val ")); Serial.println(aisVal);
}
long smooth() { /* function smooth */
////Perform average on sensor readings
long average;
// subtract the last reading:
total = total - readings[readIndex];
// read the sensor:
readings[readIndex] = analogRead(aisPin);
// add value to total:
total = total + readings[readIndex];
// handle index
readIndex = readIndex + 1;
if (readIndex >= numReadings) {
readIndex = 0;
}
// calculate the average:
average = total / numReadings;
return average;
}
The basic concept is the same, keep a fixed window size and shift the window after each reading.
Note: Please change the above code according to your need.
There are lots of ways to implement a moving/sliding average. One simple one that I've implemented is below, which works much the same way as HARSH's that he posted in his previous answer. This function, though, is a little more generic and can be used as-is for any data source and you can test it out on any platform. It also handles the startup case when values are first being populated. It is specific, though, to one source. So if you need a moving average for each of multiple sources, you'll have to duplicate the function or modify it to handle multiple sets of data. This uses float values for the data. Even if your data is integer, I'd suggest leaving the averaging data as float. Again, this is a simple averaging where all data values in the window have the same weight.
float movingAverage(float value) {
const byte nvalues = 8; // Moving average window size
static byte current = 0; // Index for current value
static byte cvalues = 0; // Count of values read (<= nvalues)
static float sum = 0; // Rolling sum
static float values[nvalues];
sum += value;
// If the window is full, adjust the sum by deleting the oldest value
if (cvalues == nvalues)
sum -= values[current];
values[current] = value; // Replace the oldest with the latest
if (++current >= nvalues)
current = 0;
if (cvalues < nvalues)
cvalues += 1;
return sum/cvalues;
}
The way you use it is fairly simple. Instead of calling, for example:
x = analogRead(DATA_PIN);
You would call:
x = movingAverage(analogRead(DATA_PIN));
And the movingAverage function does the rest for you. Inside the movingAverage function, you'll see a const value that defines the number of values used in the average. In the above case, it's 8.
You can use movingAverage on any sequence of values, so it doesn't have specific code inside it for reading pins. The way the movingAverage function works is that it keeps track of the last nvalues count of values you call it with and always returns the rolling average of those. It also avoids summing all the values in the window on each call by using a "delta" technique for the sum.

Arduino - sending large amount of data over Serial

I am trying to build a simple FLASH memory programmer (for 39SF020A) using my arduino mega. I wrote the C code and Python script to send the data over (And it all works as expected).
I need to transfer about 32k of hexadecimal data, but with my settings only 10k of data took about 4 minutes (115200 BAUD), which i found unnecessary long. Currently, i am sending over serial (from Python) my value with a terminator (i chose '$'), so for exmple '3F$'. adresses are calulated on the arduino, so no need to send them.
In my arduino code, i have
String received_string = Serial.readStringUntil('$');
and after programming every byte to teh FLASH using arduino, it sends back a '\n' to let the Python know, that it is ready to receive next byte (the python is waiting for receiving a 'line' and then continues). I am not really sure if this is a way to do it, if sending only one byte at the time is good idea and if not, how many and how do i parse them on the arduino? Is the feedback loop useful?
Thanks.
Python Code:
('file' contains all data)
for item in file[1:]:
ser.write((item + "$").encode("ascii"))
line = ser.readline()
i += 1
if i >= top:
break
elif (i % 100) == 0:
print(i)
Arduino code (just part of it)
if (Serial.available() > 0){
String received_string = Serial.readStringUntil('$');
programData(received_string.toInt(),program_adress);
program_adress++;
}
void programData(char data_in, unsigned long adress)
{
digitalWrite(OE,HIGH);
digitalWrite(CE,LOW);
writeByte(0xAA, 0x5555);
writeByte(0x55, 0x2AAA);
writeByte(0xA0, 0x5555);
writeByte(data_in, adress);
Serial.print("\n"); // Feedback for Python
delayMicroseconds(30); // Just to be on the safe side
}
void writeByte(char data_in, unsigned long adress)
{
setDataAs(OUTPUT);
digitalWrite(OE,HIGH);
digitalWrite(WE,HIGH);
setAdress(adress);
setData(data_in);
digitalWrite(WE,LOW);
delayMicroseconds(1);
digitalWrite(WE,HIGH);
}
// Sets data BUS to input or output
void setDataAs(char dir){
for (unsigned int i = 0; i < data_size ;i++) pinMode(data[i],dir);
}
// Sets data to specific values
void setData(char data_i){
setDataAs(OUTPUT);
for (int i = 0; i < data_size;i++) { digitalWrite(data[i],bitRead(data_i,i)); }
}
void setAdress(long adr){
// Set all adresses
for (int i = 0; i < adresses_size;i++)
digitalWrite(adresses[i],bitRead(adr,i));
}

Data sent through serial on arduino gets byte-shifted sometimes

I'm sending data through USART on an Arduino Due. I'm currently filling a buffer so the data gets sent just when a buffer is full.
The data I'm putting into the buffer is a lookup table of different wave shapes with 12 bits of depth (values from 0 to 4095). So I'm putting into the buffer values that are 2 bytes of depth, and the most significant byte is always 0.
My problem is that everyonce in a while a whole wave period gets shifted a byte (every value gets multiplicated by 256). The error is unpredictable: it might happen on the 2nd or 3rd period to be sent, but it happens soon. I tried slower baudrates, or adding two stopbits, but nothing fixes it. The relevant chunk of the code:
const int buflen = 2048;
int i = 0;
int j = 0;
int k = 1;
int wave = 0;
short buff[buflen];
volatile PROGMEM short sintab[3][512] = ...//there's no need to paste here the lookup tables
void setup(void){
Serial3.begin(115200, SERIAL_8N2);
}
void loop(void) {
buff[j]= sintab[wave][i];
i+= k;
j++;
if (i>511){
i-=512;
}
if (j>=buflen){
byte* bytePointer =(byte*)buff;
for (int l=0; l<=buflen; l++){
Serial3.write(bytePointer[l]);
Serial3.flush();
}
int j = =0;
}
I'm checking the received data on both a serial monitor and a python program that stores the received values and print them. I think its weird that the error never happens in the middle of a wave: a one or two waves are copied good on the buffer and then a whole value gets shifted. How could I fix this?
It looks like the issue is not in this block of code where you're writing the data out to your USART port, rather in storing the data to that array. When you have this byte offset occur, can you validate that the data in your array is as you expect it to be?
Edit:
Change
for (int l=0; l<=buflen; l++)
to
for (int l=0; l< buflen; l++)
so you enumerate over the set 0 to 511, which is 512 elements. Now you are enumerating an additional element, which is reading data from an unexpected memory location and returning whatever is there (likely the next byte of your static structure).

send a list of data from python to arduino using pyserial

I want to turn ON and OFF, three LEDS connected to arduino, using a python GUI, thus I use pyserial. The state of the LEDs is described by a tuple
RGB = (Red On/Off, Green On/Off, Blue On/Off), e.g. (1,0,1)
Since pyserial.write() works only with strings, let's say that RGB = "101"
I want to sent to arduino the RGB string, split it to three values 1, 0 and 1, and set LOW or HIGH three output pins, depending on the incoming values.
The python code works fine:
import serial
ser = serial.Serial('/dev/ttyACM4', 9600)
ser.write('101')
This is the arduino code:
void setup() {
Serial.begin(9600);
Serial.println("Ready");
}
void loop() {
char input_data = ' ';
if(Serial.available()){
char input_data = {Serial.read()};
Serial.println(input_data);
}
delay(100);
}
The print line is only for inspection purpose.
Can I somehow split the input_data string, and retrieve its values, like:
int R = input_data[0];
int G = input_data[1];
int B = input_data[2];
Any suggestion would be appreciated.
OK, so one quick clarification here (as verified by your comment): input_data is not a string, it is a single char (one byte). Also, serial.read() returns a single byte (the next in the serial stream) and does so as an int, so you're implicitly casting int to char in your code. This is fine, just wanted to make that clear.
What you can do is make input_data an array of chars, and store each new byte in a new location in the array. Then you'll have all three numbers you're looking for. Then, all that's left is to turn input_data[i] into a LOW or HIGH value to be passed to each of your LED pins. What I would do is within your for loop, test each value read from the serial.read() function to see if it's value is '0' or '1' and then storing true or false in another array of bools. Finally, you can test that array and set the corresponding pin 'HIGH' or 'LOW' as necessary. Please keep in mind what I mentioned earlier in the comments, that you're going to want to test the received data as the characters 1 and 0 and not the numbers 1 and 0.
Here's a quick snippet as an example:
int[3] pins; //Initialize this to contain the numbers of the R, G, and B pins.
void setup() {
Serial.begin(9600);
Serial.println("Ready");
}
void loop() {
char[3] input_data;
bool[3] low_high;
if(Serial.available() >= 3){
for (int i=0; i<3; i++) {
input_data[i] = Serial.read();
if(input_data[i] == 48) //ASCII for 0
low_high[i] = false;
if(input_data[i] == 49) //ASCII for 1
low_high[i] = true;
//Serial.println(input_data);
}
}
for (int j=0; j<3; j++) {
if(low_high[j]) {
digital_write(pins[j],'HIGH');
} else {
digital_write(pins[j], 'LOW');
}
}
delay(100);
}
That should get you up and running. Please keep in mind that this example has very limited input checking, so you'll need to beef it up a bit (i.e. checking for more than 3 bytes ready, making sure you're getting char's and not gibberish, etc.).

Resources