Making a Talking Plant

18 Jan 2020


I got a robot kit for Christmas (thanks to you know who) and a few of the things it came with were an Arduino, batteries, and an ultrasonic. I never really used it until I did this project where I wanted a plant to speak to you if you walked past it.

Powering the Arduino

So like I said, the robot kit I got had batteries and a nice little battery connector; otherwise, I would have had to tape my own battery pack together.

Each battery was about 3.7V each, for a total of 7.4V of power to the Arduino. For voltages between 7 to 12 volts, you're supposed to use the Vin pin on the Power side of the Arduino. Using male to male cables (the ones with two pointy ends), connect the red cable to Vin and black cable to ground (GND).

Yay, Arduino is on!

Connecting Ultrasonic

An ultrasonic is a little device that can do motion detection using sonar. Basically how it works is:

  1. Transmitter (written as Trig on ultrasonic) sends out sound
  2. Sound bounces back off object
  3. Reciever (known as Echo) picks up reflected sound frequency
We will end up using the time it took Echo to recieve the sound to calculate the distance between the ultrasonic and the object. But for now, here are the connections from ultrasonic to Arduino:
  • Vcc -> 5V (power side)
  • Trig [OUTPUT] -> Pin 8 (pin side)
  • Echo [INPUT] -> Pin 7
  • Gnd -> GND (power side)

The wires ended up being short so I used more male to male cables to extend the connection.

I also used the Arduino docs and this Youtube video to learn how to set this up.
Side note: The pin numbers I chose for the ultrasonic are trivial, you can use any (digital) pin without consquence.

Connecting Speaker

LESSON LEARNED 1: Don't connect a speaker straight to an Arduino. I'll mention why later on in this post. For documentation's sake, I am continuing, but that's just my word to the wise.

Although I'm not actually doing this at this point, I will write down the pin connections:

  • Red Speaker Wire -> Pin 11 (pin side)
  • Black Speaker Wire -> GND (pin side)
Side note: Everything fit on the Arduino so I didn't bother using a breadboard because this was all gonna be stuffed into a plant pot.

Programming the Arduino

Now for some code! So once I plugged in my Arduino to the computer, we'll have to write a little bit of code to make things work.

Ultrasonic outputs time between transmission and recieving (in μs)

All Arduino code have two main sections: the setup() function and the loop() function. setup() will run once and loop() is what the Arduino will keep doing when you upload code to it.

