-
Pan Tilt Servo Control
03/26/2017 at 16:08 • 0 commentsThe gimbal was pretty quick to assemble, though the order of connections was critical and I found I had to take it apart and reassemble a couple times before finishing.
Connecting the servos to an Arduino requires some changes to the wiring. The critical thing is to power the servos with an external source, if you don't the Arduino will brown out when trying to move both simultaneously. I used a 6V external power supply so the servos wouldn't be powered through the USB port.
The pan and tilt motion resulted in a way wider angle than I needed. This could be useful when the thermometer needs to be placed close to the target, but lots more math would be required to account for the angle of motion. From a distance the angular motion can be translated linearly without much distortion.
I considered modifying the servos in some way, probably not gearing but maybe the resistance values of the potentiometers inside so the feedback loop would limit the rotation to a more narrow range. I needed higher torque on another project and used these external servo gearboxes from servo city, those could work but would make the gimbal much larger and more complex.
But, luckily I discovered that servos can be controlled from an Arduino with Microseconds instead of angular measurements. Even at the small angles I wanted the servos to move, microsecond signals allow for 500+ steps of movement. This is possible in the standard library, but I ultimately elected to use the alternate VarSpeed library so I could set acceleration speeds when needed.
This is the code I used to test drawing a frame around the area to be scanned, as a preview before beginning the scan.
// Michael Shaub 1/18/2017 // Based on Sweep by BARRAGAN #include <Servo.h> Servo myservoTilt; // create servo object to control a servo Servo myservoPan; // create servo object to control a servo // a maximum of eight servo objects can be created int posTilt = 1500; // variable to store the servo position int posPan = 1500; // variable to store the servo position int tiltLimitUpper = 1350; //2000; int tiltLimitLower = 950; //500; int panLimitUpper = 1750; //2300; int panLimitLower = 1350; //700; boolean countDown = true; int frameCase = 0; //state of the frame sequence //0=Upper Left Corner, 1=Upper Right Corner //2=Lower Right Corner, 3=Lower Left Corner void setup() { myservoTilt.attach(9, tiltLimitLower, tiltLimitUpper); // attaches the servo on pin 9 to the servo object myservoPan.attach(10, panLimitLower, panLimitUpper); // attaches the servo on pin 9 to the servo object } void loop() { frame(); delayMicroseconds(500); } void frame(){ switch(frameCase){ case 1: //Upper Right Corner if(posTilt<=tiltLimitLower){ frameCase=2; delay(5); }else{ posTilt--; myservoTilt.writeMicroseconds(posTilt); // tell servo to go to position in variable 'posTilt' } break; case 2: //Lower Right Corner if(posPan<=panLimitLower){ frameCase=3; delay(5); }else{ posPan--; myservoPan.writeMicroseconds(posPan); // tell servo to go to position in variable 'posPan' } break; case 3: //Lower Left Corner if(posTilt>=tiltLimitUpper){ frameCase=0; delay(5); }else{ posTilt++; myservoTilt.writeMicroseconds(posTilt); // tell servo to go to position in variable 'posTilt' } break; default: //Upper Left Corner if(posPan>=panLimitUpper){ frameCase=1; delay(5); }else{ posPan++; myservoPan.writeMicroseconds(posPan); // tell servo to go to position in variable 'posPan' } break; } }
-
Reading the thermometer with an Arduino
03/26/2017 at 15:00 • 0 commentsAccording to this Instructable the thermometer's pins should connect to an Arduino like this:
- pin D (IR data) to pin 12
- pin C (IR clock) to pin 2
- pin V (IR power) to 3.3V power
- pin G (IR ground) to ground
Here's the sample code I tried first to get some measurements streaming in:
byte n = 0; // Interrupt Bit Count volatile byte pos = 0; // Values Position Count volatile byte values[5] = { 0,0,0,0,0}; // Values to be stored by sensor byte cbit = 0; // Current bit read in boolean irFlag = false; // Flag to indicate IR reading has been made boolean ambFlag = false; // Flag to indicate ambient temp reading has been made byte irValues[5] = { 0,0,0,0,0}; // Variable to store IR readings byte ambValues[5] = { 0,0,0,0,0}; // Variable to store Ambient readings const int len = 5; // Length of values array const int clkPin = 2; // Pins const int dataPin = 12; const int actionPin = 5; void setup(){ Serial.begin(9600); pinMode(clkPin, INPUT); // Initialize pins pinMode(dataPin, INPUT); pinMode(actionPin, OUTPUT); digitalWrite(clkPin, HIGH); digitalWrite(dataPin, HIGH); digitalWrite(actionPin, HIGH); Serial.println("Type to Start..."); // Wait for input to start while(!Serial.available()); Serial.println("Starting..."); Serial.println("IR (C), Ambient (C), Time Since Start (ms)"); attachInterrupt(1,tn9Data,FALLING); // Interrupt digitalWrite(actionPin,LOW); // Make sensor start sending data } void loop(){ if(pos == len && values[0] == 0x4C){ // If sensor has sent IR packet... for(int i = 0; i < len; i++){ // Store values to irValues irValues[i] = values[i]; } irFlag = true; // Indicate IR reading pos = 0; digitalWrite(actionPin,LOW); // Make sensor start sending data } if(pos == len && values[0] == 0x66){ // If sensor has sent ambient packet... for(int i = 0; i < len; i++){ // Store values to ambValues ambValues[i] = values[i]; } ambFlag = true; // Indicate Ambient reading pos = 0; digitalWrite(actionPin,LOW); // Make sensor start sending data } if(pos == len && values[0] == 0x53){ // If sensor has sent junk packet pos = 0; digitalWrite(actionPin,LOW); // Make sensor start sending data } if(irFlag && ambFlag){ // If successful IR and Ambient reading... digitalWrite(actionPin,HIGH); // Make sensor stop sending data. Because Timing is weird, I want to ensure the interrupts do not happen during this section. word tempword = 0; // Next 4 lines isolate temperature component of values tempword = tempword | irValues[1]; tempword = tempword << 8; tempword = tempword | irValues[2]; if(tn9Check(irValues)){ // If checksum is valid, print IR temperature //Serial.print("IR = "); Serial.print(int(tempword)/16.0 - 273.15); Serial.print(", "); } else{ // If checksum isn't valid, print impossible temp //Serial.print("IR = "); Serial.print("-273.15, "); } tempword = 0; // Isolate temperature component again for ambient tempword = tempword | ambValues[1]; tempword = tempword << 8; tempword = tempword | ambValues[2]; if(tn9Check(ambValues)){ // If checksum is valid, print ambient temperature //Serial.print("Amb = "); Serial.print(int(tempword)/16.0 - 273.15); } else{ // If checksum isn't valid, print impossible temp //Serial.print("Amb = "); Serial.print("-273.15"); } irFlag = false; // Reset flags ambFlag = false; Serial.print(", "); Serial.println(millis()); // Print time for logging purposes delay(2000); // Simulate other sensors or code digitalWrite(actionPin,LOW); // Make sensor start sending data } } void tn9Data(){ // Interrupt Function cbit = digitalRead(dataPin); // Read bit if(pos >= len) pos = 0; // Keep index below 5 values[pos] = (values[pos] << 1) | cbit; // Store to values n++; // Increment bit count if(n == 8){ // Increment position count based on bits read in pos++; n = 0; } if(pos == len){ // If complete "packet" sent, stop sensor from sending digitalWrite(actionPin,HIGH); // again until main loop allows it. } } boolean tn9Check(byte tn9Values[]){ // Checksum calculating function int mcheck = (int)tn9Values[0] + (int)tn9Values[1] + (int)tn9Values[2]; // Checksum calculation int scheck = (int)tn9Values[3]; // Checksum sent by sensor boolean crc = false; // Initialize return value if(mcheck > 510) mcheck = mcheck - 512; // Handle sensor byte rollover if(mcheck > 255) mcheck = mcheck - 256; // Handle sensor byte rollover if(mcheck == scheck) crc = true; // Check checksum return(crc); // Return }
-
Modification of Infrared Thermometer
03/26/2017 at 14:47 • 0 commentsLuckily, the thermometer's circuit board has an unpopulated header that's ready for hacking. I wanted to keep my setup flexible so I used an old cable with the right number of wires and soldered a set of header pins onto the board. By making a hole in the thermometer case the cable can be removed anytime.
According to this Instructable the pin out is:- pin D: IR data
- pin C: IR clock
- pin V: IR power (3.3V), and laser pointer power can be connected here too
- pin G: IR ground
(photos to come)