Cheesoid: Difference between revisions
Line 169: | Line 169: | ||
* mode change detection | * mode change detection | ||
=== test sketch === | |||
<syntaxhighlight lang="cpp"> | |||
// Two LEDs are used for eyes on two digital pins... | |||
const int redeye = 5; | |||
const int greeneye = 6; | |||
// The mode switch is on a digital input... | |||
const int switchpin = 7; | |||
// main loop has 10ms sleeps... | |||
const int naptime = 10; | |||
// the eyes flash every 60 loops = 600ms... | |||
int eyefreq = 60; | |||
// info is sent out on the serial port every 100 loops = 1s... | |||
int reportfreq = 100; | |||
// the mode switch is read every 10 loops = 100ms... | |||
// TODO - using an experimental debounce instead | |||
//int switchreadfreq = 10; | |||
// a simple loop counter is used to decide what to do... | |||
unsigned int loopcounter = 0; | |||
int mode = 0; | |||
void setup() { | |||
Serial.begin(9600); | |||
pinMode(greeneye, OUTPUT); | |||
pinMode(redeye, OUTPUT); | |||
pinMode(switchpin, INPUT); | |||
// announce startup... | |||
flasheyes(); | |||
Serial.println("\n=== CHEESOID ==="); | |||
// TODO: piezo buzzer to play a tune | |||
mode = digitalRead(switchpin); | |||
} | |||
void flasheyes() { | |||
for(int i=0;i<6;i++){ | |||
int onoff = i % 2; | |||
digitalWrite(greeneye, onoff); | |||
digitalWrite(redeye, onoff); | |||
delay(200); | |||
} | |||
} | |||
void loop() { | |||
do_switch(); | |||
do_eyes(); | |||
do_report(); | |||
do_serialinput(); | |||
delay(naptime); | |||
loopcounter++; | |||
} | |||
void do_switch() { | |||
// button debounce: state must remain stable for N samples. | |||
// This is just a lightweight debouncer | |||
// used if we want to avoid the more general purpose | |||
// but heavyweight Bounce library. | |||
const int debouncesamples = 5; | |||
static int lastsample = 0; | |||
static int steadycount = 0; | |||
static int debounced = 0; | |||
// if the value is steady for | |||
int sample = digitalRead(switchpin); | |||
// a change of value - restart the steady count... | |||
if(sample != lastsample){ | |||
lastsample = sample; | |||
steadycount = 0; | |||
return; | |||
} | |||
steadycount++; | |||
if(steadycount < debouncesamples) | |||
return; | |||
steadycount = debouncesamples; | |||
debounced = sample; | |||
// set the actual mode switch value | |||
mode = debounced; | |||
} | |||
void do_eyes() { | |||
static int eyestate = 0; | |||
if(loopcounter % eyefreq != 0) | |||
return; | |||
eyestate = !eyestate; | |||
digitalWrite(greeneye, eyestate); | |||
digitalWrite(redeye, !eyestate); | |||
} | |||
void do_report() { | |||
if(loopcounter % reportfreq != 0) | |||
return; | |||
Serial.print("CHEESOID: mode = "); | |||
Serial.print(mode); | |||
//~ Serial.print(" | eye = "); | |||
//~ Serial.print(onoff); | |||
Serial.print(" | loop = "); | |||
Serial.println(loopcounter); | |||
} | |||
void do_serialinput() { | |||
// can we avoid buffer overflows when using the | |||
// standard serial library at a 10ms read rate at 9600 baud? | |||
// Well, 9600 8-n-1 is 960 bytes per sec or 9.6 per 10ms | |||
// The standard serial receive buffer holds 128 bytes so we're fine | |||
static int maxread = 0; | |||
// any data waiting? | |||
int len = Serial.available(); | |||
if(!len) | |||
return; | |||
if(len > maxread) | |||
maxread = len; | |||
for(int i = 0; i < len; i++){ | |||
int c = Serial.read(); | |||
Serial.println(c); | |||
} | |||
} | |||
</syntaxhighlight> | |||
[[Category:Projects]] | [[Category:Projects]] | ||
[[Category:Current Projects]] | [[Category:Current Projects]] |
Revision as of 14:41, 11 August 2011
"Why Cheesoid exist?"
An unhappy robot designed to have a sense of smell but can only distinguish between its two operating modes: "CHEESE" and "PETROL".
Thoughts
Everybody loves robots: It's your plastic pal who's fun to have around! I'd like a robot too, and I'm going to build one goddamnit!!!
As with everything I want to build, it must be funny, and so Cheesoid is the ideal blueprint to follow.
It has (should have) speech limited to a number of pre-recorded phrases: -
- "Cheese"
- "Petril"
- "Help! Cannot see! Can only smell!"
- "Why Cheesoid exist?"
- etc.
Basic Construction
I have a cardboard cylinder (slightly smaller than the original) and a silver "nose hose". The nose hose will contain a bent rod that will be rotated by a servo or stepper motor. The robot can run on top of a R/C car to begin with. The donated R/C car at the space has no battery and I couldn't get the motor to run!
I plan to cover Cheesoid in silver-grey paper.
The nose hose needs to be mounted in a shallow box which in turn is fixed to the body.
The "CHEESE" or "PETROL" mode switch must be authentic!
Voice capability will just be some sort of recordable button box.
Object detector (that initiates the smelling process) would be awesome.
The ability to actually distinguish between the smell of cheese and petrol would be crazy-awesome!
Need: -
- R/C vehicle
- silver-grey paper or card
- nose rod and motor
- voice
- lamp eyes - one red, one green
- flashing LEDS
- automation!!!
Nose Stepper
- get to grips with random recovered stepper motors
- This one is especially useful - taught me enough to proceed: http://www.stepperworld.com/Tutorials/pgUnipolarTutorial.htm
- http://www.piclist.com/techref/io/stepper/..%5Csteppers.htm
- http://www.instructables.com/id/Drive-a-Stepper-Motor-with-an-AVR-Microprocessor/
- http://wwwhomes.doc.ic.ac.uk/~ih/doc/stepper/others/
A stepper motor will be used to drive the "nose". The curved nose hose is fixed to the body and doesn't rotate. Inside a rigid but bent rod will rotate, driven by the stepper. The stepper needs enough grunt! I have no idea how "grunt" is measured in ISO units - torque I guess. Speed and accuracy is not so important for this task but it is a learning experience.
So I chose a random biggish stepper motor (from the members' motor box)...
It has 6 wires that go to a 2x4 0.1" pitch connector. It says "MINEBEA" "TYPE 17PS-C035-03" -- hmmm...
1.7 inch, P = Precision, Hybrid, S = 3.6 Deg, C =2 & 4 Phase Hybrid, Motor Lengths = 0(?), Different Windings = 35, Version = 03.
OK, so the information on the side isn't much help in finding the voltage and current so using the magic knowledge on the pages listed above I gleaned some info using SCIENCE!!!!
The stepper turns out to be a Unipolar. It has 6 wires, 2 for the centre taps which should go to V+ and two each for the grounds of the half coils.
I identified the usage of the wires using my cheap multimeter and measured the half coil resistances: 36.9 ohms, 36.6 ohms, 36.7 ohms, 36.7 ohms.
Brown | Black | Red |
Green | Orange | White |
Coil B 1 | Coil A Centre | Coil B 2 |
Coil A 1 | Coil B Centre | Coil A 2 |
To be continued!!!
Display and Indicators
The eyes on the "real" Cheesoid just flash left-right, left-right with one eye being red and the other green. I'll stick with this for now as it's simple but I'm not sure I want to use two pins on my Xino. I'll look into that when I have the basics in place.
I have added an LCD display...
This is a Seiko L2012 LCD module (File:Seiko L2012 LCD Module - datasheet-3.pdf) which can be driven straight from the Arduino example library. I modified a Xino to directly drive one with a 14-pin header soldered to the prototype area of the board. This module I rescued from the skip at work and it has some damage to the LCD but it is entirely usable.
Voice
- make cheesoid voice recordings
- download FLV of youtube video and extract audio - DONE
- slice and dice with audacity - DONE
- investigate robot voice changers and try to get the Robert Webb voice perfect
I need a device that can play back my recordings on demand. Some sort of controllable MP3 player would be ideal. How do I make an MP3 player controllable? Wire into the buttons? Possible. I'd need some feedback on what's playing or whatever is useful or available. I could try to read the LCD screen! I could try to "listen" to the audio output!
I need speakers!
An MP3 shield is a fine solution but it's not my cup of tea: too easy and no pain! I could make my own MP3 shield: -
- VLSI VS1000 Ogg Vorbis chip
- would need a LQFP48 breakout board (http://www.nkcelectronics.com/lqfp48-breakout-boa48.html) - couple of quid
- VLSI VS1011 MP3 chip
- full-on breakout for the VS1000 at sparkfun: http://www.sparkfun.com/products/8849
- http://elm-chan.org/works/sd20p/report.html
Other devices can play audio and MP3s: PDAs, phones, etc. Can they be driven?
Movement and Power
Although I eventually want the robot to be pretty autonomous, initially I guess any kind of movement will be good. I imagine simply mounting the body on a reasonably powerful R/C car or tank. I'm going to have to get to grips with servos and R/C in general. I'll be looking out for tank track parts (e.g. bike chain tracks) in the meantime for a more serious robot movement base.
For power I want to try out using some of the 12v and 6v lead acid batteries from the Emergency Roadside Telephone. I have recharged a 12v one and it seems quite happy after being sat on a shelf for many years! I also have my solar panel and I'd like to make use of it for recharging.
--Michael Erskine 16:38, 3 May 2011 (BST)
Progress Update: Aug 2011
After some time on the back-burner (Arcade Machine and Barcamp) this project has gained momentum again with the resurrection of my dead Asus eeePC 701. I am now using this little gem as the brains inside Cheesoid which solves a number of issues but perhaps introduces a few too! A quick list: -
- I bought this eeePC 701 from Andy Beale some time ago and over time the keyboard broke followed by the power port. I tried previously to fix the power port but failed. A redoubled effort got it going yesterday but I don't know about the battery life!
- an external USB keyboard is enough to get things going
- it's a Linux box with bash and a full Java JVM!!!
- it can play WAV and MP3 files with mplayer - solving my voice issues
- there is a voice recognition app!
- it has WiFi!
- it can power the Arduino and also talk to it over the USB-Serial
- I think I'll develop on my Arduino Uno - maybe even running the IDE on the eeePC
The eeePC just about fits into the body of Cheesoid apart from USB cables plugged into the side ports - I hope to sort that out
--Michael Erskine 21:14, 7 August 2011 (BST)
PC application and Arduino sketch
Now the eeePC is to be used I want to use one of my genuine Arduino boards for the USB serial. I'd prefer not to use the UNO as it seems to have more issues with the USB/Serial but I need to retain my Duemilanove for most prototyping. Perhaps it's time to start making PaperFTDI cables (http://txapuzas.blogspot.com/2010/07/cable-de-programacion-para-arduino-ftdi.html) so I can use the Xino boards.
OK, so since my eeePC has a full Java VM perhaps I might write the PC end in Java. I wouldn't really host an IDE on the eeePC though so perhaps Perl is better option for quick prototyping. I don't think I need bother too much with Dev::Serial (or whatever it's called nowadays) since under Linux I can use tty to set up the port and just open the device as a plain filehandle. Good in theory! I'll have a go with this later.
On the Arduino end I'll probably keep the LCD panel running from the modified Xino and maybe talk to it with softserial from the other Arduino or talk to it from the PC app - wow, the possibilities! Either way I'll be wanting to chop the loop functionality into blocks and perhaps implement a cheap scheduler.
- Switch debounce for all inputs
- LED eye flash routines - for different modes
- nose control
- PIR or sonar detection for proximity of smell sample!
- mode change detection
test sketch
// Two LEDs are used for eyes on two digital pins...
const int redeye = 5;
const int greeneye = 6;
// The mode switch is on a digital input...
const int switchpin = 7;
// main loop has 10ms sleeps...
const int naptime = 10;
// the eyes flash every 60 loops = 600ms...
int eyefreq = 60;
// info is sent out on the serial port every 100 loops = 1s...
int reportfreq = 100;
// the mode switch is read every 10 loops = 100ms...
// TODO - using an experimental debounce instead
//int switchreadfreq = 10;
// a simple loop counter is used to decide what to do...
unsigned int loopcounter = 0;
int mode = 0;
void setup() {
Serial.begin(9600);
pinMode(greeneye, OUTPUT);
pinMode(redeye, OUTPUT);
pinMode(switchpin, INPUT);
// announce startup...
flasheyes();
Serial.println("\n=== CHEESOID ===");
// TODO: piezo buzzer to play a tune
mode = digitalRead(switchpin);
}
void flasheyes() {
for(int i=0;i<6;i++){
int onoff = i % 2;
digitalWrite(greeneye, onoff);
digitalWrite(redeye, onoff);
delay(200);
}
}
void loop() {
do_switch();
do_eyes();
do_report();
do_serialinput();
delay(naptime);
loopcounter++;
}
void do_switch() {
// button debounce: state must remain stable for N samples.
// This is just a lightweight debouncer
// used if we want to avoid the more general purpose
// but heavyweight Bounce library.
const int debouncesamples = 5;
static int lastsample = 0;
static int steadycount = 0;
static int debounced = 0;
// if the value is steady for
int sample = digitalRead(switchpin);
// a change of value - restart the steady count...
if(sample != lastsample){
lastsample = sample;
steadycount = 0;
return;
}
steadycount++;
if(steadycount < debouncesamples)
return;
steadycount = debouncesamples;
debounced = sample;
// set the actual mode switch value
mode = debounced;
}
void do_eyes() {
static int eyestate = 0;
if(loopcounter % eyefreq != 0)
return;
eyestate = !eyestate;
digitalWrite(greeneye, eyestate);
digitalWrite(redeye, !eyestate);
}
void do_report() {
if(loopcounter % reportfreq != 0)
return;
Serial.print("CHEESOID: mode = ");
Serial.print(mode);
//~ Serial.print(" | eye = ");
//~ Serial.print(onoff);
Serial.print(" | loop = ");
Serial.println(loopcounter);
}
void do_serialinput() {
// can we avoid buffer overflows when using the
// standard serial library at a 10ms read rate at 9600 baud?
// Well, 9600 8-n-1 is 960 bytes per sec or 9.6 per 10ms
// The standard serial receive buffer holds 128 bytes so we're fine
static int maxread = 0;
// any data waiting?
int len = Serial.available();
if(!len)
return;
if(len > maxread)
maxread = len;
for(int i = 0; i < len; i++){
int c = Serial.read();
Serial.println(c);
}
}