Using XBee RSSI values to control Mozzi synths

Hello. I hope someone can help.

My Arduino knowledge is currently pretty basic, but I am trying to use XBee RSSI values to control Mozzi synths, so that various envelopes or filters change when 3D objects are further apart of closer together. There are 4 objects, each with an XBee inside.

I am trying to use

rssiDur = pulseIn(digitalPin, LOW, 200);

as mentioned here - Notion – The all-in-one workspace for your notes, tasks, wikis, and databases., but don't know how to use / adapt this to control synths.

I have some code that I had a lot of help with that seems to read the fact that there RSSI data there, but it doesn't seem to change the sound when the distance changes, just when it detects another XBee transmitting.

#include <MozziGuts.h>
#include <Oscil.h> // oscillator 
#include <tables/cos2048_int8.h> // table for Oscils to play
#include <AutoMap.h> // maps unpredictable inputs to a range
 
// desired carrier frequency max and min, for AutoMap
const int MIN_CARRIER_FREQ = 22;
const int MAX_CARRIER_FREQ = 440;

// desired intensity max and min, for AutoMap, note they're inverted for reverse dynamics
const int MIN_INTENSITY = 700;
const int MAX_INTENSITY = 10;

AutoMap kMapCarrierFreq(0,1023,MIN_CARRIER_FREQ,MAX_CARRIER_FREQ);
AutoMap kMapIntensity(0,1023,MIN_INTENSITY,MAX_INTENSITY);

const int KNOB_PIN = 0; // set the input for the knob to analog pin 0
const int LDR_PIN = 1; // set the input for the LDR to analog pin 1

Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aCarrier(COS2048_DATA);
Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aModulator(COS2048_DATA);

int mod_ratio = 3; // harmonics
long fm_intensity; // carries control info from updateControl() to updateAudio()

//Constants
const int ledPin = 3; //Led to Arduino pin 3 (PWM)

//Variables
bool started= false;//True: Message is strated
bool ended  = false;//True: Message is finished 
char incomingByte ; //Variable to store the incoming byte
char msg[3];    //Message - array from 0 to 2 (3 values - PWM - e.g. 240)
byte index;     //Index of array

int rssiDur = 0;
int rssiMapped =0;
bool calib = false;
bool calib_top = false;
int base_value= 0;
int top_value=0;

void setup() {
  //Start the serial communication
  Serial.begin(9600); //Baud rate must be the same as is on xBee module
  pinMode(ledPin, OUTPUT);
  pinMode(6, OUTPUT);
  calib = true;
  calib_top = true;
  startMozzi(); // :))
}
void updateControl(){
  // read the knob
  //int knob_value = mozziAnalogRead(KNOB_PIN); // value is 0-1023
  rssiDur = pulseIn(5, LOW, 200);
  rssiMapped = map(rssiDur, 10, 40, 0, 1023);
  
  
  Serial.print("raw RSSI : ");
  Serial.println(rssiDur);
  Serial.print("RSSI mapped : ");
  Serial.println(rssiMapped);
  
   //delay(100);
  
  // map the knob to carrier frequency
  int carrier_freq = kMapCarrierFreq(rssiMapped);
  
  //calculate the modulation frequency to stay in ratio
  int mod_freq = carrier_freq * mod_ratio;
  
  // set the FM oscillator frequencies to the calculated values
  aCarrier.setFreq(carrier_freq); 
  aModulator.setFreq(mod_freq);
  
  // read the light dependent resistor on the Analog input pin
  int light_level= mozziAnalogRead(LDR_PIN); // value is 0-1023

  fm_intensity = kMapIntensity(light_level);

}

 int updateAudio(){
  long modulation = fm_intensity * aModulator.next(); 
  return aCarrier.phMod(modulation); // phMod does the FM
}


