2009-05-18

Sketch to calibrate SEN-08663

Got my hands on a ADJD-S371 on a breakout board from Sparkfun. The code below can be used to calibrate it. The most up-to-date version of the code can be found at my git repository under colour_sensor_calibration.




#include <Wire.h>
/* Calibrates the sensor to get white balance. Pin 2 should be connected
* to LED on the breakout board's LED pin. Calibration is done by placing the
* breakout board inside a pin pong ball, and using the built-in LED for
* illumination.
*
* Amount of light is measured by charging N capacitors for time X then
* reading off the voltage. (Conjecture)
*
* N is controlled by CAP_XXX
* T is controlled by INT_XXX
*
* Calibration is done by adjusting the integration time. No real reason.
*/
int _slave_id = 0x74;
int _LED_pin = 2;

uint8_t read_register(uint8_t addr)
{
i2c_send(_slave_id, &addr, 1);
return i2c_read(_slave_id);
}

void write_register_int(uint8_t addr, int data)
{
write_register_multibyte(addr, (uint8_t*)&data, 2);
}

/* write data[i] = register+i */
void write_register_multibyte(uint8_t addr, uint8_t* data, uint8_t bytes)
{
for (int i = 0; i < bytes; ++i)
{
write_register(addr+i, data[i]);
}
}

void write_register(uint8_t addr, uint8_t data)
{
uint8_t bytes[] = {addr, data};
i2c_send(_slave_id, bytes, 2);
}

uint8_t i2c_read(uint8_t id)
{
Wire.requestFrom(_slave_id, 1);
for(int i = 0; i<10 && !Wire.available(); ++i, delay(10));
if (!Wire.available())
{
return 11;
}
return Wire.receive();

}

void i2c_send(uint8_t id, uint8_t * data, uint8_t len)
{
Wire.beginTransmission(id);
for(int i = 0; i < len; ++i)
{
Wire.send(data[i]);
}
Wire.endTransmission();
}

#define CTRL 0x00
#define CONFIG 0x01

#define CAP_RED 0x06
#define CAP_GREEN 0x07
#define CAP_BLUE 0x08

#define INT_RED_LO 0x0A
#define INT_RED_HI 0x0B
#define INT_GREEN_LO 0x0C
#define INT_GREEN_HI 0x0D
#define INT_BLUE_LO 0x0E
#define INT_BLUE_HI 0x0F

#define DATA_RED_LO 0x40
#define DATA_RED_HI 0x41
#define DATA_GREEN_LO 0x42
#define DATA_GREEN_HI 0x43
#define DATA_BLUE_LO 0x44
#define DATA_BLUE_HI 0x45

int read_colour(uint8_t low_addr)
{
int lo = read_register(low_addr);
int hi = read_register(low_addr+1);

return lo|(hi<<8);
}

int red_integration_time = 2048;
int green_integration_time = 2048;
int blue_integration_time = 2048;

void set_integration_times(int red, int green, int blue)
{
write_register_int(INT_RED_LO, red);
write_register_int(INT_GREEN_LO, green);
write_register_int(INT_BLUE_LO, blue);
}

void setup()
{
pinMode(_LED_pin, OUTPUT);
digitalWrite(_LED_pin, HIGH);

Serial.begin(57600);
Wire.begin(); // join i2c bus (address optional for master)
Serial.println("Setting up...");

// datasheet says, wait 10us for hardware reset, so lets wait 1000
delay(1);

// gain setup
write_register(CAP_RED, 0x08);
write_register(CAP_GREEN, 0x08);
write_register(CAP_BLUE, 0x08);

set_integration_times(
red_integration_time,
green_integration_time,
blue_integration_time
);

// ask for colour data and offset
write_register(CTRL, 0x01);
}

