I am designing the controller and data acquisition unit for a rocket engine test stand. This system needs to control a number of actuators on the test stand and also be able to transmit collected data back to the host computer where the team will be watching live data/camera feeds from safety.
The overall design requirements are as follows:
Acquire data from ~15 analog sensors at 1KHz
Control the actuators on the test stand including valves and ignition switches
Transmit data back to the host computer in our shelter in real time
Accept control from the host computer for things like manual valve actuation, test sequence modification, sequence abortion, etc.
I am not exactly sure where to begin when laying out the software for this system. I am considering using an STM32 ARM Cortex-M4 processor running at 180 MHz. I am having trouble figuring how I should approach the problem. I have considered using an RTOS system but based on what I have seen those generate large overheads as you run them faster as the scheduler has to run each tick. The other idea I'm bouncing around is a state machine combined with some timer-based interrupts for reading and then sending data back out to the PC. Any advice as to how to approach this problem to minimize code complexity would be greatly appreciated. Thanks.
EDIT:
I have been told to clarify a number of things concerning the technical specs of the system.
My actuators consist of:
6 solenoids (controlled digitally through relays/MOSFET, and switched around once a second)
2 DC motors (driven with PWM outputs in a PID loop, need to be able to ramp position controllably)
One igniter, again controlled through a relay/MOSFET
My sensors consist of:
8 pressure transducers (analog voltages)
4 thermocouples (analog voltages)
2 motor encoders (quadrature encoders)
1 light sensor (analog voltage)
1 Load cell (analog voltage)
Ideally all of the collected data (all of the above sensors) plus some additional data (timestamps, motor set positions, solenoid positions) is streamed back to the host computer at in real time.
Given the motor control with PWM & PID, you need to specify a desired resolution, either in PWM timer ticks or ADC reads. This is the most critical part. It doesn't hurt if the ADC has greater resolution than your specified resolution either. The PCB has to be designed accordingly, with sufficient resolution on resistors etc.
After you've done this, find MCU with sufficiently accurate ADC. I would imagine that 12 bit resolution is enough for most applications, but I don't know your specific case.
Next, you need to decide how fast you want the PID to be. Should an output on the PWM result in a read on the ADC in the next cycle, or could you settle for slower response? The realtime bottleneck here will be the ADC conversion clock, not the CPU.
The rest of the system doesn't seem time critical at all - you just have to ensure that everything is read/set synchronously. The data transmission to/from the host should preferably be done over CAN since it comes with hard real-time characteristics. Doesn't seem that you need a whole lot of bandwidth.
I have designed systems very similar to this using bare metal 16 bit MCUs running on 16MHz. Processing speed is really not a big concern, but meeting real-time deadlines is. That means you can forget about using Linux toys like Rasp PI, it's completely out of the question. And a RTOS is likely overkill since it mostly adds additional complexity.
A bare metal Cortex M with sufficient ADC resolution and CAN seems like a good choice. If you can stay away from floating point, that's nice too - depends on how advanced math you need. If you need nothing more advanced than PID, it can be implemented with fixed point just fine. (Or PI rather, since that usually works best for fast motor control systems.)
I am working on a project to control switching of gates for an inverter with python in Raspberry Pi.
There is this sequence of pins I need to turn off and on in a cycle to achieve this with some time delay inbetween for adjusting the frequency. But as I wanna develope my code to next level, now I would like to adjust the delay in loop in real time to adjust the frequency ,I am trying to change the speed of the execution of the loop without stopping the loop itself in real time, is there any way to do this in python?
I am playing around with a PIC 24 and currently I have a bit of a problem with converting hertz to seconds and then using it as a delay for a signal send to a piezo piece(buzzer, zoomer, speaker, etc) and I would like to make it play certain notes.
I want to know if I am doing my conversion from hertz to seconds(mseconds in the code provided) and if I am doing my signal processing properly.
Here is the code where I am troubled with:
My hertz to int conversion:
int16 note(int i)
{
float time = (1.0/i);
int fin = ((time/2) * 1000);
return fin;
}
and here is how I send the signal to the pic24 I am using:
void main()
{
InitMCU();
output_high(PIN_D1);
delay_ms(note(E));
output_low(PIN_D1);
delay_ms(200);
output_high(PIN_D1);
delay_ms(note(E));
output_low(PIN_D1);
delay_ms(200);
}
Here is how I have defined the notes:
#define C 255 //do
#define D 227 //re
#define E 204 //mi
#define F 191
#define G 170
#define A 153
#define B 136
#define C2 127
You need a loop!
repeat for note length:
on
delay
off
delay
Also consider calculating the required period for each note off-line and enter it as an integer instead of in Hz - the CPU wont be wasting time in floating point calculations
first off you are trying to use square waves to make sine waves. So it is always going to sound a bit wrong if you aim specifically for the target frequency with the timer. make a 440Hz square wave it doesnt "sound" like a 440Hz sine wave. Maybe the physics will round it off but, I am betting not as much as you want.
You can if you have the speed. Do the one bit DAC thing from the 90s or whenever that was. If you can make your square waves go faster than the speaker can physically move you can say sprinkle more ones than zeros for a while say pushing the speaker out a bit at a controlled rate then more zeros than ones for a while teasing the speaker in. The speaker becomes a physical low pass filter. You can probably use the PWM in the microcontroller to help with this. But you need to dynamically change it and this is PIC so you are likely to run out of resources before you can code up a lot of tables for clean sound.
To do the square wave thing, you need to change the output pin at half the frequency. Do not do the calculations at runtime, do then on your calculator or let the toolchain do it. Say you are running your processor/timer at 1Mhz, and you want 440Hz on a pin. You need the period to be 1/440. hz is cycles per second so inverting that makes it seconds per cycle. 0.00227272 (repeating) seconds per cycle or period, so you need it high for half and low for half (or vice versa, doesnt matter) so
that means 0.00113636... between output state changes. If your timer was 1Mhz that is 1/1Million seconds per cycle. Or one microsecond. how many microseconds in 0.00113636... 1136. So every 1136 timer ticks you change state, you read the docs on the timer and have it count down or up or whatever 1136 counts (usually these are zero based numbers so 1135 and then count the zero and then the interrupt or status flag or whatever). you can also probably poll a counter that counts to/from all ones to/from all zeros and rolls over, subtract then from now and mask it with the number of bits that are counting and the difference is the time. with a 16 bit counter (start-now)&0xFFFF is the difference so long as your desired time is enough less than 0xFFFF. 1136 would certainly be. wait until the start minus now (if it is a down counter or now mins start if up counter).
Pre-compute your count times for a half cycle of each of these frequencies you want. when you make a tone you have to in some way loop every cycle on for the half period, off for half period, on for half period off for half period.
Depending on the speaker and your frequency it should sorta work. If you want to try the one bit thing
https://en.wikipedia.org/wiki/1-bit_DAC
you could start with a triangle wave do a say 66% duty cycle for 1/4th of the 1136 microseconds, a 33% duty cycle for 1/2 of the 1136 microseconds then 66% for the final 1/4th. Or one time do a 1/4th then do 1/2 at one duty cycle then 1/2 at another. You should be able to find or write a low pass filter, not that you would know what the speaker properties are but you can get a feel for how to generate the slower wave within the higher. After a triangle you could try a trapezoid. ramp up at some rate, do a 50% for a bit, then ramp down, repeat for the other half of the period.
For experimental purposes, find or pre-compute a sequence covering the whole period, you could have code that generates some few hundred or thousand lines of code, with a pic you can be fairly if not exactly deterministic X number of microseconds can be achived by executing exactly Y number of instructions or the right mix of Y instructions like
on
on
off
on
off
on
on
off
then the last instruction jumps to the top, again experimental, but you may find if you do it right you get a cleaner sound, perhaps much cleaner than a square wave.
you can add a simple R/C filter, literally two components, to convert your bit stream into an analog waveform that you then feed the speaker or amplify then feed the speaker, the feature here is you can look at it on a scope.
The other path you can take on the cheap and easy is a resistor ladder, instead of one bit you output basically the analog value for that place in the period and use a resistor ladder to turn that into an analog signal.
Or just use a real dac. based on how fast you can feed the dac pre-compute the number of values you need to send for one period, and make a table and just send them, in a loop until you are done with that frequency.
so with all that back to your code. you are trying to use some I guess millisecond library function? so lets say that is what you want to do.
440Hz as we saw is 0.00113636 seconds for a half period, so that would be 1millisecond on then one millisecond off, your code should do this
for(i=0;i<nperiods;i++)
{
on
delay_ms(1)
off
delay_ms(1)
}
any other delays in there just make it wrong...for a square wave. for others then I doubt you will have hardcoded delays.
So there are a number of problems with the above, first off a millisecond delay is way to slow for what you are trying you need a microsecond delay and you need to understand how long it takes for the overhead in the loop, our math showed 1136 microseconds for 440hz, with some truncating of accuracy. but the code that does the delay, esp on a slow mcu like this takes many clock cycles, if this is C code and not asm then many many more, plus the code to turn the gpio pin on and off, you have to subtract/tune those out. A scope will help, if you start off with 1136 and the scope is showing a period of 3000us instead of 2272.7 then you need to subtract that out and try again. so a delay of 772 instead of 1136. that kind of thing.
Middle C is 261.6Hz according to google, right or wrong lets run with it. that is 3823 microseconds. feeding your note function 255, which I assume is what the defines are for gives 1.9 I assume milliseconds. which is right as far as milliseconds goes. which gets truncated to 1 millisecond or 2000 microseconds which is 500hz which is of course way off. that define should have been 261 or 262 not 255 anyway right?
hmmm so you are trying to make a high pulse then a fixed length low pulse of 200ms? so if you fed it note E and assumed that the code took no time to run. it would be high for 2 ms then low for 200, and assuming you repeated that that is a 1% duty cycle at the frequency of 1/201ms or 4.97...Hz, the piano frequencies
https://en.wikipedia.org/wiki/Piano_key_frequencies
dont show a note at 5hz. I am sure it is close to some harmonic down there, but pretty low.
A would be 3ms high 200 low or a frequency of 1/203ms or 4.9hz
Other than the math, doing runtime floating point on a pic (or anywhere that doesnt have an fpu) is extremely costly, the math alone probably takes longer than your entire cycle. absolutely no reason to compute that runtime. you could have easily made the defines with the math or used your calculator and made the defines with hardcoded hand computed numbers. It still wouldnt have worked with a fixed low period esp one that is so significantly large compared to the numbers you need. with millisecond delay assuming the code ran instantly. on delay 1ms off delay 1ms is 500hz. on, delay 2, off delay 2, 250hz, delay 3 is 166, delay 4 is 125 and so on. you are not going to hit many real notes assuming the code ran instantly which it doesnt and using a millisecond delay.
to make the pressure wave you want to basically have the speaker pushed out from its resting state for half the cycle and sucked back in from its resting state for half the cycle, ideally in a sine fashion so that it slowly goes out and comes back then pulls in and goes out. going from reseting state to out only will work sure, but you still need to have the duty cycle right to get close with a square wave. so understand the timers you have, with a pic you can easily hand code some loops that burn clock cycles as they are deterministic from what I remember. start with the frequency of your processor, what is it? how many processor cycles for one period of your note? same as the 440hz to 1mhz math above. 0.0011363636 times 1million (seconds per half period times ticks per second the seconds cancel out and you get ticks per half period math works on units just like numbers) if your mcu is running at 2million clock ticks per second then it is 2million times 0.001136363636...
THEN figure out how to turn it on wait that number of cpu clocks then off and wait that number of cpu clocks. feed that into your piezo or other and see how it sounds.
If you had 16 bit registers which I bet you dont but assuming a 1mhz clock you would
load reg with some number
top
subtract reg,1
compare with zero
branch to top
in assembly of course. assuming one clock cycle for the subtract and compare each then two for the branch lets say that is four per loop, so 1136/4 = 284. load the register with the pre-computed value 284.
hand code some assembly
top:
gpio on
load reg,284
one:
sub reg,1
cmp reg,0
bne one
gpio off
load reg,284
two:
sub reg,1
cmp reg,0
bne two
jmp top
crude but it would get you started down the path.
if you dont have 16 bit registers but 8 bit instead, 1mhz 1136/0x100 = 4 remainder 112 that would come out quite nice if this processor takes 4 clocks per loop as I have fantasized above. each delay would be
mov reg,0xFF
A:
sub reg,1
cmp reg,0
bne A
mov reg,28
B:
sub reg,1
cmp reg,0
bne B
there are no doubt countless resources here and other places describing delay loops for the PIC family members.
You could just wing it and see the sounds change
#define DELX 300
volatile unsigned int x;
while(1)
{
output_high(PIN_D1);
for(x=0;x<DELX;x++) continue;
output_low(PIN_D1);
for(x=0;x<DELX;x++) continue;
}
and play with different numbers for the define. the tone should change, the quality may not be that great or maybe much better than what you have now, but it should change if audible at all. there are likely cliffs that you will hit I assume it is an 8 bit processor so counting to 200 is WAYY different then counting to 300, it is not going to be a frequency that is one and a half times lower. possible it wont be linear, might be depends on the compiler, but it might be linear segments with kinks here and there. 100 to 200 might be linear and 300 to 400 but 200 to 300 might not be.
This is probably linear though
volatile unsigned int x;
unsigned int y,z;
for(z=0;z<1000;z++)
for(y=0;y<100;y++)
{
output_high(PIN_D1);
for(x=0;x<z;x++) continue;
output_low(PIN_D1);
for(x=0;x<z;x++) continue;
}
The middle A note is normally a 440 Hz tone. If you toggle your piezo speaker on and off 440 times per second, the delay between successive toggles is 1/880 of a second, which is 1.13636363636 ms. This shows two things:
your calculations are way off; and
timer resolution of one millisecond is way too coarse for this application.
Of course you need a loop to play a tone with some duration.
I'm currently working on generating a tone on a PIC32 device. The information I've found has not been enough to give me a complete understanding of how to achieve this. As I understand it a PWM signal sends 1's and 0's with specified duty cycle and frequency such that it's possible to make something rotate in a certain speed for example. But that to generate a tone this is not enough. I'm primarily focusing on the following two links to create the code:
http://umassamherstm5.org/tech-tutorials/pic32-tutorials/pic32mx220-tutorials/pwm
http://www.mikroe.com/chapters/view/54/chapter-6-output-compare-module/#ch6.4
And also the relevant parts in the reference manual.
One of the links states that to play audio it's necessary to use the timer interrupts. How should these be used? Is it necessary to compute the value of the wave with for example a sine function and then combine this with the timer interrupts to define the duty cycle after each interrupt flag?
The end result will be a program that responds to button presses and plays sounds. If a low pass filter is necessary this will be implemented as well.
If you're using PWM to simulate a DAC and output arbitrary audio (for a simple and dirty tone of a given frequency you don't need this complexity), you want to take audio samples (PCM) and convert them each into the respective duty cycle.
Reasonable audio begins at sample rates of 8KHz (POTS). So, for every (every 1/8000th of second) sample you'll need to change the duty cycle. And you want these changes to be regular as irregularities will contribute to audible distortions. So you can program a timer to generate interrupts at 8KHz rate and in the ISR change the duty cycle according to the new audio sample value (this ISR has to read the samples from memory, unless they form a simple pattern and may be computed on the fly).
When you change the duty cycle at a rate of 8KHz you generate a periodic wave at the frequency of 4KHz. This is very well audible. Filtering it well in analogue circuitry without affecting the sound that you want to hear may not be a very easy thing to do (sharp LPF filters are tricky/expensive, cheap filters are poor). Instead you can up the sample rate to either above twice what the speaker can produce (or the human ear can hear) or at least well above the maximum frequency that you want to produce (in this latter case a cheap analogue filter can help rid the unwanted periodic wave without much effect on what you want to hear, you don't need as much sharpness here).
Be warned, if the sample rate is higher than that of your audio file, you'll need a proper upsampler/sample-rate converter. Also remember that raising the sample rate will raise CPU utilization (ISR invoked more times per second, plus sample rate conversion, unless your audio is pre-converted) and power consumption.
[I've done this before on my PC's speaker, but it's now ruined, thanks to SMM/SMIs used by the BIOS and the chipset.]
For playing simple tones trough PWM you first need a driver circuit since the PIC cannot drive a speaker directly. Typically a push-pull is used as actively driving both high and low results in better speaker response. It also allows for a series capacitor, acting as a simple high-pass filter to protect the speaker from long DC periods.
This, for example, should work: http://3.bp.blogspot.com/-FFBftqQ0o8c/Tb3x2ouLV1I/AAAAAAAABIA/FFmW9Xdwzec/s400/sound.png
(source: http://electro-mcu-stuff.blogspot.be/ )
The PIC32 has hardware PWM that you can program to generate PWM at a specific frequency and duty cycle. The PWM frequency controls the tone, thus by changing the PWM frequency at intervals you can play simple music. The duty cycle affects the volume, but not linearly. High duty cycles come very close to pure DC and will be cut off by the capacitor, low duty cycles may be inaudible. Some experimentation is in order.
The link mentions timer interrupts because they are not talking about playing simple notes but using PWM + a low pass filter as a simple DAC to play real audio. In this case timer interrupts would be used to update the duty cycle with the next PCM sample to be played at regular intervals (the sampling rate).
I'm developing a system that will get the GPS signal and send it though the GSM with information about position, speed and temperature from some digital sensors.
Currently I'm using the GPS EM408, the Arduino mega plus the GSM board (official one).
The problem is that the GPS (by the library TinyGPSPlus) gives me the same speed for long time or sometimes give me 0km/h.
The sketch works like this:
loop()
{
getGPSData() - ~ 1 sec to execute and take one data from the GPS.
getSensors() - ~ 1 sec to execute and take one data from the digital sensors.
sendData() - ~ 6 n 10 secs to send the data through the internet.
}
The whole process takes around 10 ~ 15 secs to be completed.
If I remove the sendData() and the system starts getting the GPS information each second the speed value works perfectly but if I get the data from the GPS each 12 secs (because of the GSM delay) the speed doesn't work as expected.
I understand that the problem is because the library TinyGPSPlus calculate the speed between two points and the getGPSData() only takes one information each loop and the next point has 15 secs of difference.
Although I've added a "for(i=0;i<=4;i++)" to the getGPSData() enforcing it to get at least 4 times of position before the GSM send it over the internet, now is working better but still getting the wrong value or sometimes it freezes to the same speedy for long time.
I've tried to add a second board and put both to communicate with I2C turning it "dual core", where one board will be getting the data from the GPS each second and another one will send though the data each 15 secs, but the GSM freezes sometimes when the I2C is connected :(.
Does anyone has any clue how to do it?
It is not good to add "for(i=0;i<=4;i++)" loop like you tried and furthermore to add duplicate device - so far from the solution. Instead you should unbind getGPSdata() from sendData() in other words separate the calls of them into different tasks.
I can imagine it is a simple Round-robin scheduling provided with that library, not a complete RTOS in there, isn't it? Nevertheless, put them into different tasks, loops or whatever. Probably you will need to arrange a buffer to collect GPS data to and sending out this from the buffer from a different loop.
Hope it helps.