Arduino Yun linux and bluetooth conflict

I am working with Arduino Yun and camera connected to its USB Host.

I have added to arduino Adafruit NRF8001 BLE module and hacked the camera so I can use my smartphone to execute several options like power on/off the camera and start recording for instance - this part works good. On top of that one of the commands sent from smartphone is to execute python script which is on the openWRT side that uploads contents of the camera SD card to dropbox. And here is my problem because as soon as I try to execute the linux script the bluetooth connections drops (and the script is not executed - so it drops when it tries to connect to openWRT I guess, using bridge).

I am suspecting that is has to do something with the UART or rx/tx communication but I can’t seem to pinpoint what exactly goes wrong. Maybe it is because I didn’t fully understood Arduino Yun’s architecture. I am rather a beginner and I would be glad to hear any pointers where to look or what to take into the consideration. Thank you in advance for any help.

I do realise that is quite specific, but I was hoping that maybe someone will notice some obvious mistake :wink:

And last but not least the Arduino code:

//LIBRARIES
#include <SPI.h>
#include <Adafruit_BLE_UART.h>
#include <Bridge.h>
#include <Process.h>
//#include <Adafruit_BLE_Firmata.h>
//#include <Boards.h>
//#include <Shifter.h>
//#include <Console.h>

//BLUETOOTH
#define ADAFRUITBLE_REQ 3
#define ADAFRUITBLE_RDY 2
#define ADAFRUITBLE_RST 4

Adafruit_BLE_UART uart = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);
static bool isBTConnected = false;

void initBluetooth () {
  uart.setRXcallback(rxCallback);
  uart.setACIcallback(aciCallback);
  uart.setDeviceName(PSTR("test")); /* 7 characters max! */
  Serial.print(F("BT:"));
  if (uart.begin())
    Serial.println(F("OK"));
  else
    Serial.println(F("FAILED"));
}

void aciCallback(aci_evt_opcode_t event) {
  switch (event)
  {
    case ACI_EVT_DEVICE_STARTED:
     // Serial.println(F("Advertising started"));
      break;
    case ACI_EVT_CONNECTED:
      isBTConnected = true;
      //Serial.println(F("Connected!"));
      break;
    case ACI_EVT_DISCONNECTED:
      isBTConnected = false;
     // Serial.println(F("Disconnected or advertising timed out"));
      break;
    default:
     // Serial.print(F("ACI OPCODE:"));
      Serial.println(event);
      break;
  }
}

void rxCallback(uint8_t *buffer, uint8_t len) {

  uint8_t target_len = 4;
  const char* target = "open";
  uint8_t counter = 0;
  char ByteReceived; 
  //float test_output;
  //test_output = 5,5;

    Serial.print(F("Received "));
    Serial.print(len);
    Serial.print(F(" bytes: "));

  for (int i = 0; i < len; i++) {
    char ch = (char)buffer[i];
    Serial.print(ch);
    ByteReceived = ch;


   switch (ByteReceived) {
   case 'p':
   power();
   uart.print("Power Received!");
   break;

   case 'm':
   change_mode();
   uart.print("Mode changed");
   break;

   case 's':
   shutter();
   uart.print("Recording");
   break;

   case 'd':
   uart.print("DEBUG");
   delay(2000);
   upload2dropbox();
   uart.print("File uploaded!");
   break;
                          }
                               }   
 }


//CONTROLS
void upload2dropbox() {

int spk = 4;
int freq = 800;
pinMode(spk, OUTPUT);

//I was debuging and after this line BLE disconects

tone(spk, freq);
delay(16);
noTone(spk);  

Process p;

//p.begin("curl");
//p.runShellCommandAsynchronously("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");
//p.addParameter("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");
//p.run();
//Serial.flush();
//p.close();

p.begin("python");
p.addParameter("/root/dropbox_run.py");
p.run();
p.close();

tone(spk, freq);
delay(16);
noTone(spk);
tone(spk, freq);
delay(16);
noTone(spk);
}

