Der sprechende Farbdetektor mit DFPlayer und TCS3200 - [Teil 1]

Introduction

In this blog series I would like to build a simple talking color detector with you. Such devices are often used by people with visual impairment. It will allow you to recognize e.g. the color of clothing in the wardrobe.

We want to construct a device that can be held on a color area and then the color is output as a spoken text by pressing a button. In the first part, we commission the MP3 player for voice output and include a button for the mode change, as well as a potentiometer for the volume change. Here we go.

Required hardware

number Component annotation
1 TCS3200 color sensor module (in the second part)
1 DFPlayer Mini MP3 Player Module
1 Micro SD card
1 Arduino nano
1 Speaker (max 3W)
1 Button
Changeable resistance (potentiometer)
Resistance 1 Kohm
connection cable
Computer with Arduino IDE and internet connection
External voltage source (recommended), 7 - 12V


Voice

With the Arduino library "Talkie" the Arduino is transformed into a language generator. I tried that. I will not dig further into this. I was not satisfied with the voice quality for this project.

Another variant is to play audio files. For this I use the DFPlayer by Dfrobot. Albert Vu and Matthias Kammerer have already shown in your blog contributions how this component is put into operation. The disadvantage here is that you need a speaker with whom you record the words that will be played back later.

In addition, the audio files must be edited. I used online language generators. These can be found e.g. at Voicebooking.com or Wideo.com. You will receive the required files for free for private use. For editing the audio files, you can use e.g. the free audio editor Audacity . We will need a start sound and the following texts:

Audio file text
0001_startsound.wav [StartSound]
0002_info.wav Press and hold buttons and keep sensor close to the object.
0003_scanne.wav Scan.
0004_rot.wav Red.
0005_gruen.wav Green.
0006_blau.wav Blue.
0007_schwarz.wav Black.
0008_weiss.wav White.
0009_gelb.wav Yellow.
0010_orange.wav Orange.
0011_pink.wav Pink.
0012_braun.wav Brown.
0013_kalibriere.wav Calibration.
0014_deutsch.wav German.


Visit one of the websites and allow the text to convert the text to a speech file completely in a piece:

Press and hold buttons and keep sensor close to the object. Scan. Red. Green. Blue. Black. White. Yellow. Orange. Brown. Calibration. German.

Then edit this with an audio editor of your choice to get individual files at the end. Alternatively, you can also record the texts yourself. The naming of the files is important. At least the first four characters.

The DFPlayer we use searches for files with numbers 0001.MP3 or 0001.Wav on the SD card. For a better overview, any text can follow after the four digits. You can choose this designation freely. We will play very specific audio files at certain times. Do not forget the start sound. If you have your files at hand and named accordingly, copy them one after the other on the micro SD card. Here, the order in which the files are copied is actually important . Subfolders we will not need for the time being.

We will first commission the player and ensure that the start sound is played. The components are connected as follows:


Between the RX pin of the DFplayer and the TX pin of the arduinos, a 1 kOhm resistor should be connected. It is also advisable to connect an external power source that provides between 7 and 12V on the VIN pin of the Arduino.

DFPlayer Mini Pins Arduino Nano Pins
Vcc 5V
GND GND
RX Over 1 KOHM to D11 (TX)
TX D10 (RX)
speaker
SPK_1 Red (plus)
SPK_2 Black (minus)


After connecting everything, we have to write the sketch. Some libraries are available in the Arduino IDE library management. We use the library provided by the manufacturer Dfrobot Dfrobotdfplayermini.

I also have tested the library DFPlayermini_Fast . This is well described and something slimmer. However, at the point where I needed the info, whether the player just plays an audio file, I did not get on. While it is possible to query this information, however, the constantly repeated command generates errors in playback. The same thing happens in the DFFRobot library.

But here, one can additionally query if and with which parameter the status has changed. Then you can query whether the playback has been stopped and which audio file was last played. I did not find this possibility in the Fast Library.

After installing the library, some examples are available. Open the project Getstarted and transfer it to the Arduino.

Of course, you must not forget to insert the SD card on which the audio files are located. If everything is done properly, the start sound should be heard for three seconds. If not, different sources of error could be the cause.

