Arduino temperature sensor - arduino

I am trying to build a small program with arduino using a temperature-sensor.
I thought I knew how to do it but I'm getting some weird outputs.
Here is my code:
int sensorPin = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
int reading = analogRead(sensorPin);
float voltage = reading * 5.0 / 1024;
float temperatureC = (voltage - 0.5) * 100;
Serial.print(temperatureC); Serial.print(" degrees C, ");
Serial.print(voltage); Serial.println(" volts");
delay(1000);
}
This code gives me the output:
-26.56 degrees C, 0.23 volts
-26.56 degrees C, 0.23 volts
-27.05 degrees C, 0.23 volts
-26.56 degrees C, 0.23 volts
-26.07 degrees C, 0.24 volts
-26.07 degrees C, 0.24 volts
Why is it - in degrees? and Why can I change it to any pin I want and it will still give me a similar output?

Analog input 0 is not pin 0.
You should use the defined symbols:
A0,A1,...,A7
for analog inputs.
Try
int sensorPin = A0;
and your program should work.
If you are curious about the actual values, under your Arduino IDE install look in the file
..\hardware\arduino\variants\standard\pins_arduino.h

You are reading this input correctly.
In order for you to not get negative degrees, you'll have to process it differently.
With this:
float temperatureC = (voltage - 0.5) * 100;
Any values < 0.5 result in multiplying a negative number by 100.
Try breaking this down using commutative property.
(voltage - 0.5) * 100 is the same as (voltage * 100) - (0.5 * 100).
This can be further simplified to (voltage * 100) - 50.
Still, for all values where voltage < 0.5 the temperature will be negative.
I would suggest multiplying temperatureC by -1 to make it positive and not putting the sensor near anything that is `~ >= 50 degrees Celsius.
Also, As jdr5ca pointed out here, you're not actually getting any data from the sensor yet... :(
You are probably getting noise (or garbage) from whatever pin0 is.
EDIT
It is best practice to use parentheses to make order of operations more clear.
ie:
float voltage = reading * 5.0 / 1024;
should be
float voltage = reading * (5.0 / 1024);

First, you have to use the defined symbols A0
int sensorPin = A0;
in the next
float voltage = reading * (5.0 / 1024);
There is an example in File/Examples/Basic/AnalogReadSerial

Related

Arduino, HC SR-04 distance sensor wrong output

my name is Dmitrij and I wanted to connect HC-SR04 to Arduino so that I can measure the distance.
The problem is that the sensor is sending 4-5 right results and then 5-6 wrong ones in a row.
I've tried to replace Arduino and the sensor it didn't help.
At the end while I was writing this I kinda solved the problem.
The sensor was getting 5 Volt from external powersuply module (https://i.imgur.com/Zjg22ka.png) after I connected sensor to Arduino 5V everything was working Fine.
Is there a way to fix this somehow?
int echo = 8;
int trig = 9;
float duration, distance;
void setup() {
pinMode(echo, INPUT);
pinMode(trig, OUTPUT);
digitalWrite(trig, LOW);
Serial.begin (9600);
}
void loop() {
digitalWrite(trig, HIGH);
delayMicroseconds(10);
digitalWrite(trig, LOW);
duration = pulseIn(echo, HIGH);
distance = (duration / 2) * 0.0344;
Serial.print("Distance = ");
Serial.print(distance);
Serial.println(" cm");
delay(500);
}
Thats the output of the sensor when it was directed on the wall.
The real Distance is around 15-16 cm and i don't understand why does it output something else also.
Distance = 15.70 cm
Distance = 15.70 cm
Distance = 15.65 cm
Distance = 15.70 cm
Distance = 3.92 cm
Distance = 2.25 cm
Distance = 1.67 cm
Distance = 0.48 cm
Distance = 0.55 cm
Distance = 6.73 cm
Distance = 15.65 cm
Distance = 15.65 cm
Distance = 15.65 cm
Distance = 15.65 cm
Distance = 4.11 cm
Distance = 2.27 cm
Distance = 1.50 cm
Distance = 0.50 cm
Distance = 0.50 cm
Distance = 6.33 cm
and so on.
It depends on how curvy your scanned surface is, some times it can give you the wrong information, try scanning a flat surface and take a look your output will be.
Can you follow these steps ? I had same problem and I connected trig and echo pin as shown in link and worked.
Don't forget that you have to download NewPing library
If not worked, you should check all the cables.

Opencl size of local memory has impact on speed?

i am new in OpenCL and i am trying to compute histogram of grayscaled image. I am performing this computation on GPU nvidia GT 330M.
code is
__kernel void histogram(__global struct gray * input, __global int * global_hist, __local volatile int * histogram){
int local_offset = get_local_id(0) * 256;
int histogram_global_offset = get_global_id(0) * 256;
int offset = get_global_id(0) * 1920;
int value;
for(unsigned int i = 0; i < 256; i++){
histogram[local_offset + i] = 0;
}
barrier(CLK_LOCAL_MEM_FENCE);
for(unsigned int i = 0; i < 1920; i++){
value = input[offset + i].i;
histogram[local_offset + value]++;
}
barrier(CLK_LOCAL_MEM_FENCE);
for(unsigned int i = 0; i < 256; i++){
global_hist[histogram_global_offset + i] = histogram[local_offset + i];
}
}
This computation is performed on image 1920*1080.
I am firing kernels with
queue.enqueueNDRangeKernel(kernel_histogram, cl::NullRange, cl::NDRange(1080), cl::NDRange(1));
When local size of histogram is set to 256 * sizeof(cl_int) speed of this computation is (through nvidia nsight performance analysis) 11 675 microseconds.
Because local workgroup size is set to one. I tried increase local workgroup size to 8. But when i increase local size of histogram to 256 * 8 * sizeof(cl_int) and compute with local wg size 1. I get 85 177 microseconds.
So when i fire it with 8 kernels per workgroup i dont get speedup from 11ms but from 85ms. So final speed with 8 kernels per worgroup is 13 714 microseconds.
But when i create computation bug, set local_offset to zero and size of local histogram is 256 * sizeof(cl_int) and use 8 kernels per workgroup i get much better time - 3 854 microsec.
Does anybody have some ideas to speed up this computation ?
Thanks!
This answer assumes you want to eventually reduce your histogram all the way down to 256 int values. You call the kernel with as many work groups as you have compute units on your device, and group size should be (as always) a multiple of CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE on the device.
__kernel void histogram(__global struct gray * input, __global int * global_hist){
int group_id = get_group_id(0);
int num_groups = get_num_groups(0);
int local_id = get_local_id(0);
int local_size = get_local_size(0);
volatile __local int histogram[256];
int i;
for(i=local_id; i<256; i+=local_size){
histogram[i] = 0;
}
int rowNum, colNum, value, global_hist_offset
for(rowNum = group_id; rowNum < 1080; rowNum+=num_groups){
for(colNum = local_id; colNum < 1920; colNum += local_size){
value = input[rowNum*1920 + colNum].i;
atomic_inc(histogram[input]);
}
}
barrier(CLK_LOCAL_MEM_FENCE);
global_hist_offset = group_id * 256;
for(i=local_id; i<256; i+=local_size){
global_hist[global_hist_offset + i] = histogram[i];
}
}
Each work group works cooperatively on one row of the image at a time. Then the group moves on to another row, calculated using the num_groups value. This will work well no matter how many groups you have. For example, if you have 7 compute units, group 3 (the forth group) will start on row 3 in the image, and then every 7th row thereafter. Group 3 would compute 153 rows in total, and its final row would be row 1074. Some work groups may compute 1 more row -- groups 0 and 1 in this example.
The same interlacing is done within the work group when looking at the columns of the image. in the colNum loop, the Nth work item starts at column N, and skips ahead by local_size columns. The remainder for this loop shouldn't come in to play as often, because CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE will likely be a factor of 1920. Try all work group sizes from (1..X) * CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE up to the maximum work group size for your device.
One final point about this kernel: the results are not identical to your original kernel. Your global_hist array is 1080 * 256 integers. The one I have needs to be num_groups * 256 integers. This helps if you want a full reduction, because there is much less to add after the kernel executes.

analogread() function in a for loop

I have 6 sensors connected to the pin A0, A1, A2, A3, A4, A5 and I am trying to get readings from each sensor. I have a analogread() function inside of a for loop and it does not work.
If I just trigger the sensor at A0, all other sensors will have the same reading as that one even if they are not triggered. I used a voltage meter to test the voltage of each pin and only got voltage at A0 when the A0 sensor is triggered. So I believe this is a coding problem.
Here is my code:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0~5:
for(int i = 0; i < 6; i++){
int sensorValue0 = analogRead(i);
delay(700);
// Convert the analog reading (which goes from 0 - 1023) to voltage range (0 - 5V);
float voltage0 = sensorValue0 * (5.0 / 1023.0);
// print out the value you read:
Serial.print(voltage0);Serial.print(" i = ");
Serial.print(i);Serial.print(" ; ");
if (i == 5) Serial.println(" ");
}
}
I just set up some voltage dividers, consisting of combination of various R1 and R2=1k and hooked them up to the analog inputs of an Arduino. Using your code, I received the following data (S0 = raw reading, V0 = calculated voltage)
R1 S0 V0
220 841 4.11
470 695 3.40
1k 511 2.50
2k2 318 1.55
4k7 179 0.87
6k8 128 0.63
This looks fine. Your code is correct. There's definitely something wrong with your wiring.

Arduino and RC Transmitter

I am new to Arduino and to this forum and this is my first Arduino project besides the tutorials.
I am trying to control a servo using a rc transmitter/receiver and the Arudino. The reason why I am using a Arduino instead of connecting the servo directly to the RC receiver is that the RC can only generate a PWM of 1000µs to 2000µs while I need a PWM of 600µs to 2400µs to get the full range of motion of my servo. What I have tried to do is to read the value from pulseIn(), then mapping this value to 0 to 180 degree as written in code below (which utilizes servo library).
However, with this code, the motor behaviour is weird. As I move the radio transmitter control stick through its range of motion, the motor rotates from 0 to 45 degrees, back from 45 to 0, 0 to 45, and back to 0 again instead of sweeping from 0 to 180 degrees. Could anyone please offer some help or advice?
Thank you very much
#include <Servo.h>
Servo myservo;
int ch1;
int ch2;
int ch3;
int degree;
void setup() {
pinMode(7, INPUT);
myservo.attach(9);
Serial.begin(9600);
}
void loop() {
ch3 = pulseIn(7, HIGH, 25000);
degree = ((ch3-1250)* 180)/700;
Serial.print("Channel 3:");
Serial.println(ch3);
myservo.write(degree);
delay(5); // waits 5ms for the servo to reach the position
}
You are overflowing the int data type. The signed value can only be -32768 to +32767. See int docs
Your formula is all int's and the compiler will not guess that you might need a larger intermediate value. The multiply by 180 is a red flag. (2000-1250)*180 = 135000 = boom
To understand the math, break down a formula into the individual operations as shown in the test program below. That is essentially what the compiler is doing for you.
Run the program below and you will see the failure. Just after the out value reaches 45, the intermediate value overflows and the formula breaks down.
in: 1040 out: 39 t0: -210 t1: 27736 t2: 39
in: 1048 out: 41 t0: -202 t1: 29176 t2: 41
in: 1056 out: 43 t0: -194 t1: 30616 t2: 43
in: 1064 out: 45 t0: -186 t1: 32056 t2: 45
in: 1072 out: -45 t0: -178 t1: -32040 t2: -45
in: 1080 out: -43 t0: -170 t1: -30600 t2: -43
Use this program below as a test fixture. Modify the data types to use unsigned int and you will be able to make the output behave as you need.
int ch3;
int degree;
void setup() {
ch3 = 1000;
Serial.begin(9600);
}
void loop() {
int t0, t1, t2;
degree = ((ch3-1250)* 180)/700;
t0 = ch3 - 1250;
t1 = t0 * 180;
t2 = t1 / 700;
Serial.print("in: ");
Serial.print(ch3);
Serial.print(" out: ");
Serial.print(degree);
Serial.print(" t0: ");
Serial.print(t0);
Serial.print(" t1: ");
Serial.print(t1);
Serial.print(" t2: ");
Serial.println(t2);
ch3 += 8;
if(ch3 > 2400) {
ch3 = 1000;
}
delay(100);
}
As a note, you may have more Arduino/servo luck on https://robotics.stackexchange.com/.
What are you seeing on the serial output? Is ch3 cycling from 0 to 45 or from 0 to 180? Don't forget that map() is designed to do what you're doing by hand here.
My first suspicion is that you're occasionally getting 0 back from pulseIn either because you're timing out, or you're starting your reading in the middle of a pulse (which could lead to a shorter pulse than you expect).

How to make ARGB transparency using bitwise operators

I need to make transparency, having 2 pixels:
pixel1: {A, R, G, B} - foreground pixel
pixel2: {A, R, G, B} - background pixel
A,R,G,B are Byte values
each color is represented by byte value
now I'm calculating transparency as:
newR = pixel2_R * alpha / 255 + pixel1_R * (255 - alpha) / 255
newG = pixel2_G * alpha / 255 + pixel1_G * (255 - alpha) / 255
newB = pixel2_B * alpha / 255 + pixel1_B * (255 - alpha) / 255
but it is too slow
I need to do it with bitwise operators (AND,OR,XOR, NEGATION, BIT MOVE)
I want to do it on Windows Phone 7 XNA
---attached C# code---
public static uint GetPixelForOpacity(uint reduceOpacityLevel, uint pixelBackground, uint pixelForeground, uint pixelCanvasAlpha)
{
byte surfaceR = (byte)((pixelForeground & 0x00FF0000) >> 16);
byte surfaceG = (byte)((pixelForeground & 0x0000FF00) >> 8);
byte surfaceB = (byte)((pixelForeground & 0x000000FF));
byte sourceR = (byte)((pixelBackground & 0x00FF0000) >> 16);
byte sourceG = (byte)((pixelBackground & 0x0000FF00) >> 8);
byte sourceB = (byte)((pixelBackground & 0x000000FF));
uint newR = sourceR * pixelCanvasAlpha / 256 + surfaceR * (255 - pixelCanvasAlpha) / 256;
uint newG = sourceG * pixelCanvasAlpha / 256 + surfaceG * (255 - pixelCanvasAlpha) / 256;
uint newB = sourceB * pixelCanvasAlpha / 256 + surfaceB * (255 - pixelCanvasAlpha) / 256;
return (uint)255 << 24 | newR << 16 | newG << 8 | newB;
}
You can't do an 8 bit alpha blend using only bitwise operations, unless you basically re-invent multiplication with basic ops (8 shift-adds).
You can do two methods as mentioned in other answers: use 256 instead of 255, or use a lookup table. Both have issues, but you can mitigate them. It really depends on what architecture you're doing this on: the relative speed of multiply, divide, shift, add and memory loads. In any case:
Lookup table: a trivial 256x256 lookup table is 64KB. This will thrash your data cache and end up being very slow. I wouldn't recommend it unless your CPU has an abysmally slow multiplier, but does have low latency RAM. You can improve performance by throwing away some alpha bits, e.g A>>3, resulting in 32x256=8KB of lookup, which has a better chance of fitting in cache.
Use 256 instead of 255: the idea being divide by 256 is just a shift right by 8. This will be slightly off and tend to round down, darkening the image slightly, e.g if R=255, A=255 then (R*A)/256 = 254. You can cheat a little and do this: (R*A+R+A)/256 or just (R*A+R)/256 or (R*A+A)/256 = 255. Or, scale A to 0..256 first, e.g: A = (256*A)/255. That's just one expensive divide-by-255 instead of 6. Then, (R*A)/256 = 255.
I don't think it can be done with the same precision using only those operators. Your best bet is, I reckon, using a LUT (as long as the LUT can fit in the CPU cache, otherwise it might even be slower)
// allocate the LUT (64KB)
unsigned char lut[256*256] __cacheline_aligned; // __cacheline_aligned is a GCC-ism
// macro to access the LUT
#define LUT(pixel, alpha) (lut[(alpha)*256+(pixel)])
// precompute the LUT
for (int alpha_value=0; alpha_value<256; alpha_value++) {
for (int pixel_value=0; pixel_value<256; pixel_value++) {
LUT(pixel_value, alpha_value) = (unsigned char)((double)(pixel_value) * (double)(alpha_value) / 255.0));
}
}
// in the loop
unsigned char ialpha = 255-alpha;
newR = LUT(pixel2_R, alpha) + LUT(pixel1_R, ialpha);
newG = LUT(pixel2_G, alpha) + LUT(pixel1_G, ialpha);
newB = LUT(pixel2_B, alpha) + LUT(pixel1_B, ialpha);
otherwise you should try vectorizing your code. But to do that you should at least provide us with more info on your CPU architecture and compiler. Keep in mind that your compiler might be able to vectorize automatically, if provided with the right options.

Resources