Go Down

Topic: Have terminal bash script act as virtual "button" for Arduino? (Read 202 times) previous topic - next topic

realdannys

I've searched quite a lot for this and tried to piece bits of code together but with no luck so far.

All i'm looking to do is have a command I can run in terminal/bash script on the Mac trigger some code to run on the Arduino (Leonardo)

It doesn't matter what data the Mac sends, I only have one command to run so it doesn't need to look like separate buttons or anything.

So far i've tried

Code: [Select]
int incomingByte = 0;   // for incoming serial data
void setup() {
    Serial.begin(9600);
}

void loop() {

        // send data only when you receive data:
        if (Serial.available() > 0) {
                // read the incoming byte:
                incomingByte = Serial.read();
//run commands
  }
        }


and then from terminal/script both

Code: [Select]
echo "1" > /dev/tty.usbmodemHIDPC1 9600

and

Code: [Select]
screen > /dev/tty.usbmodemHIDPC1 9600

I see the Arduino light flash when I run those two commands in terminal which would seem to suggest that its receiving the data, but nothing runs.

I have stripped out my code that is due to be run by the way for simplicity. I also include keyboard.h and want the Leonardo send keyboard presses.

pert

I see the Arduino light flash when I run those two commands in terminal which would seem to suggest that its receiving the data, but nothing runs.
There's nothing to run in the code you posted.

I have stripped out my code that is due to be run by the way for simplicity. I also include keyboard.h and want the Leonardo send keyboard presses.
Don't add that extra complexity in yet. Start by getting an LED to turn on when the serial data is received.

realdannys

There's nothing to run in the code you posted.
Yes I know, that's why I said i've stripped my code out - the code i've got works perfectly - I just want it to be triggered my the terminal on the Mac.

GoForSmoke

I lined up the braces to make it easier to see at a glance. The baud rate and char instead of int are tips to try. Uno has 2K for heap and stack memory, if you develop good RAM habits from the start you can go far without a crash. BTW, don't use type String on Arduino.

Code: [Select]

char chr;   // for incoming serial data, type char is signed 8-bit, -128 to 127, ASCII is char codes. Save 1 byte over type int.

void setup()
{
    Serial.begin(115200);  // set serial monitor to this, it empties the outgoing buffer 12x faster than 9600.
}

void loop()
{
    // read data only when you receive data:
    if (Serial.available() > 0)
    {
        // read the next char in the Serial input buffer, might be the last/latest arrived
        chr = Serial.read();
        // run commands
        //     ummmmmmm, what commands?
        Serial.println( chr, HEX );
        // if ( chr == 'D' ) // do thing if key is D
    }
}


1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

realdannys

Thanks @GoForSmoke

I've used the below code but i've still got the same issue from terminal on the Mac.

If I use

Code: [Select]
echo "1" > /dev/tty.usbmodemHIDPC1 115200

Then I see the Leonardo LED flash once, but then nothing happens. Also it locks up terminal as if it's in a state of trying to send commands. Is there a terminal command I can add to the bash script that will effectively just ping the Arduino and exit so it's not locking the terminal session up?

Here is my Arduino code now.

Code: [Select]
#include <Keyboard.h>
char chr;   // for incoming serial data, type char is signed 8-bit, -128 to 127, ASCII is char codes. Save 1 byte over type int.
void setup() {
    Keyboard.begin();
    Serial.begin(115200);  // set serial monitor to this, it empties the outgoing buffer 12x faster than 9600.
}

void loop()
{
    // read data only when you receive data:
    if (Serial.available() > 0)
    {
        // read the next char in the Serial input buffer, might be the last/latest arrived
        chr = Serial.read();
        // run commands
        delay(3000);
  Keyboard.write('S');
  delay(100);
  Keyboard.write('Y');
  delay(100);
  Keyboard.write('S');
  delay(100);
  Keyboard.write('T');
  delay(100);
  Keyboard.write('E');
  delay(100);
  Keyboard.write('M');
  delay(100);
        Serial.println( chr, HEX );
        // if ( chr == 'D' ) // do thing if key is D
    }
}



I lined up the braces to make it easier to see at a glance. The baud rate and char instead of int are tips to try. Uno has 2K for heap and stack memory, if you develop good RAM habits from the start you can go far without a crash. BTW, don't use type String on Arduino.

Code: [Select]

char chr;   // for incoming serial data, type char is signed 8-bit, -128 to 127, ASCII is char codes. Save 1 byte over type int.