void power() { //Turn the power ON or OFF

int spk = 6;
int freq = 800;
pinMode(spk, OUTPUT);

int powerButton = A5; 

digitalWrite(powerButton, HIGH);
delay(500);  // Wait half a second
digitalWrite(powerButton, LOW);


tone(spk, freq);
delay(16);
noTone(spk);
delay(100);
tone(spk, freq);
delay(16);
noTone(spk);
delay(100);
tone(spk, freq);
delay(16);
noTone(spk);
delay(100);

Serial.println(F("Camera is turned ON or OFF"));
}

void change_mode() { //Change the mode of the camera

int spk = 6;
int freq = 800;
pinMode(spk, OUTPUT);

int modeButton = A3; 
int led = 7;

digitalWrite(modeButton, HIGH);
digitalWrite(led, HIGH);
delay(500);  // Wait half a second
digitalWrite(modeButton, LOW);
digitalWrite(led, LOW);

tone(spk, freq);
delay(16);
noTone(spk);

//int led = 7;
//shifter.setPin(1, HIGH);
//shifter.write();
//digitalWrite(led, HIGH);
//delay(500);  // Wait half a second
//shifter.setPin(1, LOW);
//shifter.write();// Release the mode button.
//digitalWrite(led, LOW);

Serial.println(F("Mode is changed"));
}

void shutter() { //Shutter control 

int spk = 6;
int freq = 800;
pinMode(spk, OUTPUT);

int shutterButton = A4; 
int led = 7;

digitalWrite(shutterButton, HIGH); // Activate the shutter button
digitalWrite(led, HIGH);
delay(500);  // Wait half a second
digitalWrite(shutterButton, LOW);  // Release the shutter button.
digitalWrite(led, LOW);

delay(1000);

tone(spk, freq);
delay(50);
noTone(spk);
delay(100);
tone(spk, freq);
delay(50);
noTone(spk);

Serial.println(F("Recording is ON or OFF"));

}  


//SETUP
void setup () {

  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A5, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);



  Serial.begin(9600);
  Serial.println(F("BT+ETH"));
  Bridge.begin();
  initBluetooth();

}

void loop () {

uart.pollACI();
digitalWrite(5, HIGH);
}

To make things clear this is the python script I am calling:

#!/usr/bin/python
import sys
import subprocess


subprocess.call(['./dropbox_uploader.sh', '-k', 'upload', '/mnt/sdb1/test2.txt', 'test2.txt'])

As you can see I am actually only calling the .sh script and by default it would be cool to just call it but while trying to solve the problem I though maybe an .sh file is making some problems so I wrapped it into python. Probably this is not the case but I guess it is important to mention it.

I suspect that your Process run() call is never returning. You can verify this by adding some debug output:

Serial.println("Calling process");
p.begin("python");
p.addParameter("/root/dropbox_run.py");
p.run();
Serial.println("Returned from process:");
while (p.available())
   Serial.print((char)p.read());
Serial.println();
Serial.println("End of process output");

I did not try to compile this, so I might have a subtle bug in there...

This prints out a message before and after the process is run. If you don't see the returned from process message, you know that it's the process that is holding things up. The process.run() command won't return until the spawned Linux process has finished and returned. Once it returns, these changes print a message to that effect, and then display any output generated by the process.

You include your Puthon script, but not your .sh script. Is it possible that the script is never returning? Have you tried running manually it from the SSH command line? Does it return? Does it generate a lot of output?

Another possibility is that you are running the process synchronously. Any output from the process gets buffered, and then you can read that output once the process is done (as shown by the added p.available() loop in the code above.) If the script being run is generating a lot of output, and the buffer is filling up before the process can complete, I think things will lock up at that point: the script will block until there is room in the buffer, but nothing will be removed from the buffer because the sketch is blocked until the script finishes. But the script can't finish because it is blocked by the full buffer. A classic deadly embrace.

If this is what's happening, the solution is to run the process asynchronously. This lets the sketch still run, and process the output from the process, which should allow the process to run to completion. Again, I haven't compiled or tested this code, but it would look something like:

Serial.println("Calling process");
p.begin("python");
p.addParameter("/root/dropbox_run.py");
p.runAsynchronously();
while (p.running())
   if (p.available())
      Serial.print((char)p.read());
Serial.println();
Serial.println("Process returned");

Looking at the commented out sections of your code, it looks like you were doing some experimenting with the Process class:

//p.runShellCommandAsynchronously("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");
//p.addParameter("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");

Be aware that runShelCommand() and runShellCommandAsynchronously() expect the entire command, including all of the parameters, to be included in the command line string. addParameter() has no meaning with either of those two functions. addParameter() is only used in the context of a begin() followed by run() or runAsynchronously(), with the parameters being added after the begin() and before either of the run commands.

I think that you should be able to run your .sh script directly, without needing a Python wrapper. If that didn't work for you, it may again be because it's generating too much output? Maybe you could try something like this:

Serial.println("Calling process");
p.runShellCommandAsynchronously("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");
while (p.running())
   if (p.available())
      Serial.print((char)p.read());
Serial.println();
Serial.println("Process returned");

If this works, and you see lots of output from the command, it could be the deadly embrace mentioned earlier. Once you get it working, if you don't need the debug output, you could simplify either version to:

p.begin("python");
p.addParameter("/root/dropbox_run.py");
p.runAsynchronously();
while (p.running())
   if (p.available())
      p.read());
p.runShellCommandAsynchronously("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");
while (p.running())
   if (p.available())
      p.read());

Thank you ShapeShifter, again for a very good input. I have read it couple of times now and did some testing.

I have inserted part of the code directly under the “case” and now the bluetooth connection doesn’t drop but the script is not executed either:

The code under the case:

case 'd':
   uart.print("DEBUG");
   delay(2000);
   Process p;
   p.begin("python");
   p.addParameter("/root/dropbox_run.py");
   p.runAsynchronously(); 
   while (p.running())
   if (p.available())
      Serial.print((char)p.read());
   Serial.println();
   Serial.println("Process returned");
  // upload2dropbox();
   uart.print("File uploaded!");
   break;

And the serial output:

Received 2 bytes: d Writing out to BTLE: 0x44 0x45 0x42 0x55 0x47

Process returned
 Writing out to BTLE: 0x46 0x69 0x6C 0x65 0x20 0x75 0x70 0x6C 0x6F 0x61 0x64 0x65 0x64 0x21

I am unsure what is exactly wrong as this is supposed to be quite straight forward.

To answer your questions:

“You include your Puthon script, but not your .sh script. Is it possible that the script is never returning? Have you tried running manually it from the SSH command line? Does it return? Does it generate a lot of output?”

This is the .sh script that I am using: github

And yes, I have been executing it from the ssh command line both directly through .sh and python and both work fine and seem to return. I am not sure what you mean buy generating output but there is none - like a one line confirming that the file has been uploaded and I can see the file in my dropbox folder.

EDIT:

I have made this simplified version just to test python script execution, everything seems fine yet the script doesn’t run.

#include <Adafruit_BLE_UART.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BLE_Firmata.h>
//#include <Firmata.h>
#include <Boards.h>
#include <Bridge.h>
//#include <Shifter.h>
#include <Process.h>
#include <Console.h>
#define led 5

void python() {
   Serial.println("Cameras are ON/OFF");
      
      Process p;
      p.begin("python");
      p.addParameter("/root/dropbox_run.py");
      p.runAsynchronously(); 
        while (p.running())
        if (p.available())
        Serial.print((char)p.read());
        Serial.println();
        Serial.println("Process returned");

        Serial.println("debug message");
}

void setup(){ 

  
  Bridge.begin();
  Serial.begin(9600);
  delay(2000);


  while (!Serial) 


  Serial.println("Enter d to test python code");
 

}

void loop(){  
  if (Serial.available() > 0){
    int ByteReceived = Serial.read();

    switch (ByteReceived){
      case 'd':
     python();
        break;
      
    }
  } 

}

This is serial monitor output for the simplified script:

Cameras are ON/OFF

Process returned
debug message

OK, so the added debug messages show that the process is running and completing, and it is not generating so much output that the original method of using p.run() should cause things to block as I originally suspected.

This is a bit of an older thread, and I had to go back and re-read things to try and remember the problem. But it appears that you are complaining that when you try to upload a file, it fails and the bluetooth interface disconnects. You seemed to think that it had something to do with the upload process, so I was focused on that.

But now that I go back and re-read your original post, I see this section of code:

