20091231

Reality Blows: Strange LCD Problem and Strange Solution.

I spent the better part of two hours struggling with your average HD44780 driven 16x2 character LCD, even though I was using the LiquidCrystal library that comes with the arduino environment. My problem was the text I was printing out looks like this:


I tried a lot of things, like adding in delays here and there, even going so far as to use a subclass of LiquidCrystal which inserts a 2ms delay after each write to no avail. Then by a process of elimination, I found that if I reverse the order in which the lines were printed, i.e. print line 1 then line 0, the problem goes away:


Whiskey Tango Foxtrot.

Cheers,
Steve

Labels: , , ,


20091222

Latching Power Supply With Electronic Turn Off

This circuit has (as far as I can tell), 0 off current, and 17mA on current. It is latched by the momentary push button, and can be turned off by applying >0.7V at the input as shown. It is intended for use with embedded interactive installation (e.g. an arduino) where the user pushes the button to turn the device on, and the device will turn itself off after some time to conserve battery.

It is a modified version of this circuit.

Cheers,
Steve

Labels: ,


20091216

Yet Another Arduino Float Print Function

void floatPrint(float f, int places=6)
{
        int _d;
        if (f < 0)
        {
                Serial.print("-");
                f*=-1;
        }

        _d = (int)f;
        
        if (!places)
        {
                return;
        }

        Serial.print(_d, DEC);
        Serial.print('.');

        while(places--)
        {
                f-=_d;
                f*=10;
                _d = (int)f;
                Serial.print(_d, DEC);
        }
}

void floatPrintln(double f, int places=6)
{
        floatPrint(f, places);
        Serial.println();
}

Why another float print function? The ones I found wasn't too nice, one of which required long integers. Yuck. It was also fun, and now I know where to look for one in the future :P

Cheers,
Steve

Labels: ,


20090604

microbric viper review

The microbric viper is neat. Good quality parts and unique idea. Makes a decent robotics platform if you get the wheel add-on. However, you gotta have small fingers to get some of the parts in place. Despite this, the hardware is solid, I like it. The one thing I would ask for however is more short-nuts and a printed manual, not a CDROM with a PDF. Take a leaf from LEGO and their construction manuals.

While the hardware is decent, the microbric viper is sadly let down by the software.

The microbric viper uses the basicAtom (by basicmicro), a PIC 16F87{6,7} with a custom bootloader. Now there is nothing wrong with this - arduino uses a custom bootloader too. However the custom bootloader uses a proprietary programming protocol. This is pretty fail, but what really fails is the programming software only runs under windows (or wine under ubuntu, but only for now).

IMHO the basic-esque language used by basicAtom is no better than what picaxe offers. I am completely at a lost as to why companies would use the basicmicro's products and lock themselves to a single supplier. Think about it: if basicmicro goes bust, your products using the basicAtom will not longer have a supported development environment.

Robotics companies need to seriously consider how their selection of controller will affect their customers - specifically those customers who aren't going to be running windows and staying with in the limits of whatever custom language designed by the controller vendors.

Arduino would be the best choice IMHO. Open hardware, open software. You don't have to pay premiums for the bootloader, and the number of people who will consider your product increases to include people like me.

I bought the microbric viper because it was on sale: reduced to $29 from $199. If I had known I could only program it under windows or that it used such a closed platform, I won't have bought it, even for that price.

Cheers,
Steve

Labels: , , , ,


20090518

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

Labels: , ,


20090216

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

Labels: , , ,


20090125

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

Labels: , , ,


20090104

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

Labels: ,


20081212

2x16 character LCD displays

2x16 character LCD displays can be tricky beasts. I got mine working today with my seeeduino (an arduino compatible board with more awesome), and really wished I had known that:

  1. The contrast pin needs to be in the same power network as the power and ground pins. The contrast pin at 0v provides highest contrast, which means you can probably just ground it normally.
  2. The timing between LCD driver power up and commencement of device programming appears to be important. I had the LCD power independently, and this gave me garbage on screen. When the LCD shared the same power supply as the seeeduino everything worked perfectly.

Cheers,
Steve

Labels: , ,


This page is powered by Blogger. Isn't yours?