I am newbie in Arduino community. I am using a Mitotoyo Digimatic Indicator (Mitutoyo) to record the real-time inline diameter of filament running through a machine. I am having following issues-
Initially I was getting 11 reads per second. But I want to read filament diameter at 30-32 Hz. I changed the time.sleep amount as in the following python script to get data 30Hz. Now, I am getting 30-32 Hz only for the 1st second. For the remaining of the seconds I am getting 9-12 Hz. I am not understanding how can I get data at 30-32 Hz for each second of readings. I used following Arduino script (from - "https://www.instructables.com/Interfacing-a-Digital-Micrometer-to-a-Microcontrol/") and python code-
Arduino Script:
int req = 5; //mic REQ line goes to pin 5 through q1 (arduino high pulls request line low)
int dat = 2; //mic Data line goes to pin 2
int clk = 3; //mic Clock line goes to pin 3
int i = 0;
int j = 0;
int k = 0;
int signCh = 8;
int sign = 0;
int decimal;
float dpp;
int units;
byte mydata[14];
String value_str;
long value_int; //was an int, could not measure over 32mm
float value;
void setup()
{
Serial.begin(9600);
pinMode(req, OUTPUT);
pinMode(clk, INPUT_PULLUP);
pinMode(dat, INPUT_PULLUP);
digitalWrite(req, LOW); // set request at high
}
void loop()
{
digitalWrite(req, HIGH); // generate set request
for ( i = 0; i < 13; i++ )
{
k = 0;
for (j = 0; j < 4; j++)
{
while ( digitalRead(clk) == LOW)
{
} // hold until clock is high
while ( digitalRead(clk) == HIGH)
{
} // hold until clock is low
bitWrite(k, j, (digitalRead(dat) & 0x1));
}
mydata[i] = k;
}
sign = mydata[4];
value_str = String(mydata[5]) + String(mydata[6]) + String(mydata[7]) + String(mydata[8] + String(mydata[9] + String(mydata[10]))) ;
decimal = mydata[11];
units = mydata[12];
value_int = value_str.toInt();
if (decimal == 0) dpp = 1.0;
if (decimal == 1) dpp = 10.0;
if (decimal == 2) dpp = 100.0;
if (decimal == 3) dpp = 1000.0;
if (decimal == 4) dpp = 10000.0;
if (decimal == 5) dpp = 100000.0;
value = value_int / dpp;
if (sign == 0)
{
Serial.println(value, decimal);
}
if (sign == 8)
{
Serial.print("-"); Serial.println(value, decimal);
}
digitalWrite(req, LOW);
delay(10);
}
Python Script:
import serial
import time
import datetime
# make sure the 'COM#' is set according the Windows Device Manager
ser = serial.Serial('COM5', 9600, bytesize=8,stopbits=1, timeout=0.1)
print("Connected to: " + ser.port)
ser.isOpen()
alldata = []
print("Instrument Type: Sanap Gauge")
run_time = float(input('\nInsert Runtime: '))
file_name = str(input('\nInsert Filename: '))
file_name = file_name + '_' + datetime.datetime.now().strftime("%m%d%Y_%H%M%S")
with open('data/' + file_name + '.csv', 'w+') as output_file:
start = time.time()
output_file.write('Timestamp,Diameter\r')
while time.time()-start < run_time:
timestamp = str.format('{0:.3f}', (time.time()-start))
data = ser.readline().decode().rstrip()
output_file.write(timestamp + ',' + data + '\r')
time.sleep(0.001-(time.time()-start)%0.001)
print(timestamp, data)
alldata.append(data)
Moreover, I am getting data with 2 decimal points such as 0.12mm. But, I want to get with 3-4 decimal points.
I am sure I doing a simple mistake, but I am not sure what is that. Any help regarding this would be highly appreciated.
Thank you fr the code tags. It does help, but the lack of formatting and the excess white space make reading and following the code somewhat more difficult. I took the liberty of autoformatting your code and removing some extra blank lines. Does this look easier to follow now?
int req = 5; //mic REQ line goes to pin 5 through q1 (arduino high pulls request line low)
int dat = 2; //mic Data line goes to pin 2
int clk = 3; //mic Clock line goes to pin 3
int i = 0;
int j = 0;
int k = 0;
int signCh = 8;
int sign = 0;
int decimal;
float dpp;
int units;
byte mydata[14];
String value_str;
long value_int; //was an int, could not measure over 32mm
float value;
void setup()
{
Serial.begin(9600);
pinMode(req, OUTPUT);
pinMode(clk, INPUT_PULLUP);
pinMode(dat, INPUT_PULLUP);
digitalWrite(req, LOW); // set request at high
}
void loop()
{
digitalWrite(req, HIGH); // generate set request
for ( i = 0; i < 13; i++ )
{
k = 0;
for (j = 0; j < 4; j++)
{
while ( digitalRead(clk) == LOW)
{
} // hold until clock is high
while ( digitalRead(clk) == HIGH)
{
} // hold until clock is low
bitWrite(k, j, (digitalRead(dat) & 0x1));
}
mydata[i] = k;
}
sign = mydata[4];
value_str = String(mydata[5]) + String(mydata[6]) + String(mydata[7]) + String(mydata[8] + String(mydata[9] + String(mydata[10]))) ;
decimal = mydata[11];
units = mydata[12];
value_int = value_str.toInt();
if (decimal == 0) dpp = 1.0;
if (decimal == 1) dpp = 10.0;
if (decimal == 2) dpp = 100.0;
if (decimal == 3) dpp = 1000.0;
if (decimal == 4) dpp = 10000.0;
if (decimal == 5) dpp = 100000.0;
value = value_int / dpp;
if (sign == 0)
{
Serial.println(value, decimal);
}
if (sign == 8)
{
Serial.print("-"); Serial.println(value, decimal);
}
digitalWrite(req, LOW);
delay(10);
}
I don't see where you specify the Arduino board that you are using. If you are using an 8 bit board with limited memory, the use of the String class can cause hard to debug memory problems unless you know what you are doing. Read the Evils of Strings to see why and some ways to use c_strings (null terminated character arrays) to replace the String class.
Increasing the baud rate may help with throughput.
I know nothing of Python so can't be of help with that part.
Formatting will make the Arduino code more readable, but is absolutely essential for the Python code since preserving indentation is part of the syntax and it doesn't look like you've got that bit correct.
Edit to add: Also, the Python code looks to be incomplete as some of the variables aren't defined.
2nd Edit to add: ser.readline() as you've called it is blocking until it gets a carriage return character, so you shouldn't need the time.sleep() call that follows.
I am getting 30-32 Hz only for the 1st second. For the remaining of the seconds I am getting 9-12 Hz. I am not understanding how can I get data at 30-32 Hz for each second of readings.
This behavior suggests that a (serial?) buffer is getting backed up as if data is not being output as quickly as you are attempting to produce it. The time.sleep() call might do this, but you could try getting rid of the print and/or the list append on the Python end to see if that changes the behavior.
It may help to move the digitalWrite(req, LOW); that ends the request to right after you finish reading and do the calculations outside of the reading section.
Increase the baud rate to 115200 or higher to lessen the sending time.
Use c_strings. Using the String class is slower as well as potentially dangerous.
Don't use the delay(). If you send the end request right after you finish reading, doing the calculations and sending will put some time between requests.
Do you know how long that it takes for the caliper to send a compete data packet? Is your desired sample rate achievable?
Thanks for the suggestions. I have updated the python code. I just want to confirm-
R u suggesting yo move digitalWrite(req, LOW); out of the loop? Like this-
if (sign == 0)
{
Serial.println(value, decimal);
}
if (sign == 8)
{
Serial.print("-"); Serial.println(value, decimal);
}
}
digitalWrite(req, LOW);
I have tried once, it seemed it did not work. But I will try again
Where to use c_strings instaed of string? Sorry for the silly question.
I will delete delay.
I am not sure about that. We are using filelogger software and it is outputting data at 11hz, which I can see from Serial Monitor as well. That's why I am using separate python script.
I am not an expert on reading the caliper so there may be some reason that the req line is held high longer. I thought it worth a try to get more throughput.
Just to add that I am using Arduino Lenoardo. I am not sure if it has something to do.
getting 4 decimals but with zeros at the end, like 0.1100. This might be because of the gauge, as it is also showing 2 decimals on the display. I believe if I calibrate it on the display, it might change.
Increased baud rate did not work. still 11 Hz
deleted delay(). still 11 Hz
Sorry for the silly questions. Did you suggest to move digitalWrite(req, LOW); move out of the loop like this?
if (sign == 0)
{
Serial.println(value, decimal);
}
if (sign == 8)
{
Serial.print("-"); Serial.println(value, decimal);
}
}
digitalWrite(req, LOW);
How many characters are in each line of your serial output?
Maybe it would help if you could post a sample of the output around the point where it slows down.
Your serial link only runs at 9600 baud just for starts. If that's the USB cable then it should be 115200 or faster.
Baud is bits transmitted per second. Serial we use is 1 start bit, 8 data bits. 1 stop bit.
9600 baud is only 960 chars per second, 115200 baud is 12x as fast.
Using non-blocking code cooperative multitasking, you should be able to speed that code up incredibly.. but it's a different approach with a learning curve. OTOH it allows running many tasks on a single thread without using interrupts (with 85 cycle overhead plus IRQ code) or time-slicing.
Does the micrometer have an SPI interface? It looks like you use I2C which is slower.
I'd presumed that the issue was on the transfer between Arduino and the PC, but I'm leaning towards a problem on the sensor/Arduino interface at this point. If you have access to an oscilloscope or logic analyzer it would be really helpful to see what the signals are doing there. Specifically the interval between "req" signals and the "clk" behavior following a "req".
Barring that, a test build of the Arduino side that sends the "millis()" value at the time of collect instead of the instrument reading would show the rate at which data is being read from the instrument.
The technical manual for the specific model micrometer you're using might give a clue as to its data rate limitations.
As for the baud rate, the character rate even at 9600 baud should be more than sufficient to output 32 samples/second at less than 10 characters per sample.
I try as follows for SPI interfacing. It didn't give any output.
int req = 13; //"White" mic REQ line goes to pin 5 through q1 (arduino high pulls request line low)
int dat = 12; //"Black" mic Data line goes to pin 2
int clk = 11; //"Red" mic Clock line goes to pin 3
int btn = 10; //"Green"get button from measure