Introduction: Talking Washing Machine Interface for the Blind AKA 'SOAP'

About: IT Manager and CAD Designer with a keen interest in technology for the visually impaired.

The Short Version...

A recently purchased washing machine proved to be unusable to my wife, Sue, who is totally blind. Standard tactile markings did not work due to the use of LEDs to indicate the current wash programme. The LEDs do not have a fixed relationship to the selector control knob.

This Instructable describes the design and construction of a device that detects the currently illuminated LED and plays a recorded audio clip announcing the wash programme.

We have christened the device with the acronym 'SOAP' - Speech Output Announcing Programmes.

SOAP is non-invasive and requires no electrical connection to the washing machine.

This was my Grand Prize winning entry in the Arduino Contest 2019. Many thanks to everyone who voted from Pete (Wingletang), Sue and Milly!

Step 1: Detailed Description of the Problem

As Sue is totally blind we have to make sure that all of the equipment we purchase can be made accessible to her by tactile markings or audio feedback

Recently we purchased a Samsung Eco Bubble 8.0Kg washing machine. We chose this model as it is one of the few that still features a physical wash programme selector knob. Usually machines with this style of selector can be made accessible to the blind by the use of small adhesive rubber bumps called 'Bumpons' - one is attached to the knob as a pointer and others are placed at the locations of the different wash programmes. A simple code can be used - for example, one bump for 'Cotton', two bumps for 'Synthetics'. The operator then can select the right programme by lining up the pointer and the other bumps.

Unfortunately, after a few days it became apparent that Sue was not selecting the correct wash programmes.

The machine uses LEDs around the selector knob to indicate the currently selected programme. If the knob is rotated when the machine is off, the next time it is turned on the illuminated programme is still the last one that had been run to conclusion or part way through. Also, whilst the angular rotation of the knob is always the same from one programme to the next, the angular jump of the illuminated LED is not (the wash programmes are not spaced equally around the control due to a gap at the bottom).

Another problem is that there is no 'stop' to the rotation of the knob.

The Bumpons can thus become quickly misaligned, hence Sue's selection of the wrong programmes. See the attached video for a demonstration of this problem.

How to make the machine accessible by someone with no sight? Sue asked 'Why not make it speak?', and that is how 'SOAP' was born, a talking washing machine interface for the blind.

Step 2: Introduction to SOAP - Speech Output Announcing Programmes

SOAP consists of three basic components:

1. A ring shaped sensor consisting of 14 Light Dependent Resistors (LDRs) that is fastened to the washing machine to detect which one of the 14 wash programme LEDs is illuminated.

2. The 'Chatterbox' - this plays a recorded audio clip announcing the selected wash programme as detected by the sensor. The Chatterbox is mounted on a cupboard adjacent to the washing machine.

3. A ribbon cable connecting the sensor and Chatterbox.

The Chatterbox is not mounted on the washing machine due to space restrictions and to avoid the problem of vibration.

Light detection is used (rather than direct connection to the washing machine LEDs) so the system is safe, non-invasive and does not invalidate the warranty.

Whilst SOAP is designed specifically for a particular model of washing machine, the Chatterbox could be used with different sensors to make other appliances accessible to the visually impaired.

View the video for a demonstration of SOAP in action.

Step 3: SOAP - Schematic

The circuit of SOAP is shown above.

Each LDR is connected to 0V and to +5V via a dropper resistor. The connection point between the LDR and the resistor is connected to an input on the UNO R3. The values of the resistors were determined by experiment so that an illuminated LDR results in a voltage below 3V at the UNO input, while an LDR in darkness gives rise to a voltage of more than 3V.

14 inputs to the UNO R3 were required. This was achieved by using digital inputs D2 to D9 and analogue inputs A0 to A5. The analogue inputs are configured to operate as digital inputs.

The audio output is produced by a Velleman KA02 Audio Shield.

The unit is powered by a PP3 9V battery via a latching pushbutton. The UNO R3 code runs as soon as power is applied.

The resistors and LDRs are numbered to match the wash programme numbers.

Note that all of the drawings in this Instructable are also contained in the multi-page PDF attached.

Step 4: SOAP - General Arrangement

The photograph shows all of the components of SOAP connected together without the box and sensor covers.

The ribbon cable is 16 way with header plugs at both ends. 14 conductors are connected to the LDRs, and the other 2 are used for 0V.

Step 5: The Sensor - Overview and Materials

Sensor Overview

