Archive

Archive for February, 2012

The Arduino Dalek Master Plan – Episode 2

February 24th, 2012 No comments

Looking back on my grand ideas, I’ve decided on a bit of a change of plan.

The current scheme will not have ports for video, or extraneous USB holes for keyboards and things of that ilk.

The current list of ports to stick on the Dalek is:

  • Ethernet – as i think I’ll need it in case the wifi fails
  • USB (using the already fitted port) for power while testing

The Raspberry will need USB for these:

  • Connection to the Arduino
  • Connection to the webcam (unless i can get a camera that uses the on-board connection)
  • Some form of microphone

So it still looks like I’ll need an unpowered hub.

It will also need a speaker connection for whatever sound output I decide to use.

Also, at some point i intend to get the ear lights working again.

 

Evolution of the Arduino Dalek

February 24th, 2012 No comments

The DIY Arduino Shield Kit arrived from Amazon, and has been soldered up.

And it looks really boring, without the other parts stuck on it.

The parts in question are four 5v DPDT relays (Maplin part no N05AW – which seem to be out of stock a lot of the time, but are better that the alternative BT Type 47s, as the coil isn’t fussy about the polarity of the voltage), four 1N4004S diodes (part no QL78H), and a mess of wires. Rather than try to describe the layout, I’ve drawn a really bad diagram.

Click for bigger

Click for bigger

This is the view from the component side. The yellow boxes show the relay placements, the four vertical block are the connections to the arduino. The Cyan areas are connections on the other side of the board, either whopping great solder blobs or lines joining the pads drawn with a pcb pen. The other technicolour lines are various wires.

Although that diagram gives the impression that I’ve used a double sided board, I haven’t. In retrospect that would have made things a lot easier.

Another collosal lack of planning (ie putting the Arduino header blocks too close to the top of the board) means that the Massively Ugly Blob Of Solder at the top sits directly over the ICSP header on the Arduino Duemilanove that I’m using, requiring a bit of electrical tape to stop it shorting.

Here is what it looks like now, shitty soldering included for free:

Maybe you’ve spotted some things that aren’t on the diagram. Such as the 2 pin header, the two 3 pin headers and and 4 pin header. Well, the 2 pin is for the motor power input, and the 4 pin one is for the motor driver outputs. They were an afterthought, as were the two 3 pin headers which are for the distance sensors input, and are currently not connected. That bit comes next.

Protocol of the Arduino Dalek

February 9th, 2012 No comments

Ok, so now I’m just making Doctor Who episode titles up…

Anyway, while eagerly awaiting the release of the Raspberry Pi, which should be available within a month, I’ve been playing about with the communication method twixt Raspberry and Arduino.

As the ‘berry will be running Debian Linux, my Ubuntu server had been used as the test host, despite it being far too massive and heavy to be carried by the Dalek. I have a very long USB cable for such eventualities.

The plan has come down to initially sending single character commands to the Arduino over the serial port, and listening for a response. The responses will be a 5 character code with optional additional data.

The single character commands, their actions and return messages are:

Command Action Response
q Move forward and left MOVSF Ok
w Move forward MOVFF Ok
e Move forward and right MOVFS Ok
a Spin left MOVBF Ok
s Stop MOVSS Ok
d Spin right MOVFB Ok
z Move back and left MOVBS Ok
x Move back MOVBB Ok
c Move back and rigt MOVSB Ok
h Return last movement order MOTOR {motor status} Ok
v Return version number VERSN {version number}
l Get distance from left sensor DISTL {distance in cm}
r Get distance from right sensor DISTR {distance in cm}
Unknown command UNKNW

So, here is the Arduino Sketch for this protocol:

// Project: Dalek control system – Receive and process commands from USB
// Version 1.0 (2012-02-09-09-06)
// Tony Blews tony@tonyblews.co.uk

int MotorDirectionR = 10;
int MotorDirectionL = 11;
int MotorPowerR     = 12;
int MotorPowerL     = 13;
int IRPinLeft       = 2;
int IPPinRight      = 3;
String motorStatus    = String (“”);

void setup()
{
pinMode(MotorDirectionR, OUTPUT);
pinMode(MotorDirectionL, OUTPUT);
pinMode(MotorPowerR, OUTPUT);
pinMode(MotorPowerL, OUTPUT);
motorStatus= String(“MOVSS”);
Serial.begin(9600);
Serial.println(“START Serial control Dalek system starting…”);
}