So setting up the code looks like this:

        const int trig =  8;
        const int echo = 7;
        const int speakerpin = 11;
        // put your setup code here, to run once:
        void setup() {
            Serial.begin(9600); #opens up serial port
            pinMode(trig, OUTPUT);
            pinMode(echo, INPUT); 
        // put your main code here, to run repeatedly:
        void loop() {
            //write voltage to selcted pin  
            digitalWrite(trig, LOW);
            digitalWrite(trig, HIGH);
            digitalWrite(trig, LOW);
            int time = pulseIn(echo, HIGH);


Here we set the pin numbers from the connections on the Arduino as variables in the code.Serial.begin() is always in the setup function, and usually set to 9600bps. The pinMode() function configures Trig as output and Echo as input.

In loop(), the digitalWrite function will send a voltage to the Trig pin with digitalWrite(trig, HIGH); This is transmitting out the sound frequency. It's recommended to write LOW (0V) to the Trig pin before you send out HIGH. Finally, pulseIn(echo, HIGH) is measuring the time for Echo to go from LOW to HIGH. This will return time in microseconds.

To convert time into distance, I used this formula that I Googled somewhere:


        long secondsToInches(int time) {
            long distance = time / 83.3;
            distance = distance / 2;
            Serial.print("The inches is ");
            return distance;

        //...other code from above...
        void loop() {

            int time = pulseIn(echo, HIGH);
            long distance = secondsToInches(time) 

Now we can print distance!

Using Measurements Effectively

In the project, I wanted when someone got in range of the plant (let's say 36 inches away) the speaker would speak. In theory, that means I should do this:

        if (distance <= 36 ) {
            //make the plant talk

Ultrasonic outputs time between transmission and recieving (in μs)

Unfortunately, the ultrasonic produces noisy code, and since the distance is being measured like every 30 microseconds or so, I don't want the speaker to play after one bad measurement.

This meant I needed to take a sliding average of distances. When the average was 36 inches, then I would sound the speaker. Basically, we'll just set up a queue and keep popping the least recent value, inserting the most recent value, and then taking the average of everything inside the queue to see if it is less than the desired distance.

This is generally what that would look like:

        void setup() {
            queue = [] //create empty queue
            queue.capacity = 3 //only three values in queue at a time

        void loop() {
            if(queue == full) {
                pop(queue) //take out oldest value

            push(queue) //put new value

            if average(queue) <= 36 {
                //make the plant talk

Arduino uses a C-like language, so this is what the sliding average code looked like:

        #include <assert.h>
        typedef struct Queue {
            long *arr;
            int index;
            int capacity;
            int len;
        } queue;

        int returnLen (queue* q) { return q->len; }
        int returnCapacity (queue* q) { return q->capacity; }
        void pop(queue* q) {
            assert(q->len != 0);
            for (int i = 0; i < q->index - 1; i++) {
              q->arr[i] = q->arr[i+1];

            q->index -= 1;
            q->len -= 1;
        void push(queue* q, long val) {
            assert(q->len < q->capacity);
            q->arr[q->index] = val;
        long avg(queue* q) {
            assert(q->len != 0);
            int i;
            int val;
            for (i = 0; i < q->len; i++) { val += q->arr[i]; }
            return val / q->len;
        void insert(queue* q, long val) {
            if (q->len == q->capacity) { pop(q); }
            push(q, val);
        queue Q; //make queue object called Q
        void setup() {
            Q.len = 0;
            Q.capacity = 3;
            Q.arr = (long*)malloc(Q.capacity * sizeof(long));
            Q.index = 0;
        void loop() {
            insert(&Q, inches);

            if ( returnCapacity(&Q) == returnLen(&Q) ) {
                if ((avg(&Q)) <= 36) {
                    //make the plant speak                  


Making the Speaker Speak

LESSON LEARNED 2: If you want to use sound in a project, use a sound card. Don't just do everything straight from the Arduino.

Ok, now for the sound part. I'll first mention why it's not a good idea to rely on the Arduino to play sound:

  • The main reason is that microcontrollers like Arduinos have very limited space. The sound I eventually played from the Arduino was like 2 seconds and that took up 60% of its capacity. SD cards are important.
  • In order to play MP3-like audio, it has to be encoded for pulse code modulation (PCM) ouput, rather than a microcontroller's usual PWM output.
  • The sound will be much quieter, regardless of the power of the speaker.
But I had some time constraints to finish this part of the project, and I needed to output sound.

Luckily, there is a PCM library that encodes MP3 data. However, I found out that for my Mac, the library used an incompatible version of Java(?) so I ended up using a PC to use the library. It looked like this:

        #include <PCM.h>
        //it is a lot more numbers than this...
        const unsigned char sample[] PROGMEM = {
            130, 133, 135, 134, 131, 131, 132, 131, 130, 129, 129, 12... 6, 133, 133, 132, 125, 126, 129, 128, 127, 126, 

        void loop() {
            if ( returnCapacity(&Q) == returnLen(&Q) ) {
                if ((avg(&Q)) <= 36) {
                  startPlayback(sample, sizeof(sample)); //plays the encoded sound

Testing out everything together, looked like this:

It speaks!


The speaker was very tiny. That and a lack of an amplfier meant you could barely hear anything as you walked past. I quickly learned Arduinos are not made to play sound.

The ultrasonic was also not mounted firmly onto anything, so it was subject to moving around, and generating more noise for the sliding average.


In the end, the plant could only say, "seeking human kindness", due to the time constraints and lack of better equipment. This was my first project related to robotics, so I learned a lot in the process of making this. But I also learned a couple of things after:

Read up. I, not knowing what all these gadgets really do, bought an AdaFruit Sound Board thinking that it would be a amp. Quickly realized it wasn't a amp and never used it. By the end of the project, I found out I could have used it, along with an amplfier to provide louder sound and it would have worked as a sound card too.

Using amplifiers. Amplifiers make things loud. Use them.

Using resistors. Although no damage happened to any product, resistors should be used to connect the Arduino to the speaker, especially ones more powerful than a 3W, 4Ω one.

All in all, I had a lot of fun throughout the whole thing; I think that's it. :)