Make sure the LED lights of the DFplayer are on. If so, the audio file is played. Then the speaker could not be connected correctly. You could confuse the speaker outputs of the DFplayer. The speaker should not go to SPK1 and GND, how to possibly suspect. It is a mono output and has to go to SPK1 and SPK2. If you have an audio amplifier, the audio signal can also be tapped from the Digital Analog Converter, which is located on the module. Use the connections DACL and DACR for a stereo signal. If the LED does not light up on the DFplayer module, it could be that the electricity is not strong enough. Open the serial monitor and pay attention to the screen output. There the line "Dfplayer Mini Online" appears. If not, you will see an error message. It could be that the RX and TX lines are reversed. This is a frequently occurring error. I also happened to me. It's a bit confusing if you initialize the pins. It is not determined which DFPlayer pin of the Arduino pin is connected, but one generates own RX and TX pins. Subsequently, these must be cross-linked between the two components. Another possibility is that the SD card is not recognized. This must not be greater than 32GB. And it can only be formatted with the FAT16 or FAT32 file system. If the LED lights on the DFplayer module and still do not hear anything, check the audio files for the correct file format. The [data sheet] (https://cdn.shopify.com/s/files/1/1509/1638/files/mp3PlayermoduleDatasheet.pdf? 10537896017176417241) The DFPlayer can be found in the appropriate specifications. Maybe the audio level of the file is too low. By default, the volume is set to 10 in the example program. Maximum is the value 30.

I now assume that the audio file is played. At this point I would like to explain to you how the source code works in the example so that we can better use it for our project:

#include "Softwareserial.h"
#include "Dfrobotdfplayermini.h"

For serial communication, the SoftSerial library is needed. Thus, it is possible to simultaneously receive an output on the serial monitor because this uses the hardware com interface.  The DFFRobot library provides us with the necessary functions for operating the MP3 player.

SoftwareSerial MySoftwareserial (10, 11); // RX, TX
DfrobotdfPlayermini MyDFPlayer;

The SoftSerial interface allows us to assign our own pins for communication. As already mentioned, we create our own RX and TX pins. The RX pin of the Arduinos (here 10) must then be connected to the TX pin of the DFplayer. The TX pin No. 11 of the Arduinos over the 1 KOHM resistor with the RX pin of the DFplayer. The object mydfplayer will be used later for audio playback.

In the setup() we start communication with:

mysoftwareserial.begin (9600);
Serial.begin (115200);

By default, the DFPlayer communicates with a baud rate of 9600 via the SoftSerial interface. The output on the serial monitor is here with 115200. Make sure that the same value is set in the serial monitor.

  IF (! mydfplayer.begin (mysoftwareserial) {}

This command in the query starts the communication of the DFplayer via the SoftSerial interface with the Arduino. If that was unsuccessful, an error message is output.

mydfplayer.Volume (10);  // Set Volume Value. From 0 to 30
mydfplayer.play (1);     // play the first mp3

With these two function calls you can set the volume and play a specific audio track from the SD card. If the sound is too quiet, increase the value to a maximum of 30. Our start sound is 0001_startsound.wav. With Play (1) this file is played. Important is that it was first copied to the SD card and lies in the root directory. The name behind 0001 is irrelevant.

In the loop() function at first a timer is started. This ensures that playback is restarted every three seconds.

mydfplayer.next ();

With this function, the next audio file is then played. Thus, all files on the SD card should be played for three seconds.

IF mydfplayer.available ()) {
PrintDetail (MyDFplayer.ReadType (), MyDFplayer.Read ());
}

With the available() function is it possible to respond to changes or errors. The DFPlayer supplies with READTYPE () the types of change and a suitable parameter with the function Read ().

For the issue of the associated information, the printDetail() function written below in the source code. If e.g. stopped the playback, is the returned type DfplayerPlayFinished And the associated parameters the number of the last played audio file.

For example, if you want to respond to the playback, you can query. Here is a short sample code:

IF (mydfplayer.available () && mydfplayer.readtype () == DfplayerPlayFinished) {
    // Make something
}

In this way it is possible to react without noise to stop the audio playback. Without the query of the available() function is interrupted in short cycles, which does not sound clean.

Now we come to a problem that is also discussed on the internet. The shift noises that occur when you turn the Arduino on or off with connected DFplayer. On the back of the module, a 0-ohm resistor is soldered. Exactly opposite are two free solder pads. A hardware modification is to remove the resistance and to open the other side. In the Arduino forum someone described and performed it. However, it did not bring the desired result.

In the Tonuino forum a solution is described with an additional antiserial MOSFET circuit. I did not pursue or changed this for this project.

More disturbing than the shift noises I find cracking when a song is started or stopped. To prevent this, in the sample project AdvancedSettingWithoutReset shown how to solve it. in the set up() Does this line have to:

IF (! mydfplayer.begin (mysoftwareserial) {

be supplemented as follows:

IF (! mydfplayer.begin (mysoftwareserial, true, false)) {

This will prevent a reset() call  taht causes the noise. I still heard a cracking noise at the end of my starting sound audio file. That was at the audio file itself, which seemingly ended with a termination of the audio wave. If you let the sound fade, the level in the audio file is zero at the end. After this change, there was no noise of this kind.

To get to know more features of the library, you should have a look at the sample project FullFunction.

Our own program

At the beginning, just the start sound should be played. For this we change that GetStarted-Example.

We need some variables:

int volume = 20;
int State = 0;
boot spent = false;

For the later program flow we will develop a state machine through which we can switch with the button. We realize this with a switch case statement. As an argument of the states I use the variable state. The variable spent Ensures that the output appears only once in the serial monitor. Because the main loop runs permanently through the Stemachine ().

It follows the state machine itself:

void statemachine () {
  switch(state) {
    case 0: {
mydfplayer.play (1);                           // Play start sound
Serial.Println ("Program is started.");
state = 1;
    } break;
    case 1: {                                 // standby
      if (! issued) {
Serial.Println ("Standby.");
spent = true;
      }                                     
    } break;
    default: state = 1; break;
  }
}

After switching on the Arduino, the state (case) 0 is passed through. There our start sound is played and the text "program is started." output. Then it is changed to state 1. There is once "standby." output on the screen.

Nothing happens for the other passes. You could also instead of the if-instruction for one-time playback insert another case. However, since our program gets bigger and then we would have empty cases, we solve this in this way.

The text for the screen output on the serial monitor we change in setup() according to your own needs:

void set up() {
mysoftwareserial.begin (9600);
Serial.Begin (115200);
Serial.Println (F (F ("The talking color detector"));
Serial.Println (F (F ("Initialize DFPlayer ..."));
  IF (! mydfplayer.begin (mysoftwareserial, true, false)) {
Serial.Println (F (F ("DFPlayer can not be started:"));
Serial.Println (F (F ("1. Confirms Prüfen!"));
Serial.Println (F (F ("2. SD card Prüfen!"));
  }
Serial.Println (F (F ("DFPlayer Mini Online."));
Serial.Print (F (F (F (F)"Volume: "));
mydfplayer.Volume (volume);
Serial.Println (Volume);
}

In the Loop () we call the Statemachine () on:

void Loop () {
Statemachine ();
}

If we upload the program to the Arduino, the starting sound will be played. Then nothing happens.

Complete source code: 1.0DfplayerStartsound.ino

Volume

To change the volume of playback, there are various possibilities. One is the above-mentioned audio amplifier. Another would be a turncode that is often used in AudioReceivers. I have opted for the simpler variant of a potentiometer. Of course, we must not easily influence the audio signal on the speaker pin with a changeable resistance.  There are potentiometers with which that is possible. It should be noted that an audio signal is an AC voltage.

I will use the potentiometer to change the value in the function mydfplayer.Volume (10) . We supplement the circuit as follows:


The two outer pins of the potentiometer to GND and 5V. The middle contact (grinder) to one of the analog pins of the Arduinos, here A0.

We complement our variables:

int Volume_old = 20;

and add the following function:

void volume() {
Volume = analogread (A0);
Volume = Map (Volume, 0, 1023, 0, 30); 
  IF (Volume! = Volume_old) {
Serial.Print ("Volume: ");
Serial.Println (Volume);
mydfplayer.Volume (volume);
  }
Volume_old = Volume;
}

This will read the analog PIN A0. The delivered value ranges (input values ​​0 to 1023) will be mapped to volume 0 to 30. The change in the volume shall be displayed in the monitor. However, only if a change has taken place. For that we need the if query and the variable Volume_old.

In the loop() function we add the calls of the above described function at the start:

void Loop () {
volume();
statemachine ();
}

We upload the program to the Arduino, we hear the startsound, whose volume we can change directly. This change is output in the serial monitor. It is now possible to change the volume of audio playback at any time.

Complete source code: 1.1DfplayerStartsound_poti.ino

Operation with button

We would like to somehow serve our color detector. For the time being we use only one button for this purpose. This allows us to start and stop the scanning process of the color scanner. First, we complement our circuit by the said button:


We will use the internal pullup resistor. Therefore, we connect the button to D12 and GND directly. We complement our source code by defining the pushbutton:

#define TasterPin 12

in the set up() Let's initialize him as input with pullup resistance:

pinMode (TasterPin, INPUT_PULLUP);

Now we complement the state machine around the associated cases. I want you to press the button, whereupon a hint for operation is shown. You have to let go the button again and hold the sensor to the surface that you want to scan. If you press the button again and keeps it pressed, the color is scanned. If you leave the button then, the last detected color is output via the audio playback. Then get back into the case 3 of the state machine, so that the help instruction is not reproduced again, but you can scan a color again. We will now implement this functionality. The button should also be debounced with software.

void statemachine () {
  switch(state) {
    case 0: {
mydfplayer.play (1);                     // Play start sound
Serial.println ("Program is started.");
state = 1;
    } break;
    case 1: {                                 // standby
      if (! issued) {
Serial.println ("Standby.");
spent = true;
      }                                     
    } break;
    case 2: {                                 // Play Help
mydfplayer.play (2);
Serial.println ("button pressed and keep sensor close to the object.");
state = 3;
spent = false;
    } break;
    cube 3: {                                 // ready to scan
      IF (! issued) {
Serial.Println ("Waiting for button ...");
spent = true;
      }                                   
    } break;   
    case 4: {                                 // Start Scan
mydfplayer.play (3);
Serial.println ("Scan ...");
spent = false;
state = 5;
    } break;
    case 5: {                                 // scan
Serial.println ("Colour: ");
    } break;
    case 6: {                                 // Output color
mydfplayer.play (6);
Serial.println ("Red color");
state = 3;
    } break;
    default: state = 1; break;
  }
}

The function for the button looks like this:

void taster() {
  taster_status_neu = digitalRead(TasterPin);          //taster ist active low

  // Tasteraenderung erkennen und Prelltimer starten
  if (taster_status_neu != taster_status_alt && !taster_change) {
    start_zeit = millis();
    taster_change = true;
  }
  // wenn Taster gedrueckt
  if (taster_status_neu == LOW && taster_status_alt == LOW && taster_change) {
    // Taster entprellen
    if (millis() - start_zeit > prell_delay) {
      taster_change = false;
      state++;
      if (state > maxStates) {
        state = 1;
      }
    }
  }
  // wenn Taster losgelassen
  else if (taster_status_neu == HIGH && taster_status_alt == HIGH && taster_change) {
    // Taster entprellen
    if (millis() - start_zeit > prell_delay) {
      taster_change = false;
      if (state == 5) {
        state = 6;
      }
    }
  }
  taster_status_alt = taster_status_neu;
}

It is a bit more extensive, because we not only debounce the push of the button, but also the release. Because the color should be output when the button has been released after scanning.

We read the pushbutton. This is because of the pullup resistor Active Low (pressed Low and released HIGH). Has a change in the key state taken place, a timer is started. So that this command is not running again and again, we lock that with the variable taster_change (I've chosen the term bilingual here).

In the following course, it is checked whether the button has been pressed whether it remains pressed and whether the time interval we have chosen for the development has been reached. If so, the change of the button is released again and the variable for the state machine is incremented. We must make sure that we do not exceed the maximum number of states so that the program does not go into the emptiness.

In the event that the button was already pressed, remains released, remains released and the time of the time interval for the debaounce has been reached, the lock is also lifted for the button and additionally set our state machine to the state that reproduces the color.

We declare the following variables for the two functions:

int maxStates = 6;
bool ausgegeben = false;
unsigned long neue_zeit = 0;
unsigned long start_zeit = 0;
unsigned long prell_delay = 80;
bool taster_status_neu = HIGH;          
bool taster_status_alt = HIGH;
bool taster_change = false;  

If we invite the program to the Arduino, should sound like the start sound before. If you press the button, the help text is output. You let go of the button and presses him again. The word "scanny" is output. If you leave the button at some point, a color is output. At this point, the color sensor is not yet connected. That's why I chose the color red. You can restart the process again and again. The program run now works and we receive a voice output.

Complete source code: 1.2DFPlayerStartsoundPotiTaster.ino

preview

In the second part of this blog series we will connect the color sensor and take it into operation. I will show you which libraries are available for this and what you have to consider when using the sensor.

Until then,

Andreas Wolter

For AZ-Delivery Blog

For arduinoProjects for beginnersSensors

2 comments

Heiko Hogg

Heiko Hogg

Aufbau ist nachgebaut und im standby – und wartet ungeduldig auf den nächsten Teil (oder bin ich das, der es kaum erwarten kann?)
Als ein Mensch, der wie 20% der Männer eine Rot-Grün-Farbsehschwäche hat, ist dieses Thema besonders interessant. Als Normal-Farbsichtiger kann man es sicherlich kaum nachvollziehen, welche Einschränkungen man da hat – und das nicht nur als Pilot oder Lokführer. Wie gesagt: ich bin sehr gespannt, auch darauf, was man daraus noch alles entwickeln und einsetzen kann.
Bis dahin: vielen Dank für die super ausführliche und nachvollziehbare Beschreibung und das sehr, sehr interessante Thema!

Lentner Peter

Lentner Peter

Super Beitrag, ganz ausführlich Beschrieben.
Habe diesen nur aufmerksam Gelesen und nicht getestet.
Die Programmteile mit deutschen Bezeichnungen und nicht nur aus englischen Codes heraus kopiert..

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN