A bit of help with multiple shields please!

So I am using an EasyVR 3+ shield which works perfectly. I am also using the Adafruit Music Maker with amplifier shield and that works perfectly too. I've even stacked them and I can get one or the other to work perfectly but not both at the same time.

A bit of an introduction - I am building Wheatley from Portal 2. I want to use voice commands like "say hello" and he will go "hello!" etc with various different prompts. At the moment I am just testing relatively basic code to ensure it does what I want it to do. Later I will add servos and lights into the code too (which I have tested and also work very well). My problem is, I think that the EasyVR and the Music Maker shields are sharing some pins or something? I can only run one. Can you please review my code and advise? I am using an Arduino Uno.

This code is not really mine, it's a combination of the exported code from the EasyVR software and the Simple Music Player from the VS1053 library example. I've just frankenstein'd it together. I'm not a great coder and so this sort of stuff doesn't really come naturally to me. I expect I am going to get in trouble for not starting with something simpler!! That's just not how I learn unfortunately.

#include "Arduino.h"
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SdFat.h>
#if !defined(SERIAL_PORT_MONITOR)
  #error "Arduino version not supported. Please update your IDE to the latest version."
#endif
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer = 
  // create breakout-example object!
  //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
  // create shield-example object!
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
  
#if defined(__SAMD21G18A__)
  // Shield Jumper on HW (for Zero, use Programming Port)
  #define port SERIAL_PORT_HARDWARE
  #define pcSerial SERIAL_PORT_MONITOR
#elif defined(SERIAL_PORT_USBVIRTUAL)
  // Shield Jumper on HW (for Leonardo and Due, use Native Port)
  #define port SERIAL_PORT_HARDWARE
  #define pcSerial SERIAL_PORT_USBVIRTUAL
#else
  // Shield Jumper on SW (using pins 12/13 or 8/9 as RX/TX)
  #include "SoftwareSerial.h"
  SoftwareSerial port(12, 13);
  #define pcSerial SERIAL_PORT_MONITOR
#endif

#include "EasyVR.h"

EasyVR easyvr(port);

//Groups and Commands
enum Groups
{
  GROUP_0  = 0,
  GROUP_1  = 1,
};

enum Group0 
{
  G0_WHEATLEY = 0,
};

enum Group1 
{
  G1_SAY_HELLO = 0,
  G1_TELL_STORY = 1,
  G1_YOURE_A_MORON = 2,
  G1_BE_QUIET = 3,
  G1_CLOSE_EYE = 4,
};

//Grammars and Words
enum Wordsets
{
  SET_1  = -1,
  SET_2  = -2,
  SET_3  = -3,
};

enum Wordset1 
{
  S1_ACTION = 0,
  S1_MOVE = 1,
  S1_TURN = 2,
  S1_RUN = 3,
  S1_LOOK = 4,
  S1_ATTACK = 5,
  S1_STOP = 6,
  S1_HELLO = 7,
};

enum Wordset2 
{
  S2_LEFT = 0,
  S2_RIGHT = 1,
  S2_UP = 2,
  S2_DOWN = 3,
  S2_FORWARD = 4,
  S2_BACKWARD = 5,
};

enum Wordset3 
{
  S3_ZERO = 0,
  S3_ONE = 1,
  S3_TWO = 2,
  S3_THREE = 3,
  S3_FOUR = 4,
  S3_FIVE = 5,
  S3_SIX = 6,
  S3_SEVEN = 7,
  S3_EIGHT = 8,
  S3_NINE = 9,
  S3_TEN = 10,
};


// use negative group for wordsets
int8_t group, idx;

void setup()
{
  musicPlayer.begin();
  SD.begin(CARDCS);
  musicPlayer.setVolume(10,10);
  musicPlayer.playFullFile("/MORON001.wav");
  // setup PC serial port
  pcSerial.begin(9600);
bridge:
  // bridge mode?
  int mode = easyvr.bridgeRequested(pcSerial);
  switch (mode)
  {
  case EasyVR::BRIDGE_NONE:
    // setup EasyVR serial port
    port.begin(9600);
    // run normally
    pcSerial.println(F("Bridge not requested, run normally"));
    pcSerial.println(F("---"));
    break;
    
  case EasyVR::BRIDGE_NORMAL:
    // setup EasyVR serial port (low speed)
    port.begin(9600);
    // soft-connect the two serial ports (PC and EasyVR)
    easyvr.bridgeLoop(pcSerial);
    // resume normally if aborted
    pcSerial.println(F("Bridge connection aborted"));
    pcSerial.println(F("---"));
    break;
    
  case EasyVR::BRIDGE_BOOT:
    // setup EasyVR serial port (high speed)
    port.begin(115200);
    pcSerial.end();
    pcSerial.begin(115200);
    // soft-connect the two serial ports (PC and EasyVR)
    easyvr.bridgeLoop(pcSerial);
    // resume normally if aborted
    pcSerial.println(F("Bridge connection aborted"));
    pcSerial.println(F("---"));
    break;
  }

  // initialize EasyVR  
  while (!easyvr.detect())
  {
    pcSerial.println(F("EasyVR not detected!"));
    for (int i = 0; i < 10; ++i)
    {
      if (pcSerial.read() == '?')
        goto bridge;
      delay(100);
    }
  }

  pcSerial.print(F("EasyVR detected, version "));
  pcSerial.print(easyvr.getID());

  if (easyvr.getID() < EasyVR::EASYVR3)
    easyvr.setPinOutput(EasyVR::IO1, LOW); // Shield 2.0 LED off

  if (easyvr.getID() < EasyVR::EASYVR)
    pcSerial.print(F(" = VRbot module"));
  else if (easyvr.getID() < EasyVR::EASYVR2)
    pcSerial.print(F(" = EasyVR module"));
  else if (easyvr.getID() < EasyVR::EASYVR3)
    pcSerial.print(F(" = EasyVR 2 module"));
  else
    pcSerial.print(F(" = EasyVR 3 module"));
  pcSerial.print(F(", FW Rev."));
  pcSerial.println(easyvr.getID() & 7);

  easyvr.setDelay(0); // speed-up replies

  easyvr.setTimeout(5);
  easyvr.setLanguage(0); //<-- same language set on EasyVR Commander when code was generated

  group = EasyVR::TRIGGER; //<-- start group (customize)
}

void loop()
{
  if (easyvr.getID() < EasyVR::EASYVR3)
    easyvr.setPinOutput(EasyVR::IO1, HIGH); // LED on (listening)

  if (group < 0) // SI wordset/grammar
  {
    pcSerial.print("Say a word in Wordset ");
    pcSerial.println(-group);
    easyvr.recognizeWord(-group);
  }
  else // SD group
  {
    pcSerial.print("Say a command in Group ");
    pcSerial.println(group);
    easyvr.recognizeCommand(group);
  }

  do
  {
    // allows Commander to request bridge on Zero (may interfere with user protocol)
    if (pcSerial.read() == '?')
    {
      setup();
      return;
    }
    // <<-- can do some processing here, while the module is busy
  }
  while (!easyvr.hasFinished());
  
  if (easyvr.getID() < EasyVR::EASYVR3)
    easyvr.setPinOutput(EasyVR::IO1, LOW); // LED off

  idx = easyvr.getWord();
  if (idx == 0 && group == EasyVR::TRIGGER)
  {
    // beep
    easyvr.playSound(0, EasyVR::VOL_FULL);
    // print debug message
    pcSerial.println("Word: ROBOT");
    // write your action code here
    // group = GROUP_X\SET_X; <-- jump to another group or wordset
    return;
  }
  else if (idx >= 0)
  {
    // beep
    easyvr.playSound(0, EasyVR::VOL_FULL);
    // print debug message
    uint8_t flags = 0, num = 0;
    char name[32];
    pcSerial.print("Word: ");
    pcSerial.print(idx);
    if (easyvr.dumpGrammar(-group, flags, num))
    {
      for (uint8_t pos = 0; pos < num; ++pos)
      {
        if (!easyvr.getNextWordLabel(name))
          break;
        if (pos != idx)
          continue;
        pcSerial.print(F(" = "));
        pcSerial.println(name);
        break;
      }
    }
    // perform some action
    action();
    return;
  }
  idx = easyvr.getCommand();
  if (idx >= 0)
  {
    // beep
    easyvr.playSound(0, EasyVR::VOL_FULL);
    // print debug message
    uint8_t train = 0;
    char name[32];
    pcSerial.print("Command: ");
    pcSerial.print(idx);
    if (easyvr.dumpCommand(group, idx, name, train))
    {
      pcSerial.print(" = ");
      pcSerial.println(name);
    }
    else
      pcSerial.println();
    // perform some action
    action();
  }
  else // errors or timeout
  {
    if (easyvr.isTimeout())
      pcSerial.println("Timed out, try again...");
    int16_t err = easyvr.getError();
    if (err >= 0)
    {
      pcSerial.print("Error ");
      pcSerial.println(err, HEX);
    }
  }
}