The core of the sensor is constructed from two pieces of stripboard - the Ring Board and the Support Board. These are joined together electrically and mechanically at the correct angle to position and fix the LDRs in close proximity to the washing machine LEDs.

The overall design of the sensor is shown in the diagram.

Materials

Stripboard: 95mm wide x 220mm long (strips running along the length)

14 off Light Dependent Resistors (LDRs) type 5537

Black 1.5mm Plasticard

1 off 16 Way, 2 Row, Right Angle PCB Header

A4 Double-Sided adhesive film sheets

3 tubular plastic cotton bud stems.

Black, dense foam rubber: 95mm wide x 5.5mm thickness. I sourced this from a discarded mouse mat.

Step 6: The Sensor - Ring Board

Sensor Ring Board

Cut the stripboard to a length of 118mm.

Drill a small pilot hole 47.5mm from one end of the stripboard, centred across the width. This is centred between 4 existing holes.

Using this hole as the centre, cut the end of the strip board into a 95mm diameter semi-circle. I used a compass cutter. Score the stripboard from both sides until the board can be neatly broken away.

Using the same centre hole, cut a 58mm diameter circle from the stripboard. This is a sliding fit over the washing machine selector knob.

Cut the strips at the two locations shown in diagram.

Next, install the LDRs: Cut the cotton bud stems into 28 off 3mm tubes. These are used to space the LDRs from the stripboard. Thread a spacer on to each leg of an LDR before soldering it in place as shown in the photographs.

Populate the board with all jumper wires.

Step 7: The Sensor - Support Board

Sensor Support Board

This is a rectangular board that provides mechanical support and electrical connections to the sensor ring board. It includes a 16 pin right angled PCB header for connection of the ribbon cable to the Chatterbox.

Cut the board to a length of 97mm

Cut the strips at the eight locations shown in the diagram. These electrically separate the two rows of eight pins of the right angled header. I used a scalpel to carefully cut the copper strips as these were between adjacent holes in the board.

Fix the header in position with a small amount of Superglue and solder the pins.

Populate the board with all jumper wires.

Step 8: The Sensor - Final Assembly

Assembling the Sensor

The Ring Board and Support Board must now be joined together, mechanically and electrically.

Note that the copper strips on the ring board are on the outside whilst those on the support board are on the inside - see photographs.

Links consisting of short lengths of stiff wire are used to interconnect the boards along the 'hinge'. Initially solder just two such links at the outermost strips. These links provide the initial mechanical connection.

The sensor must be made as light-tight as possible to prevent stray light reaching the LDRs. To achieve this, cut the black foam rubber into three light shields / vibration absorbers as shown in the photograph. These are the same shape and dimensions of the two boards. The 'ring board inner' has a circular hole of a slightly larger diameter than the LDR circle. The 'ring board outer' has a circular hole slightly larger than the washing machine control knob.

Temporarily attach the foam rubber shields with double sided tape to the boards. Place the sensor with on the washing machine and adjust the angle between the boards by carefully bending the hinge until the support board lies horizontally on the top of the machine and the LDRs are correctly aligned over the LEDs. Small adjustments to the LDR positions can be made by carefully bending the legs of the LDRs.

Remove the foam shields.

Install the 16 electrical links being careful not to change the angle between the boards. These are 'back soldered' on the ring board and 'front soldered' on the support board.

Once complete, attach the foam shields permanently using the double sided adhesive film, cutting this to the same shape and size as the shields.

Sensor cover

A front cover for the sensor is cut from the black Plasticard and carefully bent into shape using a heat gun to soften the plastic along the bend location. Attach this to the sensor using double-sided adhesive film on the ring board front shield and by gluing to the right angle header.

Use black insulating tape to cover the edges of the sensor.

Attach the sensor firmly to the washing machine using double sided adhesive film cut to the shape of the foam rubber inners.

Future development could include a 3D printed cover for the sensor.

Step 9: Light Tight Control Knob Cover

The control knob on the washing machine is constructed from a transparent material. Early tests indicated that stray light passing through this caused false triggering of the sensor.

To overcome this, a light-tight control knob cover was constructed as follows:

The lid from an empty 125g tub of E45 skin cream proved to be of a suitable size ('Trash to Treasure' anyone?!).

As this is white I made it light tight by lining it with a disk of black Plasticard and a ring of dense black foam rubber. These were both cut out using the compass cutting tool.

The disk was fixed inside the lid using a disk of double sided adhesive film.

