XBee end node reads same IO sample always for rotary angle sensor - sensors

I have 3 XBee SMT Grove Development Boards. I configured two of them as coordinator and endnode respectively. Note that the end node is not connected to any intelligent computer via its serial interface. It is simply powered on and is configured to read an analog sample at regular intervals and transmit it to the coordinator.
My intension is to connect an analog sensor (example: Rotary angle sensor) and transmit the knob position at regular intervals to the coordinator (using the IO data sample indicator frame).
I connected the sensor to the AD3 slot of the end node. And end node reads a sample of data and successfully sends this value to the coordinator at regular intervals. However I noticed that for a position of approximately 0-150 degrees, the IO sample value as received at the coordinator seems to be (21-1023). Meaning, the value changes according to the knob position. But when I move the knob position further (the supported rotation range by the sensor is 0-300 degrees), from 150-300 degrees, I notice the value always remains constant(1023).
I know that 2 bytes of analog samples can be transmitted via this frame. And the IO sample of the sensor is also 2 bytes. So I am wondering why the value remains the same for half the position of the rotary where as for the first half it changes as expected ?
Please note that the sensor is already tested on a Grove Pi+ shield on a Raspberry Pi for correctness using the example code. It works perfectly throughout the whole range.
Thank you all for your time.

Related

ESP8266 analogRead() microphone Input into playable audio