void loop()
{
if (read_register(CTRL))
{
return;
}

int red, green, blue;
red = read_colour(DATA_RED_LO);
green = read_colour(DATA_GREEN_LO);
blue = read_colour(DATA_BLUE_LO);

Serial.println("--------------");
Serial.print("red: ");Serial.println(red);
Serial.print("green: ");Serial.println(green);
Serial.print("blue: ");Serial.println(blue);


Serial.print("red_int: ");Serial.println(red_integration_time);
Serial.print("green_int: ");Serial.println(green_integration_time);
Serial.print("blue_int: ");Serial.println(blue_integration_time);

// have to calibrate against blue, because LED has a blue bias otherwise
// it would look like blue has high gain than it does
float P = 1;
int reference = blue;
red_integration_time += (reference - red)*P;
green_integration_time += (reference - green)*P;
blue_integration_time += (reference - blue)*P;

// set the new integration times
set_integration_times(
red_integration_time,
green_integration_time,
blue_integration_time
);

// ask for colour data again
write_register(CTRL, 0x01);
}


Cheers,

Steve

2009-05-08

Facebook python authentication gateway

Edit: it occurred to me what I have below is the basics of a thin facebook api wrapper. I might make it into one at some point in the future.



If you don't know what this does, you don't need it. Hope this helps some one. Written because pyfacebook is broken, always returns error 100.




FB_API_HOST="api.facebook.com"
FB_API_PATH="/restserver.php"

def get_session(auth_token):
params={
"api_key":FB_API_KEY,
"v":"1.0",
"auth_token":auth_token,
"generate_session_secret":1,
"method":"auth.getSession",
}

sorted = params.items()
sorted.sort(key=lambda x:x[0])

str_to_hash = ''.join(["%s=%s"%(x[0], x[1]) for x in sorted])
str_to_hash += FB_API_SECRET

md5 = hashlib.md5()
md5.update(str_to_hash)

sig = md5.hexdigest()

params["sig"] = sig

encoded_params = urllib.urlencode(params)
headers = {
"Content-type":"application/x-www-form-urlencoded",
}

conn = httplib.HTTPConnection(FB_API_HOST)
conn.request("POST", FB_API_PATH, encoded_params, headers)

response = conn.getresponse()

print response.status, response.reason
return response.read()


This Works For Me when I use it with iphone facebook-connect client:



[FBSession sessionForApplication:myApiKey getSessionProxy:myURL delegate:self];


Cheers,

Steve

2009-04-29

Stripping trailing whitespace from XCode




Firstly, my usual approach of s/\s+$//g doesn't work since it eats up the newline too. s/\s+$/\n/g doesn't work either because the Replace: field in the find dialogue doesn't escape the \n.



Final solution is as shown: s/[ \t]+$//g




Cheers,

Steve

2009-04-06

Family Planning

YLDE comic: half as funny half as often.



because imitation is the best form of flattery.


title="and the product of their age will be my private key"/>



Cheers,

Steve

2009-02-16

Futurlec Ultrasonic Sensor Note

Part number US1440, these sensors are not dual use, which means the transmitter and receiver is not exchangeable. They also look identical from the outside, so if you build my arduino ultrasound ranger with these (as I did) and find you can't see echoes, try swapping your transmitter and receiver around! It cost me no small amount of headach this morning.



Cheers,

Steve

Arduino ultrasound ranger



Code to drive it is avaliable under GPL.



An updated version of the schematic as a .sch file is available also.




Cheers,

Steve

2009-02-13

The libertarian argument against vaccination

Goes like this:



I have a right to decide what happens to my children!


To that I say, we have the right to not be a victim of your stupidity. Further, laws represent social contracts that all members of society enter into for everyone's benefit. Getting vaccinated is one such contract which serves to prevent epidemics of infectious diseases.



If you really don't want to vaccinate your child, then please ensure your child never comes into physical contact with the rest of society for our sake. I would not welcome them without vaccinations.



Cheers,

Steve

2009-02-06

MATHS FAIL


What is the period if you want to generate a 40KHz signal? It certainly isn't 250E-6 seconds. The same calculator returns 2500E-3 for 1/4 which is 2.5, not 0.25.



The calculator is PEMDAS.