void check_distance(int IRpin) {
float volts = analogRead(IRpin)*0.0048828125;   // value from sensor * (5/1024) – if running 3.3.volts then change 5 to 3.3
float distance = 30*pow(volts, -1.10);          // worked out from graph 65 = theretical distance / (1/Volts)S – luckylarry.co.uk
Serial.println(distance);                       // print the distance
delay(100);                                     // arbitary wait time.
}

// modes for the motor control
// convention here is modeXX – where X is F for forward, S for stationary and B for backwards
// first X is the left motor, second X is the right one
// for direction control, the LOW if forward and HIGH is backward
// for power control, LOW is off and HIGH is on

// all stop
void modeSS()
{
digitalWrite(MotorDirectionR, LOW);
digitalWrite(MotorDirectionL, LOW);
digitalWrite(MotorPowerR,LOW);
digitalWrite(MotorPowerL,LOW);
motorStatus= String(“MOVSS Ok”);
Serial.println(motorStatus);
}

// move straight ahead
void modeFF()
{
digitalWrite(MotorDirectionR, LOW);
digitalWrite(MotorDirectionL, LOW);
digitalWrite(MotorPowerR,HIGH);
digitalWrite(MotorPowerL,HIGH);
motorStatus= String(“MOVFF Ok”);
Serial.println(motorStatus);
}

// move straight backwards
void modeBB()
{
digitalWrite(MotorDirectionR, HIGH);
digitalWrite(MotorDirectionL, HIGH);
digitalWrite(MotorPowerR,HIGH);
digitalWrite(MotorPowerL,HIGH);
motorStatus= String(“MOVBB Ok”);
Serial.println(motorStatus);
}

// spin left
void modeBF()
{
digitalWrite(MotorDirectionR, LOW);
digitalWrite(MotorDirectionL, HIGH);
digitalWrite(MotorPowerR,HIGH);
digitalWrite(MotorPowerL,HIGH);
motorStatus= String(“MOVBF Ok”);
Serial.println(motorStatus);
}

//spin right
void modeFB()
{
digitalWrite(MotorDirectionR, HIGH);
digitalWrite(MotorDirectionL, LOW);
digitalWrite(MotorPowerR,HIGH);
digitalWrite(MotorPowerL,HIGH);
motorStatus= String(“MOVFB Ok”);
Serial.println(motorStatus);
}

// move forward left
void modeSF()
{
digitalWrite(MotorDirectionR, LOW);
digitalWrite(MotorDirectionL, LOW);
digitalWrite(MotorPowerR,HIGH);
digitalWrite(MotorPowerL,LOW);
motorStatus= String(“MOVSF Ok”);
Serial.println(motorStatus);
}

// move forward right
void modeFS()
{
digitalWrite(MotorDirectionR, LOW);
digitalWrite(MotorDirectionL, LOW);
digitalWrite(MotorPowerR,LOW);
digitalWrite(MotorPowerL,HIGH);
motorStatus= String(“MOVFS Ok”);
Serial.println(motorStatus);
}

// move backward left
void modeSB()
{
digitalWrite(MotorDirectionR, HIGH);
digitalWrite(MotorDirectionL, LOW);
digitalWrite(MotorPowerR,HIGH);
digitalWrite(MotorPowerL,LOW);
motorStatus= String(“MOVSB Ok”);
Serial.println(motorStatus);
}

// move backward right
void modeBS()
{
digitalWrite(MotorDirectionR, LOW);
digitalWrite(MotorDirectionL, HIGH);
digitalWrite(MotorPowerR,LOW);
digitalWrite(MotorPowerL,HIGH);
motorStatus= String(“MOVBS Ok”);
Serial.println(motorStatus);
}

//report distance left
void lookLeft()
{
Serial.print(“DISTL “);
check_distance(2);
}

//report distance right
void lookRight()
{
Serial.print(“DISTR “);
check_distance(3);
}

// report Status back to host
void helloDalek()
{
Serial.print(“MOTOR “);
Serial.println(motorStatus);
}

//report software version
void reportVersion()
{
Serial.println(“VERSN 1.0″);
}

