I'm currently working on my final year study project , i'm using arduino due and the ultrasonic sensors which are placed on a wheelchair to make an autonomous one.
so my problem is that i'm reading the distances from the sensors and i need to send them tomatlab simulink to use them in the fuzzy logic controller block but i can't because what i'm sending in the serial monitor from ardiuno is something like "
#distance1#distance2#...#distance10# " which is a string type,so how can i get the data (distances) using serial port to use them in matlab simulink.
Do i have to change the arduino code or should i use some block in simulink?
any response might be helpfull
You need to parse the input, based on the delimiter, and decide you often you should sample the sensor.
You want your input to be split at the hash. You should use something like:
str = input; % from arduino buffer
delimiter = "#";
C = strsplit(str,delimiter)
C = int(C) % type case to an int
You probably should read every 5th signal based on the frequency of the sensor. If the sensor takes 100 measures per second you probably only need 20 to be processed. This looks like:
C = C[1:5:end]
Maybe...
Processing the signal you might want to use error std from the data sheet of the sensor somewhere. Parse the input probably either before it gets passed into simulink, or as one of the first blocks. It is kind of up to you (I don't know if there is a best practise).
I hope that helped!
The docs for str split is here:
http://au.mathworks.com/help/matlab/ref/strsplit.html
Related
I have a problem about receiving 16-bit data in MATLAB.I cannot receive 16-bit data at high speed through UART in MATLAB software.
Using stm32, I divide a 16-bit data belonging to a sensor into two 8-bit data and send it to MATLAB through UART. And in MATLAB software, I combine these two 8-bit data together and 16-bit sensor data is obtained. In MATLAB software, at first a valid data is sent to stm32. until this data is not sent to stm32, stm32 does not send data, This is so that MATLAB gets the data order right, but it only happens once.
With the test I did, I realized that the process of separating and combining the data is done correctly.
But when I want to receive sensor data, only the first data is stored in each loop (2530) and for example if I receive 1000 data, 1000 of the first data are stored (2530).
I received the sent data of the stm32 using a serial plotter software on the computer and the data is sent to the computer correctly.
When I put a delay of 20 milliseconds in the stm32, the problem is solved and I think that the code I wrote for MATLAB is not optimal and maybe there is a better code for this task.
And the delay of 20 milliseconds is too much for my work . I need to send the data to MATLAB as fast as possible and the data will be ploted live in MATLAB.
When I delete the plot command from MATLAB, the performance of the program improves, but the problem is not solved
What should I do to fix this problem?
clear
close all;
load('fi4.mat');
clc
serialportObj = serialport("COM3",115200);
i=2
tim=0;
data=0;
w=0;
data_valid=0;
validate=11;
write(serialportObj, validate, "uint8");
while(1)
tic
data=read(serialportObj,2,"uint8");
res = double(typecast([uint8(data(2)), uint8(data(1))], 'uint16'))
%FilterdSignal=filter(Hd, res);
sig(i)=res;
w(i)=sig(i)+(0.95*w(i-1));
ff(i)=w(i)-w(i-1);
if i <=300
figure(2)
plot (sig);
else
figure(2)
plot(sig(end-300:end));
end
i=i+1;
c=toc;
tim=c+tim;
end
I would like to get peak value from STM32 adc samples. I have written the below code and I've managed to get peak value however most of the time this value includes the biggest noise. In order to eliminate noise effects, I have decided to apply averaging method. I would like to get 5 measurements' averages. Then I'd like to compare these averages and use the biggest one(biggest average). Can anybody suggest a code?
Regards,
Umut
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
ADC_raw = HAL_ADC_GetValue(hadc);
Vdd = 3.3 * (ADC_raw)/4095;
if (Vdd > Vmax)
{
Vmax = Vdd;
}
At first, I would remove as much code as possible from the Callback function because it is still inside the interrupt context which should be as short as possible. This is mentioned in a lot of answears here so I will not go into details on how to handle this.
For averaging the measurement, there are multiple ways you can go.
Automatic avarage
Use the ADCs oversampling function. The controller will sample the signal multiple times (configure using OVFS register) and calculate an average value before triggering the interrupt.
Manual average
Using the HAL_ADC_ConvCpltCallback function Store the numer of desired value into an array and calculate the average in the main loop.
Manual average using DMA
Let the DMA store the number of samples you want to use in an array using the function HAL_ADC_Start_DMA. When all samples have been collected you will be notified. This will reduce the processor load because you don't have to shift the data into the array yourself.
You can also combine the oversampling (most of the time a good idea) and one of the other methods depending on your Use-Case.
I have some data which is time-stamped by a NMEA GPS string that I decode in order to obtain the single data point Year, Month, Day, etcetera.
The problem is is that in few occasions the GPS (probably due to some signal loss) goes boinks and it spits out very very wrong stuff. This generates spikes in the time-stamp data as you can see from the attached picture which plots the vector of Days as outputted by the GPS.
As you can see, the GPS data are generally well behaved, and the days go between 1 and 30/31 each month before falling back to 1 at the next month. In certain moments though, the GPS spits out a random day.
I tried all the standard MATLAB functions for despiking (such as medfilt1 and findpeaks), but either they are not suited to the task, either I do not know how to set them up properly.
My other idea was to loop over differences between adjacent elements, but the vector is so big that the computer cannot really handle it.
Is there any vectorized way to go down such a road and detect those spikes?
Thanks so much!
you need to filter your data using a simple low pass to get rid of the outliers:
windowSize = 5;
b = (1/windowSize)*ones(1,windowSize);
a = 1;
FILTERED_DATA = filter(b,a,YOUR_DATA);
just play a bit with the windowSize until you get the smoothness you want.
I'm having an issue which is partially Matlab- and partially general programming-related, I'm hoping that somebody can help me brainstorm for solutions.
I have an external microcontroller that generates a large stream of binary data (~40kb) every 400ms and sends it via UART to a PC running Matlab scripts. The data is not encoded in hexa or dec characters, but true binary (hence, there's no terminator defined as all 256 values are possible, valid combinations of data). Baudrate is set at 1024000. In short, it takes roughly 375ms for a whole stream of data to be sent, with 25ms of dead time in between streams
In Matlab, the serial port is configured correctly (also 1024000, 8x bits, 1x stop bit, no parity, no hardware flow control, etc.). I am able to readout the data I'm sending via the microcontroller correctly (i.e. there's no corruption of data), but I'm not being able to synchronize the serial readout on Matlab. My script is as follows:
function data_show = GetDATA
if ~isempty(instrfind)
fclose(instrfind);
end
DATA_TOTAL_SIZE = 38400;
DATA_buffer = uint8(zeros(DATA_TOTAL_SIZE,1));
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])';
f_data_in = false;
f_data_out = true;
serialport = serial('COM11','BaudRate',1024000,'DataBits',8,'FlowControl','none','Parity','none','StopBits',1,...
'BytesAvailableFcnCount',DATA_TOTAL_SIZE,'BytesAvailableFcnMode','byte','InputBufferSize',DATA_TOTAL_SIZE * 2,...
'BytesAvailableFcn',#GetPortData);
fopen(serialport);
while (get(serialport,'BytesAvailable') ~= 0) % Skip first packet which might be incomplete
fread(serialport,DATA_TOTAL_SIZE,'uint8');
end
f_data_out = true;
while (1)
if (f_data_in)
DATA_buffer = fread(serialport,DATA_TOTAL_SIZE,'uint8');
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])'; %Reshape array as matrix
DATAsc(DATA_show);
disp('DATA');
end
pause(0.01);
end
fclose(serialport);
delete(serialport);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function GetPortData (obj,~)
if f_data_out
f_data_in = true;
end
end
end
The problem I see is that what I end up reading is always the correct size, but belongs to multiple streams, because I haven't found a way to tell Matlab that these 25ms of no data should be used to synchronize (i.e. data from before and after that blank period should belong to different streams).
Does anyone have any suggestions for this?
Thanks a lot!
For completeness, I would like to post the current implementation I have fixing this issue, which is probably not a suitable solution in all cases but might be useful in some.
The approach I took consists in moving into a bi-directional communication protocol, in which Matlab initiates the streaming by sending a very short command as a trigger (e.g. single, non-printable character). Given the high baudrate it does not add significant delay due to processing in the microcontroller's side.
The microcontroller, upon reception of this trigger, proceeds to transmit only one full package (as opposed to continuously streaming package at a 5Hz rate). By forcing Matlab to pickup a serial package of the known length right after issuing the trigger, it ensures that only one package and without synchronization issues is received.
Then it becomes just a matter of encapsulating the Matlab script in a routine with a 5Hz tick given by a timer, in which the sequence is repeated (send trigger, retrieve package, do whatever processing, and repeat).
Advantages of this:
It solves the synchronization problems
Disadvantages of this:
Having Matlab running on a timer tick does not ensure perfect periodicity, and hence the triggers might not always be sent at exactly 5Hz. If triggers are sent at "inconvenient" times for the microcontroller, packages might need to be skipped in order to avoid that a package is updated in memory while it is still being transmitted (since transmission takes a significant part of the 200ms time slot)
From experience, performance can vary a lot depending on what the PC running Matlab is doing. For example, it works fine when the PC is left on its own to do the acquisition, but if another program is used (e.g. Chrome), Matlab begins to lag and that results in delays in transmission of triggers.
As mentioned above, it's not a complete answer, but it is an approach that might be sufficient in some situations. If someone has a more efficient option, please fell free to share!
I'd like to send multiple signals (4 inputs and outputs and 7 outputs) from my Laptop to a microcontroller. I'm thinking of using a USB to serial converter and multiplexing the data through the port. I'll need to write codes both in the laptop end and in the microcontroller to multiplex the data.
Eg:
Tx of microcontroller:
1.Temperature sensor ADC output->Laptop
2.Voltage sensor to laptop
3.Current Sensor to Laptop
4.Photodiode current to Laptop
So I need to write a program in the microcontroller to send the data in this order. How can I accomplish this? I was thinking of an infinite loop which sends the data with time delays in between.
At the Rx pin of Microcontroller,
Seven bit sequences. Each bit sequence will be used to set the duty cycle of a PWM generated by the microcontroller.
I also need the same multiplexing or demultiplexing arrangement in the matlab end. Here too, I'm thinking of allotting some virtual 'channels' at different instants of time. What kind of algorithm would I need?
In case you always send all the inputs/outputs at the same rate, you could simply pack them into 'packets', which always start with one or more bytes with a fixed value that form a 'packet header'. The only risk is that one of the bytes of the sensor data might have the same value as the start-byte at the moment you try to start receiving bytes and you are not yet synchronized. You can reduce this risk by making the header longer, or by choosing a start-byte that is illegal output for the sensors (typically OxFF or so).
The sending loop on the microcontroller is really easy (pseudocode):
while True:
measure_sensors()
serial.send(START_BYTE)
serial.send(temperature)
serial.send(voltage)
serial.send(current)
serial.send(photodiode)
end while
The receiving loop is a bit more tricky, since it needs to synchronize first:
while True:
data = serial.receive()
if data != START_BYTE:
print 'not synced'
continue #restart at top of while
end if
temperature = serial.receive()
voltage = serial.receive()
current = serial.receive()
photodiode = serial.receive()
do_stuff_with_measurements()
end while
This same scheme can be used for communication in both directions.