void action()
{
  switch (group)
  {
  case GROUP_0:
    switch (idx)
    {
    case G0_WHEATLEY:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    }
    break;
  case GROUP_1:
    switch (idx)
    {
    case G1_SAY_HELLO:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case G1_TELL_STORY:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case G1_YOURE_A_MORON:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case G1_BE_QUIET:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case G1_CLOSE_EYE:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    }
    break;
  case SET_1:
    switch (idx)
    {
    case S1_ACTION:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S1_MOVE:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S1_TURN:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S1_RUN:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S1_LOOK:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S1_ATTACK:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S1_STOP:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S1_HELLO:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    }
    break;
  case SET_2:
    switch (idx)
    {
    case S2_LEFT:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S2_RIGHT:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S2_UP:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S2_DOWN:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S2_FORWARD:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S2_BACKWARD:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    }
    break;
  case SET_3:
    switch (idx)
    {
    case S3_ZERO:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_ONE:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_TWO:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_THREE:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_FOUR:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_FIVE:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_SIX:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_SEVEN:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_EIGHT:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_NINE:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    case S3_TEN:
      // write your action code here
      // group = GROUP_X\SET_X; <-- or jump to another group or wordset for composite commands
      break;
    }
    break;
  }
}

At first glance, it seems like maybe you have the chip select pins routed to all the shields. If you have identical shields, they have identical chip selects and that won't normally work. Usually you need to run separate chip selects to each device. But shields share all pins.

If it's not that, you still may have some shield pin conflict. Troubleshooting requires detailed understanding of the particular shield pins and what they're used for. So you should go to your shield documentation for that, we don't have it.

@anon61647709, your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with your project :wink: See About the Installation & Troubleshooting category.

Oh, so sorry! I couldn't see anywhere better. Where is it now? Do I need to do anything?

Read reply #2, the last sentence.

Don't worry, it is already moved so you don't have to do anything. See the info under the title (in below image) to figure out where it is now :wink:

image

1 Like

The amount of time it took you to write this? Why didn't you just answer or not reply? So many people here are really scathing and horrid, I see it so often - why??? Why not just go about your life?

Thank you, I didn't realise that the shields communicated beyond just what was written in the code, and turns out you are exactly right. They both use 12 and 13. The EasyVR board allows you to move two teeny tiny resistors on the back to use pins 8 and 9 instead which the Music Maker board doesn't use according to its specs.

I'm not sure what you mean about running separate chip selects to each device - would you be able to explain this as if I am an idiot please :smiley:

Those are part of the SPI bus; pins 11 and 10 are also part of that. And you have configured your EasyVR to use the pins 12 and 13 (via SoftwareSerial) so you do have a conflict.

I don't think that it applies in this case as only one board uses the SPI interface.

SPI is a bus and you can connect mutltiple slave devices to it; those devices share the signals MOSI, MISO and SCK. Each device also has a chip select pin (in your case even two); if you want to talk to a specific device (or in your case a specific part of your board), you select that device (or part of the board) by activating its chip select line.

This is all done for you in the library but you have to specify it which is done in the constructor.

Note
The Arduino Uno also has a SS pin (pin 10) as part of its SPI interface; it's the slave select and must be set as output if you want to talk to the slave devices; the library that you use will (more than likely) handle that for you. If you want the Arduino (usually not the case) to be a slave, you need to set it to input. This pin is often used as a slave select pin but you can use other pins for that purpose (as done with your Adafruit shield).

Thank you so much. This was really helpful! I've configured the Music Maker board to use the 3x2 SPI pin thingy on the end (which it is designed to do as an option, and as a requirement for Mega which I am upgrading to). I will post photos here for future readers once I get it all working!

The thing is, it's the correct answer. Hence you shouldn't regard it as scathing. Your question was, "do I need to do anything?". My suggestion was simply and solely exactly what I would do. I would go and consult the documentation. So "see such and such a reply" in this case is equivalent to "please consult the documentation", which is exactly the way I have been successfully researching and solving issues for many decades now. It's a straightforward, not a sarcastic response.

More so because so few people here would have the same hardware configuration as yours.

1 Like

Not you, you have been helpful thank you. I quoted the guy Railroad who was unhelpful and went out of his way to be unhelpful. Sorry if that wasn’t clear.

Edit: I understand more what you were saying. When I said “do I need to do anything?” I was referring to the person who moved my post to the correct place, and Railroad was telling me I need to read the reply of the person who moved the post. He wasn’t trying to help. Reply #2 is the person who moved my post to the correct place.

Please then quote who You're answering!
It's an illness here that several helpers answer, and You make one reply. To which helper? Sorry I made You upset.
As told before, giving the data asked for, the replies will be a lot different.
Reading data sheets and understanding them is number one in electronics. I've done that for more than 40 years. No internet, no salvator to ask at that time.

I literally quoted you, do I need to screenshot for you? You told me to read Reply #2 the last sentence. I did that. It was the person telling me the post has been moved. And I literally quoted you when I replied.

I'm so sorry the internet wasn't around for your career. That must've been hard for you. The world is so much better with the internet, don't you agree?

No, it was not hard at all. It was very educational to use the source of most knowledge, the manufactorers manual, the data sheets. There's where most helpers picked up their knowledge.
Okey, topics being moved or merged sometimes confuses.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.