The foam ring fitted tightly over the programme selector knob so did not need adhesive.

The complete assembly is attached to the washing machine control knob using a disk of double sided adhesive film.

Step 10: Test and Simulation Board

A small test and simulation board was constructed as shown in the diagram.

This has two functions:

1. When connected to the sensor via the ribbon cable, the resistance of each LDR can be measured with the related wash programme LED on and off.

2. When connected to the Chatterbox via the ribbon cable, the playing of each audio clip can be triggered by grounding the relevant test pin.

Cut the strips at the eight locations shown in the diagram. These electrically separate the two rows of eight pins of the 16 way PCB header. I used a scalpel to carefully cut the copper strips as these were between adjacent holes in the board.

Populate the board with the jumpers, 16 way PCB header and header pins.

Note that the test pins are numbered with the Wash Programme numbers.

Step 11: Testing the Sensor - Determining the Resistor Values

The ribbon cable is connected to the sensor (which is now fixed in position on the washing machine).

The test board is connected to the other end of the ribbon cable.

14 of the conductors carry the signals from the LDRs while the remaining 2 conductors are used for the 0V ground connection.

With the washing machine turned on, the resistance of each LDR is measured with a multimeter as the relevant wash programme LED is on or off. The table of results is shown in the diagram.

During the tests it was clear that two of the LDRs gave very different resistance readings from the others. This could have been because they were of a different type. The LDRs did not have identifying markings to confirm this.

As it would have been difficult to remove and dismantle the sensor, I decided to sidestep the problem by selecting suitable dropper resistors. The values had to result in a voltage at the UNO R3 of less than 3V when the LDR was illuminated, and more than 3V when it was in darkness.

Suitable standard resistor values were found to be 12 x 100k Ohm and 2 x 470k Ohm.

Step 12: The Interface Board

The interface board contains all of the dropper resistors and connectors for the ribbon cable and the interconnection loom.

The board is made from a piece of stripboard 86mm x 46mm.

Cut the strips at the eight locations shown in the diagram. These electrically separate the two rows of eight pins of the 16 way PCB header. I used a scalpel to carefully cut the copper strips as these were between adjacent holes in the board.

Construct the interface board using the values of resistors determined in the sensor tests (12x100K and 2x470K).

Populate the board with the jumpers, 16 way PCB header and header pins.

Note that the resistors and connection pins are numbered in the diagram to match the wash programme numbers.

Step 13: The Chatterbox - Part 1

Overview

The Chatterbox is based on an Elegoo Uno R3 microcontroller (Arduino compatible) and a Velleman KA02 Audio Shield. Fourteen short audio clips are stored in the KA02, each being the number and name of one of the wash programmes. When one of fourteen inputs to the Uno R3 is triggered, the related audio clip is selected and played through a speaker.

As this was my very first microcontroller project I purchased a starter kit containing an Elegoo Uno R3 along with a comprehensive selection of sensors, actuators, components and interconnections. This included a set of 'Dupont' wires featuring sockets and pins to connect to PCB pins and sockets - these proved to be very useful in making the interconnection loom and speaker wires: Elegoo UNO R3 Starter Kit.

Materials

Elegoo Uno R3 microcontroller (Arduino compatible).

Velleman KA02 Audio Shield for Arduino.

Plastic enclosure 90mm x 50mm x 160mm.