My goal is to record audio using an electret microphone hooked into the analog pin of an esp8266 (12E) and then be able to play this audio on another device. My circuit is:
In order to check the output of the microphone I connected the circuit to the oscilloscope and got this:
In the "gif" above you can see the waves made by my voice when talking to microphone.
here is my code on esp8266:
void loop() {
sensorValue = analogRead(sensorPin);
Serial.print(sensorValue);
Serial.print(" ");
}
I would like to play the audio on the "Audacity" software in order to have an understanding of the result. Therefore, I copied the numbers from the serial monitor and paste it into the python code that maps the data to (-1,1) interval:
def mapPoint(value, currentMin, currentMax, targetMin, targetMax):
currentInterval = currentMax - currentMin
targetInterval = targetMax - targetMin
valueScaled = float(value - currentMin) / float(currentInterval)
return round(targetMin + (valueScaled * targetInterval),5)
class mapper():
def __init__(self,raws):
self.raws=raws.split(" ")
self.raws=[float(i) for i in self.raws]
def mapAll(self):
self.mappeds=[mapPoint(i,min(self.raws),max(self.raws),-1,1) for i in self.raws ]
self.strmappeds=str(self.mappeds).replace(",","").replace("]","").replace("[","")
return self.strmappeds
Which takes the string of numbers, map them on the target interval (-1 ,+1) and return a space (" ") separated string of data ready to import into Audacity software. (Tools>Sample Data Import and then select the text file including the data). The result of importing data from almost 5 seconds voice:
which is about half a second and when I play I hear unintelligible noise. I also tried lower frequencies but there was only noise there, too.
The suspected causes for the problem are:
1- Esp8266 has not the capability to read the analog pin fast enough to return meaningful data (which is probably not the case since it's clock speed is around 100MHz).
2- The way software is gathering the data and outputs it is not the most optimized way (In the loop, Serial.print, etc.)
3- The microphone circuit output is too noisy. (which might be, but as observed from the oscilloscope test, my voice has to make a difference in the output audio. Which was not audible from the audacity)
4- The way I mapped and prepared the data for the Audacity.
Is there something else I could try?
Are there similar projects out there? (which to my surprise I couldn't find anything which was done transparently!)
What can be the right way to do this? (since it can be a very useful and economic method for recording, transmitting and analyzing audio.)
There are many issues with your project:
You do not set a bias voltage on A0. The ADC can only measure voltages between Ground and VCC. When removing the microphone from the circuit, the voltage at A0 should be close to VCC/2. This is usually achieved by adding a voltage divider between VCC and GND made of 2 resistors, and connected directly to A0. Between the cap and A0.
Also, your circuit looks weird... Is the 47uF cap connected directly to the 3.3V ? If that's the case, you should connect it to pin 2 of the microphone instead. This would also indicate that right now your ADC is only recording noise (no bias voltage will do that).
You do not pace you input, meaning that you do not have a constant sampling rate. That is a very important issue. I suggest you set yourself a realistic target that is well within the limits of the ADC, and the limits of your serial port. The transfer rate in bytes/sec of a serial port is usually equal to baud-rate / 8. For 9600 bauds, that's only about 1200 bytes/sec, which means that once converted to text, you max transfer rate drops to about 400 samples per second. This issue needs to be addressed and the max calculated before you begin, as the max attainable overall sample rate is the maximum of the sample rate from the ADC and the transfer rate of the serial port.
The way to grab samples depends a lot on your needs and what you are trying to do with this project, your audio bandwidth, resolution and audio quality requirements for the application and the amount of work you can put into it. Reading from a loop as you are doing now may work with a fast enough serial port, but the quality will always be poor.
The way that is usually done is with a timer interrupt starting the ADC measurement and an ADC interrupt grabbing the result and storing it in a small FIFO, while the main loop transfers from this ADC fifo to the serial port, along the other tasks assigned to the chip. This cannot be done directly with the Arduino libraries, as you need to control the ADC directly to do that.
Here a short checklist of things to do:
Get the full ESP8266 datasheet from Expressif. Look up the actual specs of the ADC, mainly: the sample rates and resolutions available with your oscillator, and also its electrical constraints, at least its input voltage range and input impedance.
Once you know these numbers, set yourself some target, the math needed for successful project need input numbers. What is your application? Do you want to record audio or just detect a nondescript noise? What are the minimum requirements needed for things to work?
Look up in the Arduino documentartion how to set up a timer interrupt and an ADC interrupt.
Look up in the datasheet which registers you'll need to access to configure and run the ADC.
Fix the voltage bias issue on the ADC input. Nothing can work before that's done, and you do not want to destroy your processor.
Make sure the input AC voltage (the 'swing' voltage) is large enough to give you the results you want. It is not unusual to have to amplify a mic signal (with an opamp or a transistor), just for impedance matching.
Then you can start writing code.
This may sound awfully complex for such a small task, but that's what the average day of an embedded programmer looks like.
[EDIT] Your circuit would work a lot better if you simply replaced the 47uF DC blocking capacitor by a series resistor. Its value should be in the 2.2k to 7.6k range, to keep the circuit impedance within the 10k Ohms or so needed for the ADC. This would insure that the input voltage to A0 is within the operating limits of the ADC (GND-3.3V on the NodeMCU board, 0-1V with bare chip).
The signal may still be too weak for your application, though. What is the amplitude of the signal on your scope? How many bits of resolution does that range cover once converted by the ADC? Example, for a .1V peak to peak signal (SIG = 0.1), an ADC range of 0-3.3V (RNG = 3.3) and 10 bits of resolution (RES = 1024), you'll have
binary-range = RES * (SIG / RNG)
= 1024 * (0.1 / 3.3)
= 1024 * .03
= 31.03
A range of 31, which means around Log2(31) (~= 5) useful bits of resolution, is that enough for your application ?
As an aside note: The ADC will give you positive values, with a DC offset, You will probably need to filter the digital output with a DC blocking filter before playback. https://manual.audacityteam.org/man/dc_offset.html

Pymodbus read register continuosly in read time fails

I have an intelligent sensor for measure robot axis movements, i would read valuesusing modbus for every single reading position (it read values every 100ms)
I try using pymodbus:
slave = ModbusSerialClient(port='/dev/ttyAMA4', parity=N, baudrate=9600, timeout=1)
slave.connect()
while True:
print(slave.read_input_registers(300013, 2, unit=10))
time.sleep(0.01)
The problem is, my script start and read the first values but in 5,6 seconds exit because too many request to devices (devices does not respond)
There is a method for call a modbus device and get values in "RealTime" for example every milliseconds without problem due to the hight volumes of continuosly calls?
So many thanks in advance
Your code reads values at about every 10ms rather than 100ms. Typo?
Since your purpose is to get values in "realtime", but how fast you can achieve mostly depends on the sensor, if you can find the specs from sensor datasheet, e.g. minimal polling interval, please code accordingly, otherwise, you can keep testing with different interval values until you are satisfied.

bluefruit NRF52 max connection interval speed (connInterval)

I've got an Adafruit Bluefruit NRF52 hooked up to the Adafruit BNO055 9-axis orientation sensor, gathering 3 axis of absolute orientation plus 3 axis of acceleration (6 floats in total) and sending over Bluetooth through bleuart. I need the bleuart to update every 7.5 milliseconds with a new line of values, but when I run it, it doesn't print more than about 20 lines new lines of values every second. Essentially I need values to update as quickly as possible, as I am measuring very high speed, high fidelity movement.
At the start of each line I also have three digit number, which represents the calibration status of each sensor on the IMU. Each printed line looks something like:
303 68.69 4.19 -2.19 -0.12 0.14 -0.40
I am currently streaming to my iphone with the latest iOs version, which in theory can handle 7.5ms intervals.
I've read that a solution may be to buffer the values and send over in a larger chunk at larger connection intervals, but am unsure on how to do this.
My relevant Arduino code is below:
Bluefruit.setConnIntervalMS(7.5, 20);
void loop()
{
imu::Vector<3> accel =
bno.getVector(Adafruit_BNO055::VECTOR_LINEARACCEL);
/* Get a new sensor event */
sensors_event_t event;
bno.getEvent(&event);
/* Display the floating point data */
bleuart.print(event.orientation.x);
bleuart.print("\t");
bleuart.print(event.orientation.y);
bleuart.print("\t");
bleuart.print(event.orientation.z);
bleuart.print("\t");
/* Display the floating point data for Linear Acceleration */
bleuart.print(accel.x());
bleuart.print("\t");
bleuart.print(accel.y());
bleuart.print("\t");
bleuart.print(accel.z());
bleuart.print("\n");
}
iOS doesn't actually support a 7.5ms connection interval. Check the connection parameters section (11.6) in the Apple developer guidelines. Just because you are specifying a CI that low doesn't mean that you'll actually get it. In this scenario the nRF52 is the slave and only requests an interval that low from the master (your phone). The master, if it so wishes, can completely disregard the request you make.
You'd be better off, as you've already eluded to, buffering your data and sending it via a custom characteristic. Figure out how many bytes you need and maybe you can pack a couple of readings into a single BLE write. If you're really struggling with throughput then you'll need a custom service with multiple characteristics. I recently worked on a project that streams 8 channels of data (~125Hz/16-bit) over BLE with three characteristics and this is bordering on the maximum throughput you can achieve.
As an aside: judging data throughput by the amount of lines printed per second is a big no no. Print functions typically have huge overheads and will drastically affect your measured throughput in a negative way.
Let me know if I can help further.

FPGA implementation of temperature sensor data in 7 segment display

I want to know about project related to temperature sensor , like the temperature 80 degrees is sensed the it will send signal to FPGA and it should display "error" into seven segment display. and temperature sensor is connected to one machine and FPGA is connected to the generator, both the machines are connected to each other though for supply voltage. how to integrate both?? Please help...

Generate sine wave using ADC

I have a adc module on my board. I create a sine wave on signal generator. And I give output of this generator to a adc pin. Finally I read value of this pin periodically. I try to create a sine wave on my software.
x = t,
y = Asin(wt),
A : amptitute value of the generator,
w : 2πf, f : I set its value on my software.(difference time between two read operation)
t : time
And I don't use value of adc pin. Isn't this value important to create wave?
I will try to provide you with some hints based on what I understood from your post.
The ADC is supposed to sample the analogue signal generated at a defined frequency in order to yield a digital signal. In your case, you need two information to trace your curve:
Data:
data to be traced (samples) which represents the amplitude of the signal all along sampling time (at each sampling instant).
Time:
you need to know the period in time at which ADC is sampling the signal then associate each data with its corresponding instant in time. Period can be deduced from the frequency at which ADC samples signal T = 1/f.
ADC stores each sampled data in a register and an interrupt would be generated to notify processor about a new coming data. Your interrupt service routine (in case you are proceeding with interrupts) must be able to extract that data before it will be replaced by the next sample. As a suggestion, you may create a buffer within your application where your interrupt routine could store data in it. Then, your application can extract data from buffer and use it to draw the curve if your system has a display output or send it to a desktop application that will do the job.
You don't need to stick to the equation in your post; it is for analogue. Rather you can think of the digitized curve as f(t) = Data(t).
As you are using linux, if you don't want to deal with interrupts you may proceed with reading data using /sysfs interface. Note that opening a file to read data for every single sample could be slow depending on your application requirements.

Resources