Components and supplies
Wire, Hook Up
High Brightness LED, White
Development Board, Class D Audio Amplifier Module
Audio Amplifier Board (Based on HXL1446)
Speaker: 0.25W, 8 ohms
SparkFun Sound Detector (with Headers)
Arduino Nano R3
PIR Motion Sensor (generic)
Tools and machines
Super Glue
3D Printer (generic)
Matt Black Spray Paint
Hacksaw
Soldering iron (generic)
Solder Wire, Lead Free
Orange 3D Printer Filament
2.5W UV Laser Module
Solder Flux, Soldering
Single Side Copper Clad Board
Apps and platforms
JTech Photonics Inkscape Laser Plug-In
Inkscape
FreePCB
Visual Micro
Audacity
Arduino IDE
Visual Studio 2017
GerbV
Project description
Code
TalkieToaster.ino
arduino
Main code file to run the project.....
1/* 2 3Lib: https://github.com/TMRh20/TMRpcm 4 5Talkie made by Crapola Inc --> https://reddwarf.fandom.com/wiki/Crapola_Inc. 6 7STL File for Block Lever for a Toaster (Talkie v1 needs two block ones) 8https://www.thingiverse.com/thing:63723 9 10Episodes Talkie is in: https://reddwarf.fandom.com/wiki/Talkie_Toaster 11V1 Talkie: 12In two episodes of Series I, "Future Echoes" and "Waiting for God", Talkie Toaster appears as a standard 1970s toaster made from stainless steel but with a circular light on the side which flashes as he speaks, and is voiced by John Lenahan. 13In "Balance of Power", Series I - Lister eats Krispies and converses with Talkie Toaster in the sleeping quarters of Red Dwarf 14In a deleted scene from the first episode of Series II, Talkie Toaster is seen singing a duet with Cat (this scene can be seen in the special features of the Series II DVD.) 15V2 Talkie: 16In the Series IV episode "White Hole", Talkie Toaster appears rebuilt by Kryten with a housing of red plastic, with his name "Talkie Toaster" emblazoned on the side, and rather more flashing red and green lights (originally from "Box", the computer in Star Cops) - although they have nothing to do with when he speaks, which is indicated by the press-down handle that would usually be used to start bread toasting - and is voiced by David Ross (who originally played Kryten in Series II). The second novel's description matches his appearance in Series IV. 17 18Nano - Arduino Pins 19SD Card 2013 sck 2112 miso 2211 mosi 2310 cs 24 253 2x10mm LED to sync with sound 264 PIR input 275 Mic Input for Listenting for replies 289 Speaker output, to amplifier 29 30 31*/ 32 33 34#include <SPI.h> 35#include <TMRpcm.h> 36#include <pcmRF.h> 37#include <pcmConfig.h> 38#include <SD.h> 39 40#define SD_CARD 10 41 42TMRpcm sample; 43 44// PIR sensor 45int calibrationTime = 10; 46 47long conversationQuitUs = 60000; // If no-one continues within a minute - quit conversation 48long conversationStartTime = 0; 49int pirPin = 4; // PIR sensor input 50int micPin = 5; // Mic sensor Input 51int ledPin = 3; // LED outputs 52int speakerInputPin = 2; // Feeback from output of speaker for LEDs.... 53 54char* currentPlaylist = "1"; 55int currentTrack = 0; 56boolean triggered = false; 57boolean pirTriggered = false; 58boolean micTriggered = false; 59boolean talking = false; 60 61 62/* Sound Files: 631-0_1.wav Talkiev1 - 1 - You Cant Sing 641-0_2.wav Talkiev1 - 2 - Just cos Im a Toaster 651-0_3noBang.wav Talkiev1 - 3 - Sings Sinatra (no Bang) 661-0_3withBang.wav Talkiev1 - 3 - Sings Sinatra (with Bang) 67 682-0_1.wav Talkiev2 - 1 - Intro 692-0_2.wav Talkiev2 - 2 - How About a Muffin 702-0_3.wav Talkiev2 - 3 - Waffle Man 712-0_4.wav Talkiev2 - 4 - Can I ask One Question 722-0_5.wav Talkiev2 - 5 - Any Toast 732-0_6.wav Talkiev2 - 6 - Changed Your Mind 742-0_7.wav Talkiev2 - 7 - I Toast Therefore I Am 752-1_1.wav Talkie v2.1 - 1 - Hope You don't get an overload 76 772-1_2.wav Talkie v2.1 - 2 - Youll Explode 782-1_4.wav Talkie v2.1 - 4 - Any Question 792-1_5.wav Talkie v2.1 - 5 - Any Question 802-1_6.wav Talkie v2.1 - 6 - Ok Heres my Question 812-1_7.wav Talkie v2.1 - 7 - Chaos Theory 822-1_8.wav Talkie v2.1 - 8 - Would you like a Crumpet 832-1_9.wav Talkie v2.1 - 9 - That is not answering 842-1_10.wav Talkie v2.1 - 10 - A Sensible Question 852-1_11.wav Talkie v2.1 - 11 - Resent Implication 862-1_12.wav Talkie v2.1 - 12 - God Toasted Teacake 872-1_13.wav Talkie v2.1 - 13 - Before You go 882-1_14.wav Talkie v2.1 - 14 - Cheese and Ham Braville 89*/ 90 91char* playlist[22][3] = { 92 {"1","0","1-0_1.wav" }, 93 {"1","0","1-0_2.wav" }, 94 {"1","0","1-0_3wb.wav" }, 95 // {"1","1","1-0_3wb.wav" }, 96 {"2","0","2-0_1.wav" }, 97 {"2","0","2-0_2.wav" }, 98 {"2","0","2-0_3.wav" }, 99 {"2","0","2-0_4.wav" }, 100 {"2","0","2-0_5.wav" }, 101 {"2","0","2-0_6.wav" }, 102 {"2","0","2-0_7.wav" }, 103 104 {"3","0","2-1_1.wav" }, 105 {"3","0","2-1_4.wav" }, 106 {"3","0","2-1_5.wav" }, 107 {"3","0","2-1_6.wav" }, 108 {"3","0","2-1_7.wav" }, 109 {"3","0","2-1_8.wav" }, 110 {"3","0","2-1_9.wav" }, 111 {"3","0","2-1_10.wav" }, 112 {"3","0","2-1_11.wav" }, 113 {"3","0","2-1_12.wav" }, 114 {"3","0","2-1_13.wav" }, 115 {"3","0","2-1_14.wav" } 116}; 117 118 119void setup() 120{ 121 122 // randomiser for speech output, using an unused pin (!) 123 randomSeed(analogRead(2)); 124 Serial.begin(9600); 125 music_setup(); 126 pinMode(pirPin, INPUT); 127 pinMode(micPin, INPUT); 128 pinMode(ledPin, OUTPUT); 129 digitalWrite(ledPin, HIGH); 130 delay(1000); 131 digitalWrite(ledPin, LOW); 132 Serial.println(" Done"); 133} 134 135bool micHeard = false; 136long micLastHeard = 0; 137bool lastMicRead = false; 138 139bool pirRead = false; 140bool lastPirRead = false; 141long pirLastLow = 0; 142bool pirEnabled = false; 143 144void loop() 145{ 146 // Ensure someone has gone away before triggering PIR (otherwise convesations can bleed together) 147 pirRead = digitalRead(pirPin); 148 if (pirRead != lastPirRead) { 149 if (!pirRead) { 150 pirLastLow = millis(); 151 } 152 lastPirRead = pirRead; 153 } 154 155 if (pirRead && (millis() - pirLastLow) > 5000 && pirLastLow != 0) { 156 Serial.println("PIR ENABLED"); 157 pirLastLow = 0; 158 pirEnabled = true; 159 } 160 161 pirEnabled = true; 162 byte micRead = 0; 163 if (pirEnabled) { 164 pirTriggered = digitalRead(pirPin); 165 micRead = !digitalRead(micPin); 166 167 // Debounce our mic so have to hear silence for a second... 168 if (micRead != lastMicRead) { 169 if (micRead) { 170 micLastHeard = millis(); 171 } 172 lastMicRead = micRead; 173 } 174 175 if (!micRead && (millis() - micLastHeard) > 875 && micLastHeard != 0) { 176 Serial.println("MIC TRIGGER"); 177 micLastHeard = 0; 178 micTriggered = true; 179 } 180 181 182 // Assess triggers depending on state: 183 // if Heard something, didnt see anyone, and not talking - do nothing 184 if (micTriggered && !talking) { 185 micTriggered = false; 186 triggered = false; 187 } 188 189 // If saw someone and not talking - start a conversation 190 if (pirTriggered && !talking) { 191 triggered = true; 192 pirTriggered = false; 193 micTriggered = false; 194 } 195 196 // if heard someone and already talking - continue conversation 197 if (micTriggered && talking) { 198 triggered = true; 199 micTriggered = false; 200 pirTriggered = false; 201 } 202 203 204 205 // playtime 206 if (triggered) 207 { 208 if (!talking) { // See if a new conversation 209 conversationStartTime = millis(); 210 talking = true; 211 Serial.print("Now Talking\ "); 212 } 213 // Play next in current conversation 214 playFullSample(playlist[currentTrack][2], playlist[currentTrack][1]); 215 Serial.print("Playing Track:"); 216 Serial.print(playlist[currentTrack][2]); 217 // Move On..... 218 currentTrack = (currentTrack + 1) % 22; 219 Serial.print("\ NextId:"); 220 Serial.println(currentTrack); 221 222 // set talking = false at end of convo.... if we have reached it 223 if (currentPlaylist != playlist[currentTrack][0]) { 224 talking = false; 225 Serial.print("Last in Conversation"); 226 pirEnabled = false; 227 } 228 currentPlaylist = playlist[currentTrack][0]; 229 230 triggered = false; 231 232 } 233 } 234 else { 235 // If Im left alone too long I give up.... 236 if ((millis() - conversationStartTime) > conversationQuitUs) { 237 talking = false; 238 triggered = false; 239 pirEnabled = false; 240 if (currentPlaylist == "1") { 241 currentPlaylist = "2"; 242 } else if (currentPlaylist == "2") { 243 currentPlaylist = "3"; 244 } 245 else if(currentPlaylist == "3") { 246 currentPlaylist = "1"; 247 } 248 249 currentPlaylist = "1"; 250 currentTrack = 0; 251 } 252 } 253 254} 255 256 257// Setup for Music 258void music_setup() { 259 // see if the card is inserted and found 260 if (!SD.begin(SD_CARD)) 261 { 262 return; // It's not there, don't do anything 263 } 264 Serial.println("SD card started"); 265 // speaker pin output 266 sample.speakerPin = 9; 267 // quite loud 268 sample.volume(9); 269 sample.quality(1); 270 sample.disable(); 271} 272 273// This method plays files of any length.... 274 // See docs https://github.com/TMRh20/TMRpcm/wiki 275// Play whole track but ensure that we flash our LED with the speaker PWM 276// and can adjust to get what "feels" better to see 277void playFullSample(char* sampleName) { 278 playFullSample(sampleName, false); 279} 280 281void playFullSample(char* sampleName, char* stopOnMicTrigger) { 282 sample.play(sampleName); 283 boolean micHeard = false; 284 while (sample.isPlaying() && !micHeard) { 285 286 // never actually used this to detect the bang.... 287 if (stopOnMicTrigger == "1") { 288 if (digitalRead(micPin) == HIGH) { 289 micHeard = true; 290 } 291 } 292 293 int duration = pulseIn(speakerInputPin, 500); // Allow 1ms before quitting 294 int brightness = map(duration, 0, 15, 0, 255); 295 if (brightness < 200) { // flatten lower values to 0, so visible changes in brighness 296 brightness = 0; 297 } 298 //Serial.println(duration); 299 analogWrite(ledPin, brightness); 300 delay(brightness); 301 } 302 analogWrite(ledPin, 0); 303 sample.disable(); 304}
TalkieToaster.ino
arduino
Main code file to run the project.....
1/* 2 3Lib: https://github.com/TMRh20/TMRpcm 4 5Talkie made by Crapola Inc --> https://reddwarf.fandom.com/wiki/Crapola_Inc. 6 7STL File for Block Lever for a Toaster (Talkie v1 needs two block ones) 8https://www.thingiverse.com/thing:63723 9 10Episodes Talkie is in: https://reddwarf.fandom.com/wiki/Talkie_Toaster 11V1 Talkie: 12In two episodes of Series I, "Future Echoes" and "Waiting for God", Talkie Toaster appears as a standard 1970s toaster made from stainless steel but with a circular light on the side which flashes as he speaks, and is voiced by John Lenahan. 13In "Balance of Power", Series I - Lister eats Krispies and converses with Talkie Toaster in the sleeping quarters of Red Dwarf 14In a deleted scene from the first episode of Series II, Talkie Toaster is seen singing a duet with Cat (this scene can be seen in the special features of the Series II DVD.) 15V2 Talkie: 16In the Series IV episode "White Hole", Talkie Toaster appears rebuilt by Kryten with a housing of red plastic, with his name "Talkie Toaster" emblazoned on the side, and rather more flashing red and green lights (originally from "Box", the computer in Star Cops) - although they have nothing to do with when he speaks, which is indicated by the press-down handle that would usually be used to start bread toasting - and is voiced by David Ross (who originally played Kryten in Series II). The second novel's description matches his appearance in Series IV. 17 18Nano - Arduino Pins 19SD Card 2013 sck 2112 miso 2211 mosi 2310 cs 24 253 2x10mm LED to sync with sound 264 PIR input 275 Mic Input for Listenting for replies 289 Speaker output, to amplifier 29 30 31*/ 32 33 34#include <SPI.h> 35#include <TMRpcm.h> 36#include <pcmRF.h> 37#include <pcmConfig.h> 38#include <SD.h> 39 40#define SD_CARD 10 41 42TMRpcm sample; 43 44// PIR sensor 45int calibrationTime = 10; 46 47long conversationQuitUs = 60000; // If no-one continues within a minute - quit conversation 48long conversationStartTime = 0; 49int pirPin = 4; // PIR sensor input 50int micPin = 5; // Mic sensor Input 51int ledPin = 3; // LED outputs 52int speakerInputPin = 2; // Feeback from output of speaker for LEDs.... 53 54char* currentPlaylist = "1"; 55int currentTrack = 0; 56boolean triggered = false; 57boolean pirTriggered = false; 58boolean micTriggered = false; 59boolean talking = false; 60 61 62/* Sound Files: 631-0_1.wav Talkiev1 - 1 - You Cant Sing 641-0_2.wav Talkiev1 - 2 - Just cos Im a Toaster 651-0_3noBang.wav Talkiev1 - 3 - Sings Sinatra (no Bang) 661-0_3withBang.wav Talkiev1 - 3 - Sings Sinatra (with Bang) 67 682-0_1.wav Talkiev2 - 1 - Intro 692-0_2.wav Talkiev2 - 2 - How About a Muffin 702-0_3.wav Talkiev2 - 3 - Waffle Man 712-0_4.wav Talkiev2 - 4 - Can I ask One Question 722-0_5.wav Talkiev2 - 5 - Any Toast 732-0_6.wav Talkiev2 - 6 - Changed Your Mind 742-0_7.wav Talkiev2 - 7 - I Toast Therefore I Am 752-1_1.wav Talkie v2.1 - 1 - Hope You don't get an overload 76 772-1_2.wav Talkie v2.1 - 2 - Youll Explode 782-1_4.wav Talkie v2.1 - 4 - Any Question 792-1_5.wav Talkie v2.1 - 5 - Any Question 802-1_6.wav Talkie v2.1 - 6 - Ok Heres my Question 812-1_7.wav Talkie v2.1 - 7 - Chaos Theory 822-1_8.wav Talkie v2.1 - 8 - Would you like a Crumpet 832-1_9.wav Talkie v2.1 - 9 - That is not answering 842-1_10.wav Talkie v2.1 - 10 - A Sensible Question 852-1_11.wav Talkie v2.1 - 11 - Resent Implication 862-1_12.wav Talkie v2.1 - 12 - God Toasted Teacake 872-1_13.wav Talkie v2.1 - 13 - Before You go 882-1_14.wav Talkie v2.1 - 14 - Cheese and Ham Braville 89*/ 90 91char* playlist[22][3] = { 92 {"1","0","1-0_1.wav" }, 93 {"1","0","1-0_2.wav" }, 94 {"1","0","1-0_3wb.wav" }, 95 // {"1","1","1-0_3wb.wav" }, 96 {"2","0","2-0_1.wav" }, 97 {"2","0","2-0_2.wav" }, 98 {"2","0","2-0_3.wav" }, 99 {"2","0","2-0_4.wav" }, 100 {"2","0","2-0_5.wav" }, 101 {"2","0","2-0_6.wav" }, 102 {"2","0","2-0_7.wav" }, 103 104 {"3","0","2-1_1.wav" }, 105 {"3","0","2-1_4.wav" }, 106 {"3","0","2-1_5.wav" }, 107 {"3","0","2-1_6.wav" }, 108 {"3","0","2-1_7.wav" }, 109 {"3","0","2-1_8.wav" }, 110 {"3","0","2-1_9.wav" }, 111 {"3","0","2-1_10.wav" }, 112 {"3","0","2-1_11.wav" }, 113 {"3","0","2-1_12.wav" }, 114 {"3","0","2-1_13.wav" }, 115 {"3","0","2-1_14.wav" } 116}; 117 118 119void setup() 120{ 121 122 // randomiser for speech output, using an unused pin (!) 123 randomSeed(analogRead(2)); 124 Serial.begin(9600); 125 music_setup(); 126 pinMode(pirPin, INPUT); 127 pinMode(micPin, INPUT); 128 pinMode(ledPin, OUTPUT); 129 digitalWrite(ledPin, HIGH); 130 delay(1000); 131 digitalWrite(ledPin, LOW); 132 Serial.println(" Done"); 133} 134 135bool micHeard = false; 136long micLastHeard = 0; 137bool lastMicRead = false; 138 139bool pirRead = false; 140bool lastPirRead = false; 141long pirLastLow = 0; 142bool pirEnabled = false; 143 144void loop() 145{ 146 // Ensure someone has gone away before triggering PIR (otherwise convesations can bleed together) 147 pirRead = digitalRead(pirPin); 148 if (pirRead != lastPirRead) { 149 if (!pirRead) { 150 pirLastLow = millis(); 151 } 152 lastPirRead = pirRead; 153 } 154 155 if (pirRead && (millis() - pirLastLow) > 5000 && pirLastLow != 0) { 156 Serial.println("PIR ENABLED"); 157 pirLastLow = 0; 158 pirEnabled = true; 159 } 160 161 pirEnabled = true; 162 byte micRead = 0; 163 if (pirEnabled) { 164 pirTriggered = digitalRead(pirPin); 165 micRead = !digitalRead(micPin); 166 167 // Debounce our mic so have to hear silence for a second... 168 if (micRead != lastMicRead) { 169 if (micRead) { 170 micLastHeard = millis(); 171 } 172 lastMicRead = micRead; 173 } 174 175 if (!micRead && (millis() - micLastHeard) > 875 && micLastHeard != 0) { 176 Serial.println("MIC TRIGGER"); 177 micLastHeard = 0; 178 micTriggered = true; 179 } 180 181 182 // Assess triggers depending on state: 183 // if Heard something, didnt see anyone, and not talking - do nothing 184 if (micTriggered && !talking) { 185 micTriggered = false; 186 triggered = false; 187 } 188 189 // If saw someone and not talking - start a conversation 190 if (pirTriggered && !talking) { 191 triggered = true; 192 pirTriggered = false; 193 micTriggered = false; 194 } 195 196 // if heard someone and already talking - continue conversation 197 if (micTriggered && talking) { 198 triggered = true; 199 micTriggered = false; 200 pirTriggered = false; 201 } 202 203 204 205 // playtime 206 if (triggered) 207 { 208 if (!talking) { // See if a new conversation 209 conversationStartTime = millis(); 210 talking = true; 211 Serial.print("Now Talking\ "); 212 } 213 // Play next in current conversation 214 playFullSample(playlist[currentTrack][2], playlist[currentTrack][1]); 215 Serial.print("Playing Track:"); 216 Serial.print(playlist[currentTrack][2]); 217 // Move On..... 218 currentTrack = (currentTrack + 1) % 22; 219 Serial.print("\ NextId:"); 220 Serial.println(currentTrack); 221 222 // set talking = false at end of convo.... if we have reached it 223 if (currentPlaylist != playlist[currentTrack][0]) { 224 talking = false; 225 Serial.print("Last in Conversation"); 226 pirEnabled = false; 227 } 228 currentPlaylist = playlist[currentTrack][0]; 229 230 triggered = false; 231 232 } 233 } 234 else { 235 // If Im left alone too long I give up.... 236 if ((millis() - conversationStartTime) > conversationQuitUs) { 237 talking = false; 238 triggered = false; 239 pirEnabled = false; 240 if (currentPlaylist == "1") { 241 currentPlaylist = "2"; 242 } else if (currentPlaylist == "2") { 243 currentPlaylist = "3"; 244 } 245 else if(currentPlaylist == "3") { 246 currentPlaylist = "1"; 247 } 248 249 currentPlaylist = "1"; 250 currentTrack = 0; 251 } 252 } 253 254} 255 256 257// Setup for Music 258void music_setup() { 259 // see if the card is inserted and found 260 if (!SD.begin(SD_CARD)) 261 { 262 return; // It's not there, don't do anything 263 } 264 Serial.println("SD card started"); 265 // speaker pin output 266 sample.speakerPin = 9; 267 // quite loud 268 sample.volume(9); 269 sample.quality(1); 270 sample.disable(); 271} 272 273// This method plays files of any length.... 274 // See docs https://github.com/TMRh20/TMRpcm/wiki 275// Play whole track but ensure that we flash our LED with the speaker PWM 276// and can adjust to get what "feels" better to see 277void playFullSample(char* sampleName) { 278 playFullSample(sampleName, false); 279} 280 281void playFullSample(char* sampleName, char* stopOnMicTrigger) { 282 sample.play(sampleName); 283 boolean micHeard = false; 284 while (sample.isPlaying() && !micHeard) { 285 286 // never actually used this to detect the bang.... 287 if (stopOnMicTrigger == "1") { 288 if (digitalRead(micPin) == HIGH) { 289 micHeard = true; 290 } 291 } 292 293 int duration = pulseIn(speakerInputPin, 500); // Allow 1ms before quitting 294 int brightness = map(duration, 0, 15, 0, 255); 295 if (brightness < 200) { // flatten lower values to 0, so visible changes in brighness 296 brightness = 0; 297 } 298 //Serial.println(duration); 299 analogWrite(ledPin, brightness); 300 delay(brightness); 301 } 302 analogWrite(ledPin, 0); 303 sample.disable(); 304}
Downloadable files
Image of PCB Design
Just an image to show the PCB design, read tutorial for where current issues had to be worked around.
Image of PCB Design
Documentation
Speaker Cover
STL File for 3D Printing Speaker Cover Frame (quick design) Supports: Yes Infill: 20%
Speaker Cover
Speaker Cover
STL File for 3D Printing Speaker Cover Frame (quick design) Supports: Yes Infill: 20%
Speaker Cover
Comments
Only logged in users can leave comments
arduinocc
0 Followers
•0 Projects
Table of contents
Intro
1
0