What about the questions in post #13?
Edit: Also you still have not posted the Arduino code.
What about the questions in post #13?
Edit: Also you still have not posted the Arduino code.
Meenakshichowdhary:
@TolpuddleSartreI have attached the output that I got now just with a different value but gives the same error.If i am not wrong, I think its reading from accelerometer
Your project may have multiple issues, but I can assure you the Python matplotlib stuff will not work if you call the graph update on every sample (at about 1000 updates/second) and will fail with exactly the symptoms you describe.
@bms001
I have posted the complete code in post#16
@MrMark
My project includes continuous monitoring and hence i need to plot it everytime. Any alternate that I could get to?
bms001:
What about the questions in post #13?
Edit: Also you still have not posted the Arduino code.
Meenakshichowdhary:
@bms001
I have posted the complete code in post#16
You posted the Python code. You have still never posted the Arduino code. The main reason I am asking is that I want to know how frequently information is being sent.
bms001:
How frequently are you outputting data from the Arduino?
If you slow it down, does that make a difference?
If you slow down the plotting rate (as suggested by @MrMark), does that make a difference?
Can you try reading the input lines (without processing them) as you've done for readline.png but include the plotting code (and maybe some dummy data to plot) so that you can see the effect of the delay from plotting on the received data?
Have you tried any of this?
Meenakshichowdhary:
My project includes continuous monitoring and hence i need to plot it everytime.
What is your requirement in Hz? How many data points do you need from the sensor per second? How often do you need to refresh the chart per second (at minimum)? The answer to these questions should be numbers.
Meenakshichowdhary:
Any alternate that I could get to?
I'm guessing here but perhaps Simulink (+Matlab) would be more suited to real-time plotting.
I am so sorry... This is the code below....
I have set the freq to 1khz with the register 0x24.
#include <Wire.h>
#include <MPU6050.h>
const int MPU_address=0x68;
int ACCX,ACCY,ACCZ
MPU6050 MPU;
void setup(){
Wire.begin();
MPU.initialize();
Serial.begin(9600);
Wire.beginTransmission(MPU_address);
Wire.write(0x1A);
Wire.write(00000000);
Wire.endTransmission(true);
Wire.beginTransmission(MPU_address);
Wire.write(0x24);
Wire.write(00001100);
Wire.endTransmission(true);
}
void loop(){
Wire.beginTransmission(MPU_address);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU_address,6,true);
ACCX=Wire.read()<<8|Wire.read();
ACCY=Wire.read()<<8|Wire.read();
ACCZ=Wire.read()<<8|Wire.read();
Wire.endTransmission(false);}
I will have to use Python itself for the later use.
I am not sure how to measure this freq. of the data that I am getting now. Hence,I have manually set the 0x24 register to 1Khz. I might be wrong in this case.
How frequently are you outputting data from the Arduino?
If you slow it down, does that make a difference?
I am not sure how to answer when u ask how frequently i take the output.
If you slow down the plotting rate (as suggested by @MrMark), does that make a difference?
Not making difference
Can you try reading the input lines (without processing them) as you've done for readline.png but include
the plotting code (and maybe some dummy data to plot) so that you can see the effect of the delay from plotting on the received data?
I was able to print the raw data from the python and it works fine, but i wont be able to plot them as they are not in float format and are in string and hence I have to process them before i plot.
Meenakshichowdhary:
@MrMark
My project includes continuous monitoring and hence i need to plot it everytime. Any alternate that I could get to?
The plotting only needs to appear to be continuous to a human observer. Updating a few times per second is a sufficient requirement.
My suggestion would be to get each of the software components working at some reduced speed and then refine the bits that are too slow. To focus on the Python side, perhaps write a simple Arduino sketch to output a known sequence of numbers over serial at a low rate as so:
void setup() {
Serial.begin(115200);
}
void loop() {
for (int i = 0; i < 1024; i++) {
Serial.println(i) ;
delay(500) ;
}
}
You're going to find that 9600 baud is not sufficiently fast to output 3 ASCII numbers at a 1 kHz update rate and that matplotlib will be able to update a "live" display a few tens of times per second with some care. I would use Python threading to receive the serial data, but that may not be necessary if the PC operating system has a sufficiently large buffer for the serial port.
For what it's worth, the Arduino code in your post #25 is incomplete because it doesn't write anything to the serial port and your Python code in post #16 never calls the "makeplotting" function which would fail to show the plot even if it were called.
Meenakshichowdhary:
This is the code below....
Are you sure? Nothing in that code appears to send data from the Arduino to your PC. Please make sure you post the complete code.
Wire.beginTransmission(MPU_address);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU_address,6,true);
ACCX=Wire.read()<<8|Wire.read();
ACCY=Wire.read()<<8|Wire.read();
ACCZ=Wire.read()<<8|Wire.read();
Wire.endTransmission(false);
You don't need the last Wire.endTransmission(false). Wire.endTransmission() is the last step in sending data (as you have done in the first 3 lines above). Wire.requestFrom() does not need it. I suggest that you read the documentation and check that you understand the difference between Wire.endTransmission() and Wire.endTransmission(false).
Meenakshichowdhary:
I am not sure how to measure this freq. of the data that I am getting now. Hence,I have manually set the 0x24 register to 1Khz. I might be wrong in this case.
Currently you are reading the sensor as fast as you can. At a very rough guess, your code in loop will take about 300us, so you're reading the sensor at about 3000Hz, which is more often that the sensor can take new readings.
The 0x24 register of the MPU controls the clock frequency of the auxiliary I2C bus. This is used when another sensor is connected to the MPU which you are not doing so you don't need to use this register at all.
What register were you trying to set?
I would suggest adding some control in your program like this (I have not tested the code but I hope this gives you the right idea) ...
unsigned long lastSensorRead = 0;
unsigned long sensorReadInterval = 1000; // for a read frequency of 1Hz (once per second)
void loop(){
if(millis() - lastSensorRead > sensorReadInterval){
Wire.beginTransmission(MPU_address);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU_address,6,true);
ACCX=Wire.read()<<8|Wire.read();
ACCY=Wire.read()<<8|Wire.read();
ACCZ=Wire.read()<<8|Wire.read();
lastSensorRead += sensorReadInterval;
}
}
It looks like you are trying to represent a binary number here:
Wire.write(00001100);
If that is what you are trying to do then you need to write this as
0b00001100
Otherwise it will be interpreted as the number 1100 (I expect).
Meenakshichowdhary:
If you slow down the plotting rate (as suggested by @MrMark), does that make a difference?
Not making difference
Please confirm what different plotting rates you have used.
Meenakshichowdhary:
Can you try reading the input lines (without processing them) as you've done for readline.png but include
the plotting code (and maybe some dummy data to plot) so that you can see the effect of the delay from plotting on the received data?
I was able to print the raw data from the python and it works fine, but i wont be able to plot them as they are not in float format and are in string and hence I have to process them before i plot.
That is not what I was asking. It has been suggested that your issue is not with the input from the Arduino, but due to the constant replotting. Therefore I suggested to plot some dummy data (so you know there's no problem with it), and at the same time observe the incoming data from the ARduino to see if the act of trying to plot anything so frequently is causing your issue.
MrMark:
... your Python code in post #16 never calls the "makeplotting" function which would fail to show the plot even if it were called.
I have not tried to run the Python code but interactive plotting has been enabled
ply.ion()
So I think that calling
ply.plot(ACCX)
Should trigger showing the updated chart (EDIT: if the makeplotting function were called). But this is not something I'm that familiar with, have just used once a little while ago (though I found that it was necessary to add a ply.pause(0.001) after each ply.plot for it to actually work).
By the way, did you mean to include a delay in your example Arduino code?
I have read this in some forum,hence kept it as false:
Wire.endTransmission(false); //true will send a stop message, releasing the bus after transmission. false will send a restart, keeping the connection active.
Its the complete arduino code that I use is what I have posted in #25
I will remove the register 0x24 as u mentioned that I would need it only when I use 1more sensor.
I am still not sure how to calculate the frequency at which this sensor is working...(sorry to sound dumb). Thats why,I have updated the register to 1Khz. I dont get it how did you know that its working 300us and I have not added any delay.
I am now able to get the data to Python after some changes in the logic. But the problem still persists like it reads values like 0.0.7\n, I have also tried to change the baud rates to check if it is making any difference but it does not.
I have also stopped plotting for each and every value, I am iterating from 0 to 99 and reading value once.
The connection to Python is using this line:
arduinodata=serial.Serial('COM3',9600) #port name and baud rate
Meenakshichowdhary:
Its the complete arduino code that I use is what I have posted in #25
No it's not. To confirm this, upload that code (the exact code that you posted) to your Arduino, confirm that it did so successfully, and then see if you get any output from the serial monitor.
Meenakshichowdhary:
I dont get it how did you know that its working 300us
It is an estimate based on some measurements I have done in the past (actually it is not that accurate but I don't think the details why are important right now).
Note that the frequency that the sensor has a new reading is based on the settings of the MPU, but the frequency that the sensor is read is controlled by the Arduino. These are two different things.
Meenakshichowdhary:
I am now able to get the data to Python after some changes in the logic.
What changes? You have not posted your updated code.
Check this image below with the output from serial monitor.
Which freq. do we consider for calculations then?
I have a doubt.. that when we take plot this data, y axis is always the values that we get from Arduino(Ax,Ay,Az) , can you tell me whats the units of time that we get on x axis? (Because, when I have considered it to be Time in seconds, i tried to monitor it with a real time clock but they dont match..the readings are less than a second). Hence, I am unable to calculate the frequency as well...
Note that I was able to read the data from the start but the problem was with the values that are being read from Arduino to Python. I have just tried to round the value to 0.0 but thats not what I want to do.. This is just a runaround for me to understand how to get the data atlest so that I can understand it
import serial
import matplotlib.pyplot as ply
import numpy #used for mathematical operations
import pylab as py
ACCX=[]
arduinodata=serial.Serial('COM3',9600) #port name and baud rate
fig = ply.figure()
ax = Axes3D(fig)
ply.ion()
def makeplotting():
ply.ylabel('ACCX (°/sec)')
ply.xlabel('Time')
ply.plot(ACCX)
def convert_float(value):
try:
return float(value)
except ValueError:
print ('Data {} is not in float and hence marked to zero'.format(value))
return 0.0
while True:
arduinostring=arduinodata.readline()
arduinostring=str(arduinostring,encoding="utf-8")
dataArray=arduinostring.split(',')
print (dataArray)
dataArray = map(convert_float, dataArray)
x, y, z = dataArray
ACCX.append(x)
drawnow(makeplotting)
Meenakshichowdhary:
I am still not sure how to calculate the frequency at which this sensor is working...(sorry to sound dumb). Thats why,I have updated the register to 1Khz. I dont get it how did you know that its working 300us and I have not added any delay.
In python you can measure elapsed time with this sort of construct:
import time
. . .
start_time = time.time()
##### your code to be measured ####
elapsed_time = time.time() - start_time
If you wrap this around reading some number of samples received via the serial port, and divide by the number of samples, it will give you a useful approximation of the Arduino sample rate.
. . . the problem still persists like it reads values like 0.0.7\n, . . .
I believe the mechanism is something like this:
The serial buffer is finite length, I believe 4k bytes in Linux by default and probably similar in other systems. If data is coming into this buffer faster than it is being read out, it will eventually fill and old data that has been received from the Arduino, but not yet by the Python will be overwritten. When the Python reads such data, it will see strings which may contain overlapping old and new data before encountering the newline character. Thus you can get a a character string with two decimal points and Python fails trying to convert that string to a float as you are seeing.
I have also tried to change the baud rates to check if it is making any difference but it does not.
By default Arduino sends serial data encoded as one start bit, 8 bits data, and one stop bit, thus 10 bits per byte at the specified baud rate. Thus at 9600 baud it can send at most 9600/10 = 960 bytes per second. In the Arduino "loop" code, this will ultimately block. Specifying a higher baud rate proportionally increases the output rate, which you will have to do to get to your desired sample rate, but first you need to fix the PC side of things so it can consume data produced at that rate.
I have also stopped plotting for each and every value, I am iterating from 0 to 99 and reading value once.
Slow it down more until it puts up a updating plot. Once you have a framework that puts data from the Arduino on the screen then refine the parameters.
Edit to add: You might need "ply.show()" and "ply.pause(0.001)" at the end of "makeplotting()" to get the plot to display.
Also, as written "makeplotting" re-computes and draws the entire figure on each call which is going to be particularly slow. A search on something like "python 3 fast live plotting" should get to examples of techniques to update plots much faster.
Meenakshichowdhary:
Check this image below with the output from serial monitor.
Thank you, this is clear. However I would note that the Serial.print lines were not present the last time you posted the code. It is really really important to post the exact code you are using.
In case it is not obvious to you, your Arduino program will read the sensor as fast as it possibly can. As soon as it has read the sensor (and then printed the results), it will immediately go back to the top of loop() and start reading the sensor again. Is this really what you want?
(actually because of the low baud rate used, the Serial buffer will get full and loop() execution will be delayed, but you should understand in general why the program is not pausing between sensor reads)
I suggested an alternative approach in #27 where you actively control the rate at which you read the sensor using millis(). I strongly suggest you do this in addition to any changes you make on the Python side.
EDIT: or you can use this approach to control how frequently you output the data, or you can control both (either together which is the simplest option, or separately).
Have you been through some of the basic Arduino tutorials like BlinkWithoutDelay? I think if you spend some time working through lots of the examples that come with the Arduino IDE (where you write the code) it will really help you to understand what you are doing and how the Arduino runs.
@bms001
I have tried now the logic from post#27 about adding millis() but i added it with 500 so that I could get the data little faster
I will also go through that link that you have given me about delay()
@MrMark
Thanks for the explanation Mark.
The serial buffer is finite length, I believe 4k bytes in Linux by default and probably similar in other systems. If data is coming into this buffer faster than it is being read out, it will eventually fill and old data that has been received from the Arduino, but not yet by the Python will be overwritten. When the Python reads such data, it will see strings which may contain overlapping old and new data before encountering the newline character. Thus you can get a a character string with two decimal points and Python fails trying to convert that string to a float as you are seeing.
I think you are right. I have added a delay as advised by you and bms001. For now, I dont get see the problem persisting.
The serial buffer is finite length, I believe 4k bytes in Linux by default and probably similar in other systems. If data is coming into this buffer faster than it is being read out, it will eventually fill and old data that has been received from the Arduino, but not yet by the Python will be overwritten. When the Python reads such data, it will see strings which may contain overlapping old and new data before encountering the newline character. Thus you can get a a character string with two decimal points and Python fails trying to convert that string to a float as you are seeing.
I have now added that delay, and I still use 9600 Baud rate.. I did get some clue how to calculate the bit rate but as I have now added this, the bit rate would also differ right?
Slow it down more until it puts up a updating plot. Once you have a framework that puts data from the Arduino on the screen then refine the parameters.
I am not showing the data continuously now... and only picking up data by once in 100counts after the delay (used a for loop and data captured when i=99)