Project tutorial
Send Data with Sound

Send Data with Sound © GPL3+

Control your Arduino using data-over-sound.

  • 3,488 views
  • 3 comments
  • 13 respects

Components and supplies

About this project

Here at Chirp HQ, we were extremely excited to hear the announcement that Arduino would be releasing a new board with a whole host of new features. These features include a wide range of sensors, a powerful processor and most importantly - an on board microphone! The good people at Arduino sent us over a pre-release of the new Nano 33 Sense board, which is fully compatible with Chirp, allowing the maker community to send and receive data using sound.

Chirp adds a completely unique transport mechanism to Arduino boards, the added capabilities of data-over-sound means that hackers have more connectivity options at their fingertips. Some of the advantages of data-over-sound include:

  • Device agnostic: data can be sent from mobile apps, web pages, or even with just an audio file
  • One to many: any device within hearing range is able to receive data in one simple transaction
  • Frictionless: doesn't need any pairing, passwords or initial setup

In this tutorial we will demonstrate how to use the Chirp SDK to send an RGB value to change the colour of the on board LED.

Chirp even works in noisy places, thanks to the years of research we’ve put into making the decoder robust to background sound. Read more about the benefits of using data-over-sound here.

If you are still sceptical, try it out yourself.

Getting started with Chirp is easier than ever...

Getting started

If you have not done so already, you will need to sign up to Chirp at developers.chirp.io. Once you have signed up, you can get your app key, secret and audio configuration for your application.

Note: the 16khz-mono-embedded protocol should be selected from the dropdown when selecting your Chirp configuration.
Tip: you can select the ‘C’ code box below the configuration, and click ‘Copy to Clipboard’ to easily paste into the credentials.h file.

Receiving data

Since the Nano 33 Sense comes packaged with an on board microphone, all you need to receive data using Chirp is the Chirp SDK which is available directly from the Library Manager.

Simply open the Library Manager, and search for Chirp SDK. Install v3.3.0 or later and you are ready to start coding.

Tools > Manage Libraries

You can open our example code to start with.

File > Examples > ChirpSDK > Nano33SenseReceive

You will need to copy and paste your credentials for the 16khz-mono-embedded protocol from developers.chirp.io into the credentials.h file.

It is also important to note here that the example code will not start until the Serial Monitor is opened, you can change this by commenting out the while(!Serial) line.

The example code will simply print any received data to the Serial Monitor. However, we can easily change the behaviour to light the on board LEDs by editing the onReceivedCallback function.

In your setup function, we must first set up the GPIO pins connected to the LEDs as outputs

#define R_LED_PIN         22
#define G_LED_PIN         23
#define B_LED_PIN         24
void setup() 
{    
    pinMode(R_LED_PIN, OUTPUT);    
    pinMode(G_LED_PIN, OUTPUT);    
    pinMode(B_LED_PIN, OUTPUT);
} 

To drive the LEDs we will need to pull out the RGB values from the data payload.

