Project tutorial
The Talking IoT Toaster

The Talking IoT Toaster © GPL3+

If you've ever felt people don't ask for the all toast they want, this is the project for you!

  • 625 views
  • 0 comments
  • 2 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)
4966285
Solder Wire, Lead Free
66y6421 40
Solder Flux, Soldering
Single Side Copper Clad Board
Matt Black Spray Paint
Hacksaw
3drag
3D Printer (generic)
2.5W UV Laser Module
Orange 3D Printer Filament
Can use Orange spray Paint as we did
Super Glue

Apps and online services

Ide web
Arduino IDE
Vs2017logo dyb4bnncmy
Microsoft Visual Studio 2017
Visual Micro
Audacity
FreePCB
ONLY if building PCB
GerbV
ONLY if building PCB
Inkscape
ONLY if building PCB
JTech Photonics Inkscape Laser Plug-In
ONLY if building PCB

About this project

Initially this was started as a little fun project, simply to frustrate a friend, however it has been so much fun its worth sharing!

What we wanted was a take on the classic "Talkie Toaster" from the TV Show Red Dwarf, which would be able to constantly ask toast related questions every time someone was nearby. We also wanted it to respond to being shouted at as well, so we added a few more parts to the project.

It was also a chance to try out our PCB Etching, but this could be assembled on a breadboard / strip board just as easily.

In the future we will further integrate it with other IoT peripherals and services, and this tutorial will get us well on our way...

General Hardware

To achieve this project we needed a wide array of hardware, anything marked with a (*) can be omitted unless you are trying to build the project in its entirety.

Sound

As our project is all about the sounds we need to convert them into a format we can use on our Arduino with our chosen library (TMRpcm).

All sound encoding can be done reliably using Audacity.

If your tracks are stereo you will need to downmix them to mono (as we only have one speaker) using the option on the Tracks > Mix menu.

Now Export the file from File > Export > Export As WAV, and ensure the bit rate settings are as below:

Save all of these new files to your SD Card, and if they run as part of seperate conversations, naming them in a "conversation_StepId.wav" can be useful to make them easier to iterate in the code.

Coding

To code this was relatively easy as there is already an WAV compatible library for the AVR platform, and so all we need is to add in our logic, and the code for reading our microphone and PIR sensors.

In the code we:

  • Setup all I/O
  • Work out what conversation to start in
  • Wait for a trigger to begin a conversation (PIR Only)
  • If talking to someone, wait for a response (MIC) before responding with the next segment
  • If no-one responds after a period - give up and go to the start of the next conversation for the next person

Circuit Board

To create the circuit board we used here, we used a 3D Printer along with a 2.5w UV Laser.

  • Paint the copper clad board with a single layer of black matt paint
  • Design the Gerber files in a tool of your choice (Free PCB, Eagle, etc..)
  • Export your Gerber in Black and White, where Black represents the paint / copper to remove, and either vertically or horizontally flip the bottom copper layer
  • Open Inkscape and resize the document to fit your printer bed
  • Import this into Inkscape and resize to the correct size
  • Convert the Image to Path using the Edge Tracing Tool
  • Use the JTech Laser tool to generate the laser GCode
  • Run on Printer

Now you should have a board which resembles the below:

This needs a scrub with a soft bristled brush, and we have found doing this dry first, then using a little washing up liquid works well. Clean until the copper is visibly shiny again.

NOTE - If this doesn't work you may need to tweak your laser settings to be slower / higher power.

Now we can place the board into our Ferric Chloride to etch away the copper, putting your phone torch under the vat can be useful to see progress, as the light shines through the board where the etching is progressing.

NOTE - remove the board after 5-10 minutes and gently scrub the tracks again. This ensures any paint which was not fully removed now is as the acid weakens the edges of the remaining paint.

Once the etching is complete, rinse off the board, and if you're happy remove the rest of the paint using acetone.

Now we can drill the holes for our components using a small drill, 1 mm in this example (be careful not to break the bits!)

NOTE - there were a few copper areas I failed to join on the PCB so a few added holes and wires were put in to correct this (see second image above)

We have used no solder mask or tinning solution in this project. I will just lacquer the board when finished to prevent corrosion as its just a fun project.