Cheers,

Steve

2009-01-25

Auto leveller



A simple 2 DoF setup with an accelerometer (LIS302DL) attached to the effector. The seeeduino attempts to drive the servos so the Z and Y axis measure zero acceleration. The sketch is available at the usual place.

The algorithm employed is a simple PD controller with pseduo-gradient stepping to determine how to control each servo without any knowledge of how the servos are arranged. To deal with sensor noise from the accelerometer, a schmitt trigger mechanism is employed along with a moving average.



The code also allows the system to be calibrated to deal with accelerometer miscalibration.



It is cute, but that is about it :-) Coupled with a tripod and better construction ut might be useful for some DIY surveying or construction work.



Cheers,

Steve

2009-01-13

Turn a servo into 1-wire-control bi-directional motor



It is often a pain building H-bridges or getting a motor shield just because you want to control a few motors. This is where servos come in: they are cheap(ish), have motor and gearbox, and they are controlled ysing only a single wire.



The only problem is of course, servos aren't designed for continuous motion. Servos are designed to respond to PWM pulses which encode the desired position for the servo to be in, not a desired speed or direction. So some modification is required.



Now there are many articles on the intertubes on how to do this, but they mostly concern themselves with making the servo into little more than a normal motor with a gearbox - you still need a H-bridge to control the direction. This modification is a little different: it leaves you with a servo that behaves like a bi-directional motor where the direction is controlled by a single wire.



Due to the variety of servos out there, I will present only the general idea, which applies to servos which use a potentiometer to determine position.



Firstly, a quick explanation of how these servos work. The principle behind these servos is that the potentiometer is connected to the output gear such that the voltage of the sweeper (connected to the middle pin usually) depends on the angular position of the output gear. The onboard controller converts the input PWM signal into a target voltage, then it powers the motor so it turns the output gear until the voltage of the sweeper matches the target voltage. This is kind of control action is relatively easy to achieve using an operational amplifier.



The basis of the modification is essentially this: if we fix the sweeper voltage, then any input asking the servo to move away from the sweeper voltage will result in the onboard controller continuously attempt to match sweeper voltage to target voltage. By making the target voltage higher or lower than the sweeper voltage, we get directional control.



To fix the sweeper voltage, the potentiometer will need to be disconnected and replaced with a voltage divider. I assume that when the output gear is in centre position, sweeper voltage is half the supplied power because the potentiometer will be in its centre position. Since I wanted 0 degree rotation to map to stop, I fixed the sweeper voltage at this value by using 2x1.5K resistors in series. This is all you need to do electronically. There should be enough room to fit in 2 extra resistors, even in small 8g servos (what I had).



The last thing to do is to remove any physical obstructions which prevent the output gear from completing a full revolution.



Once the electronic and physical modifications are complete, you should have a servo which can turn in either direction continuously and controlled via single wire. Two of these would be perfect for say powering a small rover...




Cheers,

Steve

2009-01-04

Tips for interfacing a electret mic with an arduino


  1. The arduino ADC is 10bit, which means the range is 0-1023 and this is mapped to 0-5V most of the time, unless you do funky things to AREF.

  2. Most amplifier circuits on the net (using op-amps or LM386s) will have a DC bias of 2.5V, this is to allow the output to swing both ways. So on the arduino side even with complete silence you will read a value ~512 or so.

  3. The resistor connecting the electret mic and power also adjust the sensitivity of the microphone in addition to providing power to the mic (which includes an internal pre-amp, by the way). This resistor is very important - if you find your microphone isn't responsive enough, then adjust this resistor first before debugging your amplifier circuit. For me this "fixed" my microphone's responsiveness. It is best of this was a variable resistor which makes adjustment trivial.

  4. I was making a simple volume meter, and I did the following: clamp upper values to about 600, then using map map this to a range between 0-7 (since I had 8 LEDs). This was because I found the value never went above 600 very often, so the upper few LEDs were essentially going to waste sitting around. YMMV.




Cheers,

Steve