void onReceivedCallback(void *chirp, uint8_t *payload, size_t length,
{    
    if (length > 0) {        
        // High values mean lower brightness, so we        
        // subtract from UINT8_MAX        
        analogWrite(R_LED_PIN, UINT8_MAX - payload[0]); 
       
        analogWrite(B_LED_PIN, UINT8_MAX - payload[2]);
    } else {       
        Serial.println(“Decode failed”);
    }
} 

You can now test your code by playing the audio files below, each one should change the LED colour from red to green to blue.

What’s next?

The first iteration of the Chirp SDK for Arduino operates only on the audible 16khz-mono-embedded protocol. Over the coming months, we will be releasing an inaudible version that will work at near ultrasonic frequencies. With this you will be able to send data at frequencies that humans cannot hear, so for example, you could embed the chirp data in existing audio such as songs or videos to trigger actions.

We will also be following up with more tutorials on how you can utilise data-over-sound with Arduino. Let us know where you have used Chirp in your own Arduino projects by tagging us on twitter @chirp or get in contact with us at contact@chirp.io.

Code

Chirp RGB values to Nano 33 SenseC/C++
Send RGB values using Chirp to change the colour of the on board LED. You can use our attached sound clips on this tutorial to try it out, or do it yourself by sending an array of 3 bytes.
/**--------------------------------------------------------------------

    Example code to receive data using Arduino Nano 33 Sense board.

    @file Nano33SenseReceive.ino

    @brief Create a developer account at https://developers.chirp.io,
    and copy and paste your key, secret and config string for the
    "16khz-mono-embedded" protocol into the chirp defines below.

    This example will start listening for RGB values and change the        colour of the on board LED.

    Circuit:
      - Arduino Nano 33 BLE board

    Copyright © 2011-2019, Asio Ltd.
    All rights reserved.

  -------------------------------------------------------------------*/
#include <PDM.h>

#include "chirp_connect.h"

#define CHIRP_APP_KEY        "YOUR_APP_KEY"
#define CHIRP_APP_SECRET     "YOUR_APP_SECRET"
#define CHIRP_APP_CONFIG     "YOUR_APP_CONFIG"

#define SAMPLE_RATE          16000
#define BUFFER_SIZE          256

#define R_LED_PIN            22
#define G_LED_PIN            23
#define B_LED_PIN            24

// Global variables ---------------------------------------------------

static chirp_connect_t *chirp = NULL;
short sampleBuffer[BUFFER_SIZE];
volatile int samplesRead;

// Function definitions -----------------------------------------------

void setupChirp(void);
void chirpErrorHandler(chirp_connect_error_code_t code);
void onPDMdata(void);

// Main ---------------------------------------------------------------

void setup()
{
  Serial.begin(115200);
//  while (!Serial);

  pinMode(R_LED_PIN, OUTPUT);
  pinMode(G_LED_PIN, OUTPUT);
  pinMode(B_LED_PIN, OUTPUT);
  
  setupChirp();

  PDM.onReceive(onPDMdata);
  PDM.setGain(30);

  if (!PDM.begin(1, SAMPLE_RATE))
  {
    Serial.println("Failed to start PDM!");
    while (1);
  }

  analogWrite(R_LED_PIN, UINT8_MAX);
  analogWrite(G_LED_PIN, UINT8_MAX);
  analogWrite(B_LED_PIN, UINT8_MAX);
}

void loop()
{
  if (samplesRead)
  {
    chirp_connect_error_code_t err = chirp_connect_process_shorts_input(chirp, sampleBuffer, samplesRead);
    chirpErrorHandler(err);
    samplesRead = 0;
  }
}

void onPDMdata()
{
  int bytesAvailable = PDM.available();
  PDM.read(sampleBuffer, bytesAvailable);
  samplesRead = bytesAvailable / sizeof(short);
}

// Chirp --------------------------------------------------------------

void onReceivingCallback(void *chirp, uint8_t *payload, size_t length, uint8_t channel)
{
  Serial.println("Receiving data...");
  analogWrite(R_LED_PIN, UINT8_MAX);
  analogWrite(G_LED_PIN, UINT8_MAX);
  analogWrite(B_LED_PIN, UINT8_MAX);
}

void onReceivedCallback(void *chirp, uint8_t *payload, size_t length, uint8_t channel)
{
  if (length)
  {
    // High values mean lower brightness, so we
    // subtract from UINT8_MAX
    analogWrite(R_LED_PIN, UINT8_MAX - payload[0]);
    analogWrite(G_LED_PIN, UINT8_MAX - payload[1]);
    analogWrite(B_LED_PIN, UINT8_MAX - payload[2]);
  }
  else
  {
    analogWrite(R_LED_PIN, 0);
    analogWrite(G_LED_PIN, UINT8_MAX);
    analogWrite(B_LED_PIN, UINT8_MAX);

    delay(500);
    analogWrite(R_LED_PIN, UINT8_MAX);
    delay(500);

    analogWrite(R_LED_PIN, 0);
    Serial.println("Decode failed");
  }
}

void chirpErrorHandler(chirp_connect_error_code_t code)
{
  if (code != CHIRP_CONNECT_OK)
  {
    const char *error_string = chirp_connect_error_code_to_string(code);
    Serial.println(error_string);
    exit(42);
  }
}

void setupChirp(void)
{
  chirp = new_chirp_connect(CHIRP_APP_KEY, CHIRP_APP_SECRET);
  if (chirp == NULL)
  {
    Serial.println("Chirp initialisation failed.");
    return;
  }

  chirp_connect_error_code_t err = chirp_connect_set_config(chirp, CHIRP_APP_CONFIG);
  chirpErrorHandler(err);

  char *info = chirp_connect_get_info(chirp);
  Serial.println(info);
  chirp_connect_free(info);

  chirp_connect_callback_set_t callback_set = {
    .on_state_changed = NULL,
    .on_sending = NULL,
    .on_sent = NULL,
    .on_receiving = onReceivingCallback,
    .on_received = onReceivedCallback
  };

  err = chirp_connect_set_callbacks(chirp, callback_set);
  chirpErrorHandler(err);

  err = chirp_connect_set_input_sample_rate(chirp, SAMPLE_RATE);
  chirpErrorHandler(err);

  err = chirp_connect_set_frequency_correction(chirp, 1.0096);
  chirpErrorHandler(err);

  err = chirp_connect_start(chirp);
  chirpErrorHandler(err);

  Serial.println("Chirp SDK initialised.");
  Serial.flush();
}

Comments

Similar projects you might like

Sound Sensor Activated LEDs with LCD for Sound Level Data!

Project tutorial by HeathenHacks

  • 4,323 views
  • 5 comments
  • 16 respects

Send MKR1000 Data to Google Sheets

Project tutorial by Stephen Borsay

  • 12,942 views
  • 30 comments
  • 37 respects

Send and Receive Text Messages (SMS) with GSM SIM900 Shield

Project tutorial by Boian Mitov

  • 68,971 views
  • 5 comments
  • 38 respects

Visualising sensor data using Arduino and Processing

Project tutorial by sowmith mandadi

  • 42,848 views
  • 3 comments
  • 39 respects

MKR Zero Weather Data Logger

Project tutorial by Arduino_Genuino

  • 28,050 views
  • 18 comments
  • 57 respects

Arduino - Send Temperature to Web via Serial

Project tutorial by IoT_hobbyist

  • 6,009 views
  • 7 comments
  • 30 respects
Add projectSign up / Login