Now just cut the board to size and the fun really begins!

Populate the Board

Now we can add all our components to the board, and solder them in place. As we have no solder mask or tin on our board we need to ensure any flux residue is removed post soldering (acetone or warm water), so we left our board to dry overnight....

We realised we had missed a resistor at this point, but its on the Nano itself so we added it now between D2 and D9. This gives us controllable feedback for our lights.

Now we can solder our LEDs together, and add wires to them, and to our speaker. Then solder the other ends to the relative connections on the board

The Black lead is due to a soldering fail on my part, the board tracks are there for this!

The Code

At this point we just had to put the code together to make all of this work as expected, and this is included in the files at the bottom.

Rename any WAV files or pin assignments depending on your implementation.

Try it out at this point, its far easier to fix before its attached to a toaster!

The Other Physical Parts

At this point we wanted to attach ours to our toaster of choice, and add a speaker cover fitting of the project, so we 3D Printed a cover, and spray painted it (didn't have any orange plastic).

We used an old plastic milk bottle to cut out the windows, and super glue to attach them to the speaker cover.

Then gluing some magnets on the back meant it would stick to the toaster, but could be removed from the toaster easily if needed.

Then we just attached our speaker and LED inside using a double sided foam pad on the back of the speaker, to the centre of our cover.

Some sticky foam pads allowed us to attach the board to the bottom of the toaster, giving the final toaster!

A short clip of its favourite phrase....

Visual Micro Website

AVR WAV/PCM Audio Library for SD Playback

Audacity

Code

TalkieToaster.inoArduino
Main code file to run the project.....
/*

Lib: https://github.com/TMRh20/TMRpcm

Talkie made by Crapola Inc --> https://reddwarf.fandom.com/wiki/Crapola_Inc.

STL File for Block Lever for a Toaster (Talkie v1 needs two block ones)
https://www.thingiverse.com/thing:63723

Episodes Talkie is in: https://reddwarf.fandom.com/wiki/Talkie_Toaster
V1 Talkie:
In 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.
In "Balance of Power", Series I - Lister eats Krispies and converses with Talkie Toaster in the sleeping quarters of Red Dwarf
In 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.)
V2 Talkie:
In 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.

Nano - Arduino Pins
SD Card
13 sck
12 miso
11 mosi
10 cs

3  2x10mm LED to sync with sound
4 PIR input
5 Mic Input for Listenting for replies
9 Speaker output, to amplifier


*/


#include <SPI.h>
#include <TMRpcm.h>     
#include <pcmRF.h>
#include <pcmConfig.h>
#include <SD.h>

#define SD_CARD 10  

TMRpcm sample;

// PIR sensor
int calibrationTime = 10;
				
long conversationQuitUs = 60000; // If no-one continues within a minute - quit conversation
long conversationStartTime = 0;
int pirPin = 4;    // PIR sensor input
int micPin = 5;    // Mic sensor Input
int ledPin = 3;    // LED outputs 
int speakerInputPin = 2; // Feeback from output of speaker for LEDs....

char* currentPlaylist = "1";
int currentTrack = 0;
boolean triggered = false;
boolean pirTriggered = false;
boolean micTriggered = false;
boolean talking = false;


/* Sound Files:
1-0_1.wav			Talkiev1 - 1 - You Cant Sing
1-0_2.wav			Talkiev1 - 2 - Just cos Im a Toaster
1-0_3noBang.wav			Talkiev1 - 3 - Sings Sinatra (no  Bang)
1-0_3withBang.wav			Talkiev1 - 3 - Sings Sinatra (with Bang)

2-0_1.wav			Talkiev2 - 1 - Intro
2-0_2.wav			Talkiev2 - 2 - How About a Muffin
2-0_3.wav			Talkiev2 - 3 - Waffle Man
2-0_4.wav			Talkiev2 - 4 - Can I ask One Question
2-0_5.wav			Talkiev2 - 5 - Any Toast
2-0_6.wav			Talkiev2 - 6 - Changed Your Mind
2-0_7.wav			Talkiev2 - 7 - I Toast Therefore I Am
2-1_1.wav			Talkie v2.1 - 1 - Hope You don't get an overload

2-1_2.wav			Talkie v2.1 - 2 - Youll Explode
2-1_4.wav			Talkie v2.1 - 4 - Any Question
2-1_5.wav			Talkie v2.1 - 5 - Any Question
2-1_6.wav			Talkie v2.1 - 6 - Ok Heres my Question
2-1_7.wav			Talkie v2.1 - 7 - Chaos Theory
2-1_8.wav			Talkie v2.1 - 8 - Would you like a Crumpet
2-1_9.wav			Talkie v2.1 - 9 - That is not answering
2-1_10.wav			Talkie v2.1 - 10 - A Sensible Question
2-1_11.wav			Talkie v2.1 - 11 - Resent Implication
2-1_12.wav			Talkie v2.1 - 12 - God Toasted Teacake
2-1_13.wav			Talkie v2.1 - 13 - Before You go
2-1_14.wav			Talkie v2.1 - 14 - Cheese and Ham Braville
*/

char* playlist[22][3] = {
	{"1","0","1-0_1.wav" },
	{"1","0","1-0_2.wav" },
	{"1","0","1-0_3wb.wav" },
	// {"1","1","1-0_3wb.wav" },
	{"2","0","2-0_1.wav" },
	{"2","0","2-0_2.wav" },
	{"2","0","2-0_3.wav" },
	{"2","0","2-0_4.wav" },
	{"2","0","2-0_5.wav" },
	{"2","0","2-0_6.wav" },
	{"2","0","2-0_7.wav" },

	{"3","0","2-1_1.wav" },
	{"3","0","2-1_4.wav" },
	{"3","0","2-1_5.wav" },
	{"3","0","2-1_6.wav" },
	{"3","0","2-1_7.wav" },
	{"3","0","2-1_8.wav" },
	{"3","0","2-1_9.wav" },
	{"3","0","2-1_10.wav" },
	{"3","0","2-1_11.wav" },
	{"3","0","2-1_12.wav" },
	{"3","0","2-1_13.wav" },
	{"3","0","2-1_14.wav" }
};


void setup()
{
	
	// randomiser for speech output, using an unused pin (!)
	randomSeed(analogRead(2));
	Serial.begin(9600);
	music_setup();
	pinMode(pirPin, INPUT);
	pinMode(micPin, INPUT);
	pinMode(ledPin, OUTPUT);
	digitalWrite(ledPin, HIGH);
	delay(1000);
	digitalWrite(ledPin, LOW);
	Serial.println(" Done");
}

bool micHeard = false;
long micLastHeard = 0;
bool lastMicRead = false;

bool pirRead = false;
bool lastPirRead = false;
long pirLastLow = 0;
bool pirEnabled = false;

void loop()
{
	// Ensure someone has gone away before triggering PIR (otherwise convesations can bleed together)
	pirRead = digitalRead(pirPin);
	if (pirRead != lastPirRead) {
		if (!pirRead) {
			pirLastLow = millis();
		}
		lastPirRead = pirRead;
	}

	if (pirRead && (millis() - pirLastLow) > 5000 && pirLastLow != 0) {
		Serial.println("PIR ENABLED");
		pirLastLow = 0;
		pirEnabled = true;
	}

	pirEnabled = true;
	byte micRead = 0;
	if (pirEnabled) {
		pirTriggered = digitalRead(pirPin);
		micRead = !digitalRead(micPin);
	
	// Debounce our mic so have to hear silence for a second...
	if (micRead != lastMicRead) {
		if (micRead) {
			micLastHeard = millis();
		}
		lastMicRead = micRead;
	}

	if (!micRead && (millis() - micLastHeard) > 875 && micLastHeard != 0) {
		Serial.println("MIC TRIGGER");
		micLastHeard = 0;
		micTriggered = true;
	}


	// Assess triggers depending on state:
	// if Heard something, didnt see anyone, and not talking - do nothing
	if (micTriggered && !talking) {
		micTriggered = false;
		triggered = false;
	}

	// If saw someone and not talking - start a conversation
	if (pirTriggered && !talking) {
		triggered = true;
		pirTriggered = false;
		micTriggered = false;
	}

	// if heard someone and already talking - continue conversation
	if (micTriggered && talking) {
		triggered = true;
		micTriggered = false;
		pirTriggered = false;
	}



	// playtime
	if (triggered)
	{
		if (!talking) { // See if a new conversation
			conversationStartTime = millis();
			talking = true;
			Serial.print("Now Talking\t");
		}
		// Play next in current conversation
		playFullSample(playlist[currentTrack][2], playlist[currentTrack][1]);
		Serial.print("Playing Track:");
		Serial.print(playlist[currentTrack][2]);
		// Move On.....
		currentTrack = (currentTrack + 1) % 22;
		Serial.print("\tNextId:");
		Serial.println(currentTrack);

		// set talking = false at end of convo.... if we have reached it
		if (currentPlaylist != playlist[currentTrack][0]) {
			talking = false;
			Serial.print("Last in Conversation");
			pirEnabled = false;
		}
		currentPlaylist = playlist[currentTrack][0];		

		triggered = false;

	}
	}
	else {
		// If Im left alone too long I give up....
		if ((millis() - conversationStartTime) > conversationQuitUs) {
			talking = false;
			triggered = false;
			pirEnabled = false;
			if (currentPlaylist == "1") {
				currentPlaylist = "2";
			} else if (currentPlaylist == "2") {
				currentPlaylist = "3";
			}
			else if(currentPlaylist == "3") {
				currentPlaylist = "1";
			}
			
			currentPlaylist = "1";
			currentTrack = 0;
		}
	}
	
}


// Setup for Music 
void music_setup() {
	// see if the card is inserted and found
	if (!SD.begin(SD_CARD))
	{
		return;   // It's not there, don't do anything
	}
	Serial.println("SD card started");
	// speaker pin output 
	sample.speakerPin = 9;
	// quite loud
	sample.volume(9);
	sample.quality(1);
	sample.disable();
}

// This method plays files of any length....
	// See docs https://github.com/TMRh20/TMRpcm/wiki
// Play whole track but ensure that we flash our LED with the speaker PWM
// and can adjust to get what "feels" better to see
void playFullSample(char* sampleName) {
	playFullSample(sampleName, false);
}

void playFullSample(char* sampleName, char* stopOnMicTrigger) {
	sample.play(sampleName);
	boolean micHeard = false;
	while (sample.isPlaying() && !micHeard) {

		// never actually used this to detect the bang....
		if (stopOnMicTrigger == "1") {
			if (digitalRead(micPin) == HIGH) {
				micHeard = true;
			}
		}
		
		int duration = pulseIn(speakerInputPin, 500); // Allow 1ms before quitting
		int brightness = map(duration, 0, 15, 0, 255);
		if (brightness < 200) { // flatten lower values to 0, so visible changes in brighness
			brightness = 0;
		}
		//Serial.println(duration);
		analogWrite(ledPin, brightness);
		delay(brightness);
	}
	analogWrite(ledPin, 0);
	sample.disable();
}

Custom parts and enclosures

Speaker Cover
STL File for 3D Printing Speaker Cover Frame (quick design)
Supports: Yes
Infill: 20%

Schematics

Image of PCB Design
Just an image to show the PCB design, read tutorial for where current issues had to be worked around.
Pcb design x0hhcit4qp

Comments

Similar projects you might like

IoT Using ESP8266-01 and Arduino

Project tutorial by Ahmed Ibrahim Ahmed

  • 9,061 views
  • 11 comments
  • 45 respects

Arduino Nano 33 IoT Debugging

Project tutorial by visualmicro

  • 3,381 views
  • 3 comments
  • 12 respects

IoT Blink - Getting started with IoT

Project showcase by AppShed Support

  • 4,893 views
  • 1 comment
  • 22 respects

Cayenne and SparkFun IoT 433 Mhz Sockets

Project tutorial by Giovanni Gentile

  • 2,503 views
  • 0 comments
  • 13 respects

Octopod: Smart IoT Home/Industry Automation Project

Project tutorial by Saksham Bhutani

  • 13,403 views
  • 11 comments
  • 44 respects

Christmas Card PCB

Project tutorial by visualmicro

  • 709 views
  • 0 comments
  • 2 respects
Add projectSign up / Login