void upload2dropbox() {

int spk = 4;
int freq = 800;
pinMode(spk, OUTPUT);

//I was debuging and after this line BLE disconects

tone(spk, freq);
delay(16);
noTone(spk);  

Process p;

//p.begin("curl");
//p.runShellCommandAsynchronously("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");
//p.addParameter("./dropbox_uploader.sh -k upload /mnt/sda1/test2.txt test2.txt");
//p.run();
//Serial.flush();
//p.close();

p.begin("python");
p.addParameter("/root/dropbox_run.py");
p.run();
p.close();

I was so focused on the process code at the end of this snippet that I missed your comment at the beginning of the function. Your comment indicates that the bluetooth module disconnects after the tone() function call. That makes perfect sense: that statement is generating an 800 Hz tone on pin 4, which is the same pin that is used to reset the bluetooth module. You apparently have a pin conflict going on.

Part of the problem may be that you are defining the pin number for the spk output locally in the function. I find it most helpful to define ALL of my pin definitions at the same place, either near the top of the sketch, or in a separate include file. If you group this spk pin definition together with the BLE module pin definitions, it would be much easier to spot that you have two functions using the same pin for conflicting purposes.

OMG, yes the pin conflict is a problem that was causing the Bluetooth disconnecting, I can't believe I didn't notice that ! Thanks a lot ! Really such little thing, thanks for the tips though, you are right that grouping them together makes easier to spot the mistake I will try to do so from now on.

Unfortunately even though the bluetooth connection is not dropped the script is still not executed. Even in a simplified code I posted earlier today. I can't seem to find why. I have read your answer in some other thread about Prosess function and you said that most often the problem lies in the absolute path, I think I have checked that and everything seems fine. One thing though: I have been expanding Yun's space onto the sd card, could that be a problem?

And thanks for bearing with me on that :wink:

domagalski:
I have read your answer in some other thread about Prosess function and you said that most often the problem lies in the absolute path, I think I have checked that and everything seems fine.

In my experience, that seems to be the most common reason why a script would work from the command line, but not from a Process call in a sketch.

When run from a Process object in your sketch, the current directory will be one of the internal bridge library directories. It won't necessarily have anything to do with the command you are running or any of the files you are referencing in your command.

This is the Python code you posted earlier:

#!/usr/bin/python
import sys
import subprocess


subprocess.call(['./dropbox_uploader.sh', '-k', 'upload', '/mnt/sdb1/test2.txt', 'test2.txt'])

The path to the command script is relative: the leading dot says to look in the current directory. You can't make any assumptions about the current directory. Change it to use the full explicit path to the script, starting from the root folder: "/"

One thing though: I have been expanding Yun's space onto the sd card, could that be a problem?

Doubtful. I have always run my Yuns with the system expanded onto the SD card.

And a hit again! I didn't understood properly this dot at the beginning of the path line, basics I know...

The python script works now as desired and there are no problems with bluetooth! Thank you so much for help to find that out :slight_smile:

Also the .sh script work well too so actually no need for a python wrapper. Yay!

Last thing that does not work as I want is assigning a name to Bluetooth as it changes all the time sometimes to UART and sometimes to random words (or parts of words) from uart.print commands. Any idea about that (to squeeze your knowledge even more) :).

domagalski:
Last thing that does not work as I want is assigning a name to Bluetooth as it changes all the time sometimes to UART and sometimes to random words (or parts of words) from uart.print commands. Any idea about that (to squeeze your knowledge even more) :).

I'm afraid I don't know anything about that Bluetooth module, so I'm not sure of the significance of you problem or what might be causing it. It sounds like there is a name associated with it, and that name keeps changing based on what you are printing to it? If that's the case, I would study the commands and data you are to send to the Bluetooth module - there may be something invalid you are sending it in one or more of your uart.print() command.

I'm afraid I don't know anything about that Bluetooth module

I though so, nevertheless I though it is worth a shot to ask.

I am going to do as you suggest, anyway thank you again for all the help!!!

domagalski:
I though so, nevertheless I though it is worth a shot to ask.

Absolutely worth a try! If you ask, you may or may not get a useful answer. If you don't ask, you definitely won't get an answer.

Besides, I'm not the only one here: someone else with knowledge of the module could very easily see this and step in with an answer.

You've got nothing to lose by asking.