void setup()
{
    Serial.begin(115200);  // set serial monitor to this, it empties the outgoing buffer 12x faster than 9600.
}

void loop()
{
    // read data only when you receive data:
    if (Serial.available() > 0)
    {
        // read the next char in the Serial input buffer, might be the last/latest arrived
        chr = Serial.read();
        // run commands
        //     ummmmmmm, what commands?
        Serial.println( chr, HEX );
        // if ( chr == 'D' ) // do thing if key is D
    }
}




realdannys

Ah i've cracked triggering it!

It needs to be

Code: [Select]

echo "1" > /dev/cu.usbmodemHIDPC1 115200


That works and exits in terminal and triggers the command.

Now the only problem as it's in loop is that it keeps writing system over and over. Is there a way I can make it just write the command once and stop? I'm wanting to put this in a script where I have a lot of keyboard commands in just the void setup part which run once, but it seems I need to use loop for listening as it didn't work when I put this code into setup. It's just I only want it to run the code once, not loop forever once the byte is received.

Current code is

Code: [Select]
#include <Keyboard.h>
char chr;   // for incoming serial data, type char is signed 8-bit, -128 to 127, ASCII is char codes. Save 1 byte over type int.
void setup() {
    Keyboard.begin();
    Serial.begin(115200);  // set serial monitor to this, it empties the outgoing buffer 12x faster than 9600.
}

void loop()
{
    // read data only when you receive data:
    if (Serial.available() > 0)
    {
        // read the next char in the Serial input buffer, might be the last/latest arrived
        if (chr = Serial.read() > 0)
        {// run commands
        delay(3000);
  Keyboard.write('S');
  delay(100);
  Keyboard.write('Y');
  delay(100);
  Keyboard.write('S');
  delay(100);
  Keyboard.write('T');
  delay(100);
  Keyboard.write('E');
  delay(100);
  Keyboard.write('M');
  delay(100);
        Serial.println( chr, HEX );
        // if ( chr == 'D' ) // do thing if key is D
        }
    }
}


I lined up the braces to make it easier to see at a glance. The baud rate and char instead of int are tips to try. Uno has 2K for heap and stack memory, if you develop good RAM habits from the start you can go far without a crash. BTW, don't use type String on Arduino.

Code: [Select]

char chr;   // for incoming serial data, type char is signed 8-bit, -128 to 127, ASCII is char codes. Save 1 byte over type int.

void setup()
{
    Serial.begin(115200);  // set serial monitor to this, it empties the outgoing buffer 12x faster than 9600.
}

void loop()
{
    // read data only when you receive data:
    if (Serial.available() > 0)
    {
        // read the next char in the Serial input buffer, might be the last/latest arrived
        chr = Serial.read();
        // run commands
        //     ummmmmmm, what commands?
        Serial.println( chr, HEX );
        // if ( chr == 'D' ) // do thing if key is D
    }
}




GoForSmoke

 after it sends the message, read all available chars and it won't send the message until you trigger it again.

while( Serial.available())  Serial.read(); // empties the serial input buffer

Maybe take more time reading the code you have to start seeing how it works and what advantages you can take.

You could code the whole thing in setup() if you really only want 1 time action. Setup is where you put what only runs once.
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

pert

Also posted at:
https://arduino.stackexchange.com/q/60362
If you're going to do that then please be considerate enough to add links to the other places you cross posted. This will let us avoid wasting time due to duplicate effort and also help others who have the same questions and find your post to discover all the relevant information. When you post links please always use the chain links icon on the toolbar to make them clickable.

realdannys

after it sends the message, read all available chars and it won't send the message until you trigger it again.

while( Serial.available())  Serial.read(); // empties the serial input buffer

Maybe take more time reading the code you have to start seeing how it works and what advantages you can take.

You could code the whole thing in setup() if you really only want 1 time action. Setup is where you put what only runs once.
For me it didn't work at all if I put it in setup, and in loop as soon as I triggered it it kept repeating over and over rather than waiting for another trigger.

At the moment I did

Code: [Select]
#define EVER (;;)

and at the end of the loop

Code: [Select]
  Keyboard.write('l');
  delay(100);
        Serial.println( chr, HEX );
        // if ( chr == 'D' ) // do thing if key is D
 for EVER;


Probably not the cleanest way but it does make it run once and allows me to run single run code in setup.

Go Up