void loop() {
  
  
  //delay(100);
 

  if(rssiDur != 0){
      digitalWrite(6, HIGH);
    }else{
      digitalWrite(6,LOW);
    }

    audioHook();
  
while (Serial.available()>0){
    //Read the incoming byte
    incomingByte = Serial.read();
    //Start the message when the '<' symbol is received
    if(incomingByte == '<')
    {
     started = true;
     index = 0;
     msg[index] = '\0'; // Throw away any incomplete packet
   }
   //End the message when the '>' symbol is received
   else if(incomingByte == '>')
   {
     ended = true;
     break; // Done reading - exit from while loop!
   }
   //Read the message!
   else
   {
     if(index < 4) // Make sure there is room
     {
       msg[index] = incomingByte; // Add char to array
       index++;
       msg[index] = '\0'; // Add NULL to end
     }
   }
 }
 
 if(started && ended)
 {
   int value = atoi(msg);
   
   //analogWrite(ledPin, value);
   Serial.println(value); //Only for debugging
   if(calib_top){
   if(value == 0){
    top_value = rssiMapped;
    Serial.println(top_value);
    calib_top = false;
   }
   }
   
   index = 0;
   msg[index] = '\0';
   started = false;
   ended = false;
 }
}

Any help at all would be appreciated, bearing in mind my basic level of knowledge. I did the Mozzi introductory tutorials, so I get how to wire stuff together, but am not so clear on how to adapt the code.

Thank you in advance.

read the fact that there RSSI data there, but it doesn't seem to change the sound when the distance changes,

Are you expecting the signal strength to change when the distance changes? It will not. Just print out the values and see what they say. You will find that they do not change linearly with distance but keep roughly the same and then drop off very quickly as you loose the signal.

RSSI depends on a lot of things and generally can't be used to estimate distance.

RSSI is principally going to be sensitive to polarization and multipath interference, as a distance indicator its
pretty rough.

Thanks for the replies. I am not trying to get an EXACT distance measurement, but to get the sound to change with the RSSI values, which I have seen change as one XBee gets further away from the other.

Any idea how I can capture these values and use them to change the sound, exact or otherwise?

To read the XBEE RSSI pin as described on that web page, in addition to connecting the output pin to an Arduino input pin, you will also have to connect the XBEE ground and the Arduino ground.

Then, follow the instruction given on the web page:

Since this function gives you a duration, it’s up to you to map that to a value relevant to your program.

Use the Arduino map() function for that. Let us know how well it all works.

Thanks. I am using a shield for the Arduino (Nano) and XBee, so the ground is already connected. It's the mapping part I am struggling with, but will look further into that now.

I tried the mapping, and now get a repeating click when the two XBees are powered / connected, and no sound at all when either is disconnected. Changing the frequency in the code doesn't change anything with the sound. Any ideas?

#include <MozziGuts.h>
#include <Oscil.h> // oscillator template
#include <tables/sin2048_int8.h> // sine table for oscillator

// use: Oscil <table_size, update_rate> oscilName (wavetable), look in .h file of table #included above
Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA);

// use #define for CONTROL_RATE, not a constant
#define CONTROL_RATE 64 // Hz

int rssiDur = 0;
int rssiMapped = 0;
bool calib = false;
bool calib_top = false;
int base_value= 0;
int top_value=0;

void setup(){
    //Start the serial communication
  Serial.begin(9600); //Baud rate must be the same as is on xBee module
  pinMode(6, OUTPUT);
  calib = true;
  calib_top = true;
  startMozzi(CONTROL_RATE); // :)
  aSin.setFreq(660); // set the frequency
}


void updateControl(){
  // put changing controls in here
  rssiDur = pulseIn(5, LOW, 200);

  rssiMapped = map(rssiDur, 10, 40, 0, 1023);
  
  
  Serial.print("raw RSSI : ");
  Serial.println(rssiDur);
  Serial.print("RSSI mapped : ");
  Serial.println(rssiMapped);
  
  aSin.setFreq(rssiDur); 
}


int updateAudio(){
  return aSin.next(); // return an int signal centred around 0
}


void loop(){
  audioHook(); // required here
}

You seem to be using the serial port on the Arduino to talk to the XBees and the port monitor, you can’t do both at the same time.

Thanks Mike

Newbie question, but how do I change that (so it hopefully works?).

You could talk to the XBee using software serial.

How would that work (basic question, I know, but am a bit stuck here)?

You look up software serial and use two other pins to talk to the XBee.