I am relatively new with Arduino and I want to:
Set the frequency of the IMU to 100 Hz.
Synchronise GPS and MPU6050 in order to get data at the same time:
1 set of IMU data and 1 set of GPS data ->
99 sets of IMU data. (//1 second) ->
1 set of IMU data and 1 set of GPS data->
99 sets of IMU data (// 2 seconds)
I can't find anything that I can use/understand.
There are several lengthy threads in the Arduino forums for the same kind of project. Here's a good starting point. Then check out powergravity's other threads here, here, here and here. The last version of his program is here. You've got a lot of reading to do. :)
It's difficult to summarize this information into something a "new Arduino" user can "use/understand", but I'll try:
The IMU and the GPS run off their own clocks; you can set the frequency, but you can't set when they happen. Their phases or time offsets could be different. The IMU could run slightly faster or slower than 100Hz, because it is based on its own oscillator, not the GPS atomic clock (in orbit).
There will be an average of 100 IMU samples per GPS data point (an exact 1000ms). But because the IMU and GPS are not synchronized, you may get 99 or 101 IMU readings for each GPS data point.
You don't explicitly state what you are doing with the data. Whatever that is, it must accommodate the different numbers of samples per GPS period. I recommend that your loop structure is based off of the GPS time. You can even use it to measure the true frequency of the Arduino crystal (and thus the micros() clock).
At these rates, you will need to choose your GPS serial port wisely. Here are some tips.
You will also need an efficient GPS parser. My NeoGPS library is smaller, faster, more reliable and more accurate than all other libraries.
Related
This is an extremely niche problem, so I'll do my best to explain it in words:
Say you have an operation that requires negligible time (in my case, stepping a stepper motor once by pulsing the pins). I want to coordinate the movement of 6 individual motors with their own acceleration curve, but actuate them with the same micro controller. I also want the individual acceleration curves of the motors to be modifiable.
I'm using a Teensy 4.1, so this program will be written in Arduino language (near identical to C++).
My current approach to this problem is to generate six individual "delay" arrays for each motor. Essentially, their speed is controlled by the delay in between each pulse, and the angular distance traveled by the # of steps, or elements of each delay array. Something like this:
1 (P20) 1 (P20) 1 (P20) 1
2 (P30) 2 (P30) 2 (P30) 2
Where a 1 or 2 is the respective motor's step and a (PX) is a delay for X seconds.
I would like to write some master transposition function that turns the above into this:
1,2 (P20) 1 (P10) 2 (P10) 1,2 (P20) 1 (P10) 2
This array, when read by my actuation code would step motors 1 and 2 at the same time, wait 20 microseconds, step motor 1, 10 microseconds, step motor 2... etc.
It seems pretty simple when you do it for two motors, but for some reason I just can't wrap my head around making a completely modular version of this. In my case, it would need to merge 6 arrays into one.
I am also just wondering if anyone could think of a more elegant solution to this problem, as I am pretty new to programming and don't know all the features / capabilities of C++.
I have tried applying an iterative method, where you keep track of the current total delay elapsed and subtract it from the lowest next total delay of the different stepper arrays, then append the master array with that difference and update all the totals accordingly, but this approach always ends up too convoluted for me to follow.
Might I offer a different solution:
Use something like freeRTOS to and make individual threads to control each motor. That way you can define delays for each motor individually without having the extra complication of making a timing array.
The ESP32 has freeRTOS available in the Arduino definitions and is pretty easy to use. You could find a port for the Teensy 4.1
Here is a really nice tutorial for blinking LEDs at different rates. Your code should have a similar approach.
freeRTOS ESP32 tutorial
This might sound like a very silly question, so I apologize if this is something very simple but I just cannot get my head around it. I am trying to understand what the data provides in terms of real time information, for example, the MPU-6050:
Gyroscope - is a 16 bit data register with a range from (0 <-> 65535)
There is a selection of ranges (±250, ±500, ±1000, and ±2000°/sec)
If the range is set to ±250°/sec, is the reading 360/65535 = 0.0054 resolution?
What does °/sec mean, if the sensor does not move and reads zero and then turned quickly does it mean it will be reading the angle at the set range? For example, if the range was set to ±2000°/sec and it was moved 200° would the read move from 0 to (2/65535 *200) and keep sending this value once the sensor stopped moving?
Accelerometer - is a 16 bit data register with a range from (0 <-> 65535)
There is a selection of ranges (±2g, ±4g, ±8g and ±16g)
If the sensor is not moving, completely flat the reading will be 0?
If the sensor is shocked at 2g will the max reading be 65535 (if set of 2g, with a resolution of 2/65535)
If the sensor is shocked at 16g will the max reading be 65535 (if set of 16g, with a resolution of 16/65535))
There are two main documents regarding the MPU6050, and those are the datasheet and the register map.
The gyro measurements are stored in the GYRO_XOUT, GYRO_YOUT, GYRO_ZOUT parameters, as you can see in the register map document, page 31. Each parameter is stored as a 2-complement signed 16 bit value split into two 8-bit registers: the GYRO_xOUT_L and _H.
In the same page, you can see the sensitivity for each full-scale range. For example, if your FSR is +/- 250º/sec, and you want to measure 1º/sec, the GYRO_xOUT parameter should read 131 counts.
The accelerometer-related registers can be seen in the same document, page 29. The idea is the same, two 8-bit registers to form a 2-complement signed 16-bit value, and the sensitivity values for each FSR.
Regarding your question in comments, if you rotate the device 125º in a second, at constant rotation speed, you should read 16375 in the rotation registers during the movement. This value comes from 131 counts/(º/sec) * 125º/sec = 16375 counts.
I would like to generate a frequency with the resolution of 0.1Hz from the range of 0.0 up til 1000.0 Hz ( Example such as 23.1 Hz, 100.5 Hz and 999.7 Hz) I have found that using AD9833 we can generate the signal as what I was required, but the notes are a bit confusing to me.
The specification can be obtained HERE .
Need your kind assist to if we can make the Arduino code.. lets say, to generate a signal of 123.4 Hz via Serial monitor from Arduino and it displayed as it is in the oscilloscope?
Thank you.
Looking at the notes, it appears that programming this chip will be non-trivial. If you don't require frequencies all the way down to 0 Hz, this job can be done much more easily with a standard Windows sound card. (Sound cards are AC-coupled, so won't go below a few Hz.) For one example, my Daqarta software can generate frequencies (with any waveform you want) at a resolution better than 0.001 Hz. The maximum frequency will be a bit less than half the sound card's sample rate... typically 20 kHz at the default 48000 Hz sample rate.
You don't have to buy Daqarta to get this capability; the Generator function will continue to work after the trial period... free, forever.
UPDATE: You don't mention what sort of waveforms you need, but note that if you can use square waves you may be able to do the whole job with the Arduino alone. The idea is to set up a timer to produce interrupts at some desired sample rate. On each interrupt you add a step value to an accumulator, and send the MSB of the accumulator to an output pin. You control the output frequency by changing the step value. This is essentially a 1-bit version of the phase accumulator approach used by the AD9833 (and by the Daqarta Generator). The frequency resolution is controlled by the sample rate and the size of the accumulator. You can easily get much better than 0.1 Hz resolution.
Best regards,
X:471 Y:486 Z:476
X:468 Y:478 Z:467
X:454 Y:460 Z:450
X:436 Y:435 Z:422
X:392 Y:379 Z:364
X:327 Y:305 Z:296
X:270 Y:248 Z:250
X:248 Y:236 Z:246
X:260 Y:258 Z:269
X:292 Y:297 Z:307
X:321 Y:331 Z:341
X:375 Y:398 Z:406
X:439 Y:465 Z:465
X:478 Y:502 Z:494
X:489 Y:503 Z:491
X:478 Y:487 Z:475
X:462 Y:465 Z:451
X:413 Y:401 Z:385
X:343 Y:321 Z:313
X:272 Y:247 Z:249
X:253 Y:239 Z:248
X:260 Y:256 Z:268
X:288 Y:293 Z:304
X:320 Y:330 Z:340
X:374 Y:394 Z:400
X:436 Y:464 Z:463
Here is my sample of data (Not moving at all) I don't know what can i do with all these data.
I wrote a blog post about this device on an Arduino that should answer your questions.
http://chrisheydrick.com/2015/02/05/adxl335-accelerometer-on-an-arduino/
In short, the values you're seeing depend on the power delivered to the ADXl335.
The sensitivity (mV/g) is stated to be ratiometric in the data sheet, and the example given is that when you deliver 3V to the power supply, the sensitivity is 300 mV/g. In a later section called “Use with operating voltages other than 3V” it gives the example of 360 mV/g with a 3.6V power supply, and 195 mV/g with a 2V power supply. You can pretty much gather that the sensitivity in mV/g is the power supply voltage divided by 10. More or less.
Another ratiometric value is the “0g bias”. The accelerometer chip can detect negative acceleration, but it doesn’t output a negative voltage signal. What you do is consider the middle point of the power supply voltage range the 0 point. My power supply voltage is 3.3V, so I have to treat 1.6V as the zero point. You’ll add have to subtract that zero point from any voltage reading to get the actual mV/g value.
I've just hooked up a electret microphone to an Arduino, and I'd like to sample between the ranges of 1 kHz and 4 kHz.
I understand this is limited to the machine code and the ADC, so I'm trying to keep the sketch simple.
Is it possible to sample between these frequencies with the sketch below?
const int analogPin = 0;
int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
int mn = 1024;
int mx = 0;
for (int i = 0; i < 5; ++i) {
int val = analogRead(analogPin);
mn = min(mn, val);
mx = max(mx, val);
}
if (mx-mn >= 50) {
digitalWrite(ledPin, HIGH);
}
else {
digitalWrite(ledPin, LOW);
}
}
Arduino is a prototyping platform consisting of a number of hardware boards plus a software abstraction layer. For a question like this, it is useful to consider the capabilities of the underlying hardware, as these provide the ultimate limits. I'll assume you are using Arduino Uno/Nano, the story is different for Due.
According to the datasheet, each ADC reading (beyond the first one) takes 13 ADC clock cycles. ADC clock (different from the MCU) clock is derived by dividing the system clock by some factor, at least 2. So at 16Mhz board this amounts to 0.6 million samples per second. So far so good. However, that's not the end of the story, you still need to read the data. If you use interrupts, even if you do something very simple, experience suggests that you will lose about 100 clock to interrupt processing. Now you are down to 126K samples/second. But this is a theoretical maximum.
The datasheet states that for maximum accuracy for the ADC requires 50kHz - 200kHz ADC clock. In the Arduino code (in wiring.c), a division factor of 128 is chosen:
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
This means that each conversion takes 128*13 = 1764 clocks, which yields a theoretical maximum of 10K samples per second. It is a little bit worse than that given that the readAnalog() function does something beyond just starting the ADC conversion and waiting for it to finish, but it shouldn't be too much worse. This doesn't involve your code of course: any processing you do on the results of readAnalog() will make it more difficult to capture more samples. But yes, to capture at 4Khz you will need to make sure that you code spends less than 1.5k clock cycles/sample, which should be doable. Note that if you are doing five readings like you are doing in the code you posted, the maximum capture rate will be 2kHz if your code does very little.
As far as how to capture the data, you need to make deal with the fact that microphones without amplification will not give you 0-5V readings that you might expect if you are using analogRead(). In fact, microphone output voltages swing from positive to negative, however, the negative voltages will not be picked up by the ADC, and show up as just zeros, unless you give your microphone a voltage offset.
I am not exactly sure what your code that compares minimum amplitude to maximum amplitude is supposed to be doing. Are you wanting to digitize the audio? In this case you need to save all the amplitude readings collected from analogRead(), and then you can run FFTs on them on another computer: Arduino is most likely not going to be fast enough to do frequency analysis on the data.
I have heard, or rather remember reading, that the ADC could handle up to 10k-samples per second, so it should be OK up to 5 kHz. However, I have not tried this nor do I have a link to back it up at the moment.
Just try and see.
Now I know some of the Arduino library functions are slow, notably the DigitalRead/Write that has overhead of hundreds of cycles. Most of this is the sanity checking that allows people to just perform DigitalRead/Write without thinking much about setting everything up.
However, to squeeze out the maximum performance you could look into writing your own AnalogRead that is optimized for your use case.
At least some links on the subject:
Pin I/O performance (JeeLabs)
C++ Template method for faster access (JeeLabs)
I happen to have just tried this using an Arduino Uno and similar code to yours and I've been able to sample an average of 8000 times a second. That is the Nyquist frequency for 4 kHz so you're good but not much margin for error.