8 Ohm loudspeaker (2" diameter).

9V battery clip.

Interface board constructed in previous step.

Latching on/off button.

White Plasticard.

Dense foam rubber (sourced from various items of packaging).

Step 14: The Chatterbox - Part 2 - Velleman KA02 Audio Shield for Arduino - Recording the Audio Clips

This was purchased as a kit: CPC - KA02 Audio Shield

It is a digital recorder / playback device based on the ISD1700PY chipcorder.

The board has a built-in microphone to record messages. The shield has a 60 second total recording time and can be rewound, fast forwarded, and erased using small push buttons on the board. In this project, playback is via a speaker.

It uses the ICSP pins on an Arduino as a serial connection to the shield.

It also uses pin 10 on the Uno R3 board for control.

The selection and playback of audio recordings can also be controlled by a microcontroller, in this project the Elegoo Uno R3.

The construction manual for the KA02 including the full circuit diagram is available from the Velleman web site: Velleman KA02 Assembly Manual

Preparation

Assemble the KA02 kit and fit it to the Uno R3.

Connect the 8Ohm speaker to the audio board. I used two cut 'Dupont' wires that feature sockets that connect to the KA02 speaker pins.

Connect a USB cable to the Uno R3 and to a PC (to provide power to the Uno R3 and KA02).

Recording the Audio Clips

Using the on board microphone and the control push buttons record the audio clips as follows:

1. Press and hold the record button.

2. Say the first clip ("1 Cotton").

3. Release the record button.

4. To check the clip press the play button.

5. If not happy with the clip, repeat from step 1.

6. If all is OK, press the forward button to go to the second recording slot.

7. Press and hold the record button.

8. Say the second clip ("2 Eco Cotton")

9. Release the record button.

10. To check the clip press the play button.

11. If not happy with the clip, repeat from step 7.

12. If all is OK, press the forward button.

Repeat until all 14 audio clips have been recorded. The total available recording time is one minute.

Step 15: The Chatterbox - Part 3 - Setting the Audio Clip Addresses

The audio clips are stored in a continuous block of memory on the KA02 from address 0x010 to 0x2DF as shown in the diagram. It is necessary to determine the start and end addresses of each clip.

The example KA02 sketch downloaded from www.velleman.be was adapted to allow each of the 14 audio clips to be played. The resulting ino file is attached.

//Set Audio Clip Addresses

#include <ISD1700.h> // Library for Audio Shield (downloaded from Velleman website)

ISD1700 chip(10); // Initialize chipcorder with
                  // SS at Arduino's digital pin 10
int apc=0;
int vol=0;  //volume 0=MAX, 7=min
int startAddr=0x10;
int endAddr  =0x2DF;
//Set Wash Programme Audio Clips start and end addresses
//Wash Programme 1 Cotton
int startAddr1=0x010;
int endAddr1  =0x020;
//Wash Programme 2 Eco Cotton
int startAddr2=0x025;
int endAddr2  =0x03E;
//Wash Programme 3 Synthetics
int startAddr3=0x03F;
int endAddr3  =0x054;
//Set message start and end addresses
//Wash Programme 4 Wool
int startAddr4=0x056;
int endAddr4  =0x066;
//Wash Programme 5 Spin
int startAddr5=0x068;
int endAddr5  =0x078;
//Wash Programme 6 Rinse + Spin
int startAddr6=0x078;
int endAddr6  =0x090;
//Wash Programme 7 Eco Drum Clean
int startAddr7=0x090;
int endAddr7  =0x0AE;
//Wash Programme 8 Super Eco Wash
int startAddr8=0x0AE;
int endAddr8  =0x0CE;
//Wash Programme 9 15' Quick Wash
int startAddr9=0x0CE;
int endAddr9  =0x0EE;
//Wash Programme 10 Daily Wash
int startAddr10=0x0EE;
int endAddr10  =0x105;
//Wash Programme 11 Delicates
int startAddr11=0x105;
int endAddr11  =0x120;
//Wash Programme 12 Dark Garment
int startAddr12=0x123;
int endAddr12  =0x133;
//Wash Programme 13 Bedding
int startAddr13=0x136;
int endAddr13  =0x148;
//Wash Programme 14 Baby Care
int startAddr14=0x149;
int endAddr14  =0x167;</p><p>void setup()
{
  apc = apc | vol;  //D0, D1, D2
  
  //apc = apc | 0x8;    //D3  comment to disable output monitor during record
  
  //apc = apc | 0x50;    // D4& D6  select MIC REC
  //apc = apc | 0x00;      // D4& D6  select AnaIn REC
  //apc = apc | 0x10;    // D4& D6  select MIC + AnaIn REC
  
  apc = apc | 0x80;    // D7   AUX ON, comment enable AUD
  
  apc = apc | 0x100;     // D8   SPK OFF, comment enable SPK
  
  //apc = apc | 0x200;   // D9   Analog OUT OFF, comment enable Analog OUT
  
  //apc = apc | 0x400;   // D10  vAlert OFF, comment enable vAlert
  
  apc = apc | 0x800;     // D11 EOM ON, comment disable EOM
  
   
  Serial.begin(9600);
  Serial.println("Sketch is starting up");
}
void loop()
{
  char c;
  
  if(Serial.available())
  {
    /* Power Up */
    chip.pu();
    c = Serial.read();
    switch(c)
    {
         case 'A':
         Serial.println(chip.rd_apc(), BIN);
         break;        
       case 'Y':  //Play current message
         chip.play();
         break;
       case 'P':  //Pause playing
         chip.stop();
         delay(500);
         break;
       case 'E':  //Erase current message
         chip.erase();
         delay(500);
         break;
       case 'R':  //Record
         chip.rec();
         break;
       case 'F':  //Move forward to next message
         chip.fwd();
         delay(500);
         break;
       case 'Z':  //Global erase all messages
         chip.g_erase();
         delay(500);
         break;
       case 'I':  //Print Chip ID
         Serial.println(chip.devid(), BIN);         
         break;
       case 'W':  
         Serial.println(apc, BIN);
         chip.wr_apc2(apc);  //Print APC2 bits
         break;
       case 'S':  
         Serial.println(chip.rd_status(), BIN); //Print chip status
         break;      
       case 'm':
         while (Serial.available() <= 0) 
         {
           delay(300);
         }
         c = Serial.read()-48;   
         mess(c);
         break;  
       case 'y':
         chip.set_play(startAddr,endAddr);
         break;
       case 'r':
         chip.set_erase(startAddr,endAddr);
         delay(500);
         chip.set_rec(startAddr,endAddr);
         break;
       case 'x':
         chip.set_erase(startAddr,endAddr);
         delay(500);
         break;</p><p>//Play Wash Programme Messages
         
       case '1':
           chip.set_play(startAddr1,endAddr1); // Set correct start and end address for the relevant audio clip
           chip.play();                        // Play the clip
           break;
        case '2':
           chip.set_play(startAddr2,endAddr2);
           chip.play();
        break;
         case '3':
           chip.set_play(startAddr3,endAddr3);
           chip.play();
         break;  
         case '4':
           chip.set_play(startAddr4,endAddr4);
           chip.play();
         break;  
         case '5':
           chip.set_play(startAddr5,endAddr5);
           chip.play();
         break;     
         case '6':
           chip.set_play(startAddr6,endAddr6);
           chip.play();
         break;
         case '7':
           chip.set_play(startAddr7,endAddr7);
           chip.play();
         break;
         case '8':
           chip.set_play(startAddr8,endAddr8);
           chip.play();
         break;
         case '9':
           chip.set_play(startAddr9,endAddr9);
           chip.play();
         break;
         case 'a':
           chip.set_play(startAddr10,endAddr10);
           chip.play();
         break;
         case 'b':
           chip.set_play(startAddr11,endAddr11);
           chip.play();
         break;
         case 'c':
           chip.set_play(startAddr12,endAddr12);
           chip.play();
         break;
         case 'd':
           chip.set_play(startAddr13,endAddr13);
           chip.play();
          break;
          case 'e':
           chip.set_play(startAddr14,endAddr14);
           chip.play();
          break;
         
         
    }
    Serial.print("Status---> ");
    Serial.print(chip.CMD_ERR()? "CMD_ERR ": "OK ");
    Serial.print(chip.PU()? "PU ": "NO PU ");
    Serial.print(chip.RDY()? "RDY ": "Not_RDY ");
    Serial.print(chip.rd_status(), BIN);
    Serial.println();
    delay(1000);
  }
}
void mess(int num){
  Serial.print("num: ");
  Serial.println(num);
  startAddr=(0x50*num)+0x10;
  endAddr=(startAddr+0x50)-1;
  Serial.print("startAddr: ");
  Serial.print(startAddr, HEX);
  Serial.print(" - endAddr: ");
  Serial.println(endAddr, HEX);
  
}

The addresses are determined as follows:

The KA02 / UNO R3 is connected via a USB lead to a PC running Arduino.

1. The sketch is uploaded to the UNO R3.

2. In the Arduino Serial Monitor type 1 and press enter.

3. The first audio clip should play. Note if the whole clip and nothing else is played.

4. If not, adjust the start and end addresses of the first clip in the sketch (lines 14 and 15), upload the modified sketch to the UNO R3 and go back to step 2.

5. If all is OK, continue to the next step.

6. In the Arduino Serial Monitor type 2 and press enter.

7. The second audio clip should play. Note if the whole clip and nothing else is played.

8. If not, adjust the start and end addresses of the second clip in the sketch (lines 18 and 19), upload the modified sketch to the UNO R3 and go back to step 6.

9. If all is OK, continue to the next step.

Repeat this process until the addresses for clip 9 have been set.

For clips 10 to 14, instead of typing a number into the monitor, use the letters a to e.

Step 16: SOAP Code

The principle of the SOAP code is as follows:

1. Initialise variables including the start and end addresses of each audio clip.

2. Detect which wash programme LED is illuminated.

3. Set Start and End address for the audio clip associated with the selected wash programme.

4. Play the relevant audio clip.

5. Wait 3 seconds.

6. Repeat from step 2.

The Arduino ino file is attached. This should be uploaded to the UNO R3.

The code is as follows:

SOAP Arduino Code
// SOAP - Speech Output Announcing Programs
// Talking Washing Machine Interface for the Blind              
//                        
#include < ISD1700.h > // Library for Audio Shield (downloaded from Velleman website)


ISD1700 chip(10); // Initialise chipcorder with SS at Arduino's digital pin 10

//           
// Initialise Audio Shield variables             
int apc=0;              
int vol=0; //volume 0=MAX, 7=min              
int startAddr=0x10; //Start address of Audio Shield RAM              
int endAddr =0x2DF; //End address of Audio Shield RAM              
//             
//Set Wash Programme Audio Clips start and end addresses determined from tests        
int startAddr1=0x010; int endAddr1 =0x020; //Wash Programme 1 Cotton              
int startAddr2=0x025; int endAddr2 =0x03E; //Wash Programme 2 Eco Cotton              
int startAddr3=0x03F; int endAddr3 =0x054; //Wash Programme 3 Synthetics              
int startAddr4=0x056; int endAddr4 =0x066; //Wash Programme 4 Wool              
int startAddr5=0x068; int endAddr5 =0x078; //Wash Programme 5 Spin         
int startAddr6=0x078; int endAddr6 =0x090; //Wash Programme 6 Rinse + Spin              
int startAddr7=0x090; int endAddr7 =0x0AE; //Wash Programme 7 Eco Drum Clean              
int startAddr8=0x0AE; int endAddr8 =0x0CE; //Wash Programme 8 Super Eco Wash              
int startAddr9=0x0CE; int endAddr9 =0x0EE; //Wash Programme 9 15 Minute Quick Wash              
int startAddr10=0x0EE; int endAddr10 =0x105; //Wash Programme 10 Daily Wash              
int startAddr11=0x105; int endAddr11 =0x120; //Wash Programme 11 Delicates              
int startAddr12=0x123; int endAddr12 =0x133; //Wash Programme 12 Dark Garment              
int startAddr13=0x136; int endAddr13 =0x148; //Wash Programme 13 Bedding              
int startAddr14=0x149; int endAddr14 =0x167; //Wash Programme 14 Baby Care              
//             
const int inputPin2 = 2; // Digital inputs. DI 10 used by Audio Shield so cannot be used for sensor input              
const int inputPin3 = 3;              
const int inputPin4 = 4;              
const int inputPin5 = 5;              
const int inputPin6 = 6;              
const int inputPin7 = 7;              
const int inputPin8 = 8;              
const int inputPin9 = 9;              
const int inputPinA0 = 14; //Analogue inputs used as Digital Inputs              
const int inputPinA1 = 15;              
const int inputPinA2 = 16;              
const int inputPinA3 = 17;              
const int inputPinA4 = 18;              
const int inputPinA5 = 19;              
//             
// Define variables        
// for storing the state of the inputs             
// Inputs initialised HIGH as sensor input pulls the input LOW             
int inputState_Baby_Care = 1;              
int inputState_Eco_Drum_Clean = 1;               
int inputState_Rinse_and_Spin = 1;              
int inputState_Spin = 1;              
int inputState_Wool = 1;              
int inputState_Cotton = 1;              
int inputState_Eco_Cotton = 1;              
int inputState_Synthetics = 1;              
int inputState_Daily_Wash = 1;              
int inputState_15_Minute_Quick_Wash = 1;              
int inputState_Super_Eco_Wash = 1;              
int inputState_Delicates = 1;              
int inputState_Dark_Garment = 1;              
int inputState_Bedding = 1;              
//        
//       
// Setup       
void setup()              
{              
//             
//Initialise Audio Shield              
apc = apc | vol; // D0, D1, D2              
apc = apc | 0x100; // D8 SPK OFF, comment enable SPK              
apc = apc | 0x800; // D11 EOM ON, comment disable EOM              
//
             
// initialize the pins as inputs:              
pinMode(inputPin2, INPUT);              
pinMode(inputPin3, INPUT);              
pinMode(inputPin4, INPUT);              
pinMode(inputPin5, INPUT);              
pinMode(inputPin6, INPUT);              
pinMode(inputPin7, INPUT);              
pinMode(inputPin8, INPUT);              
pinMode(inputPin9, INPUT);              
pinMode(inputPinA0, INPUT);              
pinMode(inputPinA1, INPUT);              
pinMode(inputPinA2, INPUT);              
pinMode(inputPinA3, INPUT);              
pinMode(inputPinA4, INPUT);              
pinMode(inputPinA5, INPUT);              
}              
//             
// Main Loop             
void loop()              
{              
 //             
chip.pu(); //Chip Power Up              
//
             
// Read the states of the inputs. Only one will be low:              
inputState_Baby_Care = digitalRead(inputPin2);              
inputState_Eco_Drum_Clean = digitalRead(inputPin3);              
inputState_Rinse_and_Spin = digitalRead(inputPin4);              
inputState_Spin = digitalRead(inputPin5);              
inputState_Wool = digitalRead(inputPin6);              
inputState_Cotton = digitalRead(inputPin7);              
inputState_Eco_Cotton = digitalRead(inputPin8);              
inputState_Synthetics = digitalRead(inputPin9);              
inputState_Daily_Wash = digitalRead(inputPinA0);              
inputState_15_Minute_Quick_Wash = digitalRead(inputPinA1);              
inputState_Super_Eco_Wash = digitalRead(inputPinA2);              
inputState_Delicates = digitalRead(inputPinA3);              
inputState_Dark_Garment = digitalRead(inputPinA4);              
inputState_Bedding = digitalRead(inputPinA5);             
//             
// Set correct start and end address for the relevant audio clip              
// based on which programme LED is illuminated              
// InputState is LOW for an illuminated LED             
if (inputState_Baby_Care == LOW)              
   {chip.set_play(startAddr14,endAddr14); }              
if (inputState_Eco_Drum_Clean == LOW)              
   {chip.set_play(startAddr7,endAddr7); }              
if (inputState_Rinse_and_Spin == LOW)              
   {chip.set_play(startAddr6,endAddr6); }              
if (inputState_Spin == LOW)              
   {chip.set_play(startAddr5,endAddr5); }              
if (inputState_Wool == LOW)              
   {chip.set_play(startAddr4,endAddr4); }              
if (inputState_Cotton == LOW)              
   {chip.set_play(startAddr1,endAddr1); }              
if (inputState_Eco_Cotton == LOW)              
   {chip.set_play(startAddr2,endAddr2); }              
if (inputState_Synthetics == LOW)              
   {chip.set_play(startAddr3,endAddr3); }              
if (inputState_Daily_Wash == LOW)              
   {chip.set_play(startAddr10,endAddr10);}              
if (inputState_15_Minute_Quick_Wash == LOW)              
   {chip.set_play(startAddr9,endAddr9); }              
if (inputState_Super_Eco_Wash == LOW)              
   {chip.set_play(startAddr8,endAddr8); }              
if (inputState_Delicates == LOW)              
   {chip.set_play(startAddr11,endAddr11); }              
if (inputState_Dark_Garment == LOW)              
   {chip.set_play(startAddr12,endAddr12); }              
if (inputState_Bedding == LOW)              
   {chip.set_play(startAddr13,endAddr13); }       
//        
{chip.play();} // Play the clip             
// 
             
delay(3000); //Wait 3 seconds before repeating loop              
//             
}

Step 17: Building the Chatterbox

The Chatterbox is constructed as follows:

Step 1: Drill one end of the plastic enclosure for the pushbutton and speaker 'grill'. The holes were laid out in an AutoCAD drawing and the final design was printed onto an adhesive label at full size. The label was attached to the box and the holes were drilled using a Dremel 4000 fixed to a Dremel bench stand.

Step 2: Cut a slot a few millimetres deep and slightly wider than the ribbon cable at the top of the opposite end of the box.

Step 3: Cut the ridge under the lid to match the ribbon cable slot. This is necessary so the lid can be fully screwed into position without crushing the ribbon cable.

Step 4: Construct the 'power loom' by soldering wires to the pushbutton, PP3 battery clip and the UNO R3 power plug. The latter was taken from a 'universal' laptop power supply kit as the correctly sized plug is right angled so it fits neatly in the Chatterbox. Take care to ensure the correct polarity of the power plug.

Step 5: The speaker connections are created from Dupont wires featuring suitable sockets for attachment to the KA02 speaker pins.

Step 6: Cut a divider from white Plasticard. This is cut to fit in the box firmly and has a corner cut off to allow wires to pass through.

Step 7: Install the speaker, pushbutton, power loom and the divider as shown in the photograph. The divider is slightly bowed by the speaker - this helps to keep the speaker in position. A piece of foam rubber is pushed between the speaker and the pushbutton to stop any sideways movement.

Step 8: Check that the wires pass under the cut corner of the divider.

Step 9: Cut a second divider. This also has a cut corner for the wires, but also has cut-outs for the UNO R3 USB socket and power plug.

Step 10: Install the second divider into the case routing the wires as shown in the photograph. The separation of the two dividers is the thickness of a PP3 battery as the gap forms the battery compartment.

Step 11: Cut a piece of dense white foam rubber to form the base of the battery compartment. A cut-out will also have to be made to accommodate the UNO R3 USB socket. Install the foam rubber between the dividers.

Step 12: Cut another piece of dense white foam rubber to fill the end section of the battery compartment. This will need a cut-out to accommodate the UNO R3 power plug. Install the foam rubber between the dividers.

Step 13: Temporarily attach the clip to the PP3 battery and install it in the battery compartment to ensure it is held firmly. The battery wires pass neatly under the battery. Adjust the foam rubber as necessary.

Step 14: The Velleman KA02 Audio Shield should be fitted to the Uno R3 as shown in the photograph.

Step 15: Temporarily install the UNO R3 / KA02 in the enclosure. The power plug should fit so that the UNO is held loosely in position. The speaker leads should be connected the to pins on the KA02. If all is well, disconnect the boards from the plug and leads and remove them from the enclosure.

Step 16: Using the Dupont wires from the Elegoo kit, fashion a 17 way interconnection loom.

Step 17: Connect the loom to the interface board as shown in the photograph.

Step 18: Connect the loom to one side of the KA02 / UNO R3 as shown. Take care that the connections are made to the correct pins.

Step 19: Connect the remaining connections of the loom to the other side of the KA02 / UNO R3 as shown. Take care that the connections are made to the correct pins. See the diagram for the interconnection details.

Step 20: Carefully fold the interconnection loom so that it fits neatly in the enclosure.

Step 21: Fit the whole assembly into the box.

Step 22: Connect the ribbon cable to the interface board, guiding the cable over the top of the board and into the slot cut in the top of the case. Some excess cable should be left in the gap between the interface board and the end of the box, forming a downward bend.

Step 23: Insert a piece of white foam rubber to hold the UNO R3 firmly against the side of the case. Insert another piece of foam rubber between the interface board and the end of the case to fix the ribbon cable in place. In this photograph the foam rubber between the speaker and the pushbutton can also be seen.

Step 24: Screw the lid into place, being careful not to crush the ribbon cable.

The Chatterbox is complete!

Step 18: Testing the Chatterbox

Connect the Chatterbox to the test board using the ribbon cable.

Turn the box on.

Connect a test pin to the 0V pin. Note that the pins are numbered in the diagram to match the wash programme numbers. The relevant audio clip should play, repeating every 3 seconds.

Test all clips in this way.

Turn the box off.

If all is well, mount the Chatterbox in the required location. This will require some dismantling of the Chatterbox to allow mounting holes to be drilled in locations that do not foul the internal components.

Step 19: Completing the Installation

The first photograph shows the three mounting holes with suitable nuts glued in position.

Mounting holes are drilled through the cabinet and bolts used to mount the Chatterbox.

Carefully connect the ribbon cable to the sensor.

The ribbon cable is fixed underneath the worktop above the washing machine ensuring there is slack to take account of washing machine movement and vibrations.

SOAP is now complete!

Step 20: Final Thoughts...

SOAP has been in use for almost a year with no sign of the battery dying. As SOAP is only powered up for a few minutes each day, the battery should last a good while yet.

The system has proved to be reliable and has helped Sue to retain her independence, an important consideration for any blind person. Watch the video to see her using SOAP.

SOAP has been thoroughly 'Lab' tested by Guide Dog Milly, a pure black Labrador - see attached photos. Milly would be known as a Seeing Eye Dog in the USA.

I would love to see other Instructables describing novel devices for the visually impaired, maybe using elements of this project.

All of the diagrams in this Instructable were created using AutoCAD 2019 LT.

This was my entry in the Arduino contest - and it won the Grand Prize! Many thanks to everyone that kindly decided to Vote for SOAP!

Arduino Contest 2019

Grand Prize in the
Arduino Contest 2019