//main program loop
void loop()
{
if (Serial.available() >0)
{
char inByte = Serial.read();
// this version uses the QWEASDZXC “square” on the keyboard
// as my laptop doesn’t have a numeric keypad
// L and R are used to “look” left and right for distance sensing
// H is for Hello. To report the status of the device.
switch (inByte)
{
case ‘q’:
modeSF();
break;
case ‘w’:
modeFF();
break;
case ‘e’:
modeFS();
break;
case ‘a’:
modeBF();
break;
case ‘s’:
modeSS();
break;
case ‘d’:
modeFB();
break;
case ‘z’:
modeBS();
break;
case ‘x’:
modeBB();
break;
case ‘c’:
modeSB();
break;
case ‘l’:
lookLeft();
break;
case ‘r’:
lookRight();
break;
case ‘h’:
helloDalek();
break;
case ‘v’:
reportVersion();
break;

default:
Serial.println(“UKNWN”);
break;
}
}
}

Again, parts of this come from Lucky Larry‘s site.

And the C part:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <getopt.h>

void usage(void);
int serialport_init(const char* serialport, int baud);
int serialport_writebyte(int fd, uint8_t b);
int serialport_write(int fd, const char* str);
int serialport_read_until(int fd, char* buf, char until);

int main(int argc, char *argv[])
{
int fd = 0;
char serialport[256];
char buf[256];
int rc,n;

fd = serialport_init(“/dev/ttyUSB0″, B9600);
if(fd==-1) return -1;
strcpy(buf,argv[1]);
rc = serialport_write(fd, buf);
if(rc==-1) return -1;
usleep(100 * 1000 ); // sleep milliseconds
serialport_read_until(fd, buf, ‘\n’);
printf(“read: %s\n”,buf);
exit(EXIT_SUCCESS);
} // end main

int serialport_write(int fd, const char* str)
{
int len = strlen(str);
int n = write(fd, str, len);
if( n!=len )
return -1;
return 0;
}

int serialport_read_until(int fd, char* buf, char until)
{
char b[1];
int i=0;
do {
int n = read(fd, b, 1);  // read a char at a time
if( n==-1) return -1;    // couldn’t read
if( n==0 ) {
usleep( 10 * 1000 ); // wait 10 msec try again
continue;
}
buf[i] = b[0]; i++;
} while( b[0] != until );

buf[i] = 0;  // null terminate the string
return 0;
}

// takes the string name of the serial port (e.g. “/dev/tty.usbserial”,”COM1″)
// and a baud rate (bps) and connects to that port at that speed and 8N1.
// opens the port in fully raw mode so you can send binary data.
// returns valid fd, or -1 on error
int serialport_init(const char* serialport, int baud)
{
struct termios toptions;
int fd;

//fprintf(stderr,”init_serialport: opening port %s @ %d bps\n”,
//        serialport,baud);

fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)  {
perror(“init_serialport: Unable to open port “);
return -1;
}

if (tcgetattr(fd, &toptions) < 0) {
perror(“init_serialport: Couldn’t get term attributes”);
return -1;
}
cfsetispeed(&toptions, B9600);
cfsetospeed(&toptions, B9600);

// 8N1
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
// no flow control
toptions.c_cflag &= ~CRTSCTS;

toptions.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl

toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
toptions.c_oflag &= ~OPOST; // make raw

// see: http://unixwiz.net/techtips/termios-vmin-vtime.html
toptions.c_cc[VMIN]  = 0;
toptions.c_cc[VTIME] = 20;

if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
perror(“init_serialport: Couldn’t set term attributes”);
return -1;
}

return fd;
}

This is a canibalisation of code from Tod Kurt‘s site.

My botch of this just takes a single character as a command line option, passes it the Arduino and prints the reply. eg:

$ ./dav s

read: MOVSS Ok

$ ./dav v

read: VERSN 1.0

$ ./dav l

read: DISTL 42.15

$ ./dav k

read: UKNWN

In other news, I’ve ordered a DIY Shield Kit from Amazon, so I can tidy up the hardware a bit, and a miniscule USB webcam which I intend to fit into the head part of the Dalek. I also plan to move all the clever bits of circuitry into to the top half, of the Dalek, and Meccano-up a set of brackets to hold the various battery sets that are needed in the bottom half.