How to make Arduino run a script - arduino

i'm a software developer but i'm new to Arduino, and to the electronics world.
I would like to build a simple project that combined both, and really appreciate any help where to start.
final project should be Arduino with a button and a LED, when tapping the button I want run a script on my mac, then if the script finished successfully i want to turn on the LED
I already saw some tutorial about how to use buttons and LEDs so
the main thing i'm interested here is how communicate from the Arduino to the mac and vice versa. and especially how to make it run a script on my mac.

You should look into the Serial class and the examples (via File > Examples > Commmunication)
You will need to write a bit of code on the Arduino side to send data via Serial when the button is pressed (so you can trigger your script) and receive data (when the script is done) to control the LED.
Here is a rough example on the Arduino side:
const int btnPin = 12;//button pin
const int ledPin = 13;
int lastButtonState;
void setup(){
//setup pins
pinMode(btnPin,INPUT_PULLUP);
pinMode(ledPin,OUTPUT);
//setup communication
Serial.begin(9600);
}
void loop() {
int currentButtonState = digitalRead(btnPin);//read button state
if(lastButtonState != currentButtonState && currentButtonState == LOW){//if the state of the pin changed
Serial.write(currentButtonState);//send the data
lastButtonState = currentButtonState;//update the last button state
//turn on LED
digitalWrite(ledPin,HIGH);
}
}
void serialEvent(){//if any data was sent
if(Serial.available() > 0){//and there's at least 1 byte to look at
int data = Serial.read();//read the data
//do something with it if you want
//turn off the LED
digitalWrite(ledPin,LOW);
}
}
Be aware you may have different pin numbers in your setup and depending on how the button wired, you will either look for a LOW or HIGH value in the in the condition checking the currentButtonState.
In terms of the communication there are a few key elements:
Serial.begin(9600);
Starts Serial communication with baud rate 9600. You will need to match this baud rate on the other end to ensure correct communication.
Serial.write();
Will send data to the port.
serialEvent()
is predefined in Arduino and gets called when new Serial data arrives.
Note that this gets called automatically on a Arduino Uno (and other simpler boards), however this doesn't get called on other boards:
serialEvent() doesn’t work on the Leonardo, Micro, or Yún.
serialEvent() and serialEvent1() don’t work on the Arduino SAMD Boards
serialEvent(), serialEvent1()``serialEvent2(), and serialEvent3() don’t work on the Arduino Due.
On the script side, you haven't mentioned the language, but the principle is the same: you need to know the port name and baud rate to establish communication from your mac.
(You can manually call serialEvent() in loop() as a workaround. For more details see the Arduino Reference)
The port is what you used to upload the Arduino code (something like /dev/tty.usbmodem####) and in this particular case the baud rate is 9600. You should be able to test using Serial Monitor in the Arduino IDE.
Your script will be something along there lines (pseudo code)
open serial connection ( port name, baudrate = 9600 )
poll serial connection
if there is data
run the script you need
script finished executing, therefore send data back via serial connection
Be sure to checkout the Interfacing with Software to find guide on the scripting language of your choice
Update
Here's a quick example using Processing to interface with the arduino using it's Serial library. So on the Arduino side, here's a minimal sketch:
const int btnPin = 12;//button pin
const int ledPin = 13;
boolean wasPressed;
char cmd[] = "/Applications/TextEdit.app\n";
void setup(){
//setup pins
pinMode(btnPin,INPUT_PULLUP);
pinMode(ledPin,OUTPUT);
//setup communication
Serial.begin(9600);
}
void loop() {
int currentButtonState = digitalRead(btnPin);//read button state
if(!wasPressed && currentButtonState == LOW){//if the state of the pin changed
Serial.write(cmd);//send the data
wasPressed = true;//update the last button state
//turn on LED
digitalWrite(ledPin,HIGH);
}
if(currentButtonState == HIGH) wasPressed = false;
}
void serialEvent(){//if any data was sent
if(Serial.available() > 0){//and there's at least 1 byte to look at
int data = Serial.read();//read the data
//do something with it if you want
//turn off the LED
digitalWrite(ledPin,LOW);
}
}
and on the Processing side:
import processing.serial.*;
void setup(){
try{
Serial arduino = new Serial(this,"/dev/tty.usbmodemfa141",9600);
arduino.bufferUntil('\n');//buffer until a new line is encountered
}catch(Exception e){
System.err.println("Error opening serial connection! (check cables and port/baud settings!");
e.printStackTrace();
}
}
void draw(){}
void serialEvent(Serial s){
String[] command = s.readString().trim().split(",");//trim spaces, split to String[] for args
println(command);//see what we got
open(command);//run the command
s.write("A");//send a message back to flag that the command is finished (turn LED off)
}
Hope this is a helpful proof of concept. Feel free to use any other language with a serial library available instead of Processing. The syntax may differ just a tad (probably more on the running of the process/command), but the concept is the same.
Update The example above can be simplified a touch by not having the command on the Arduino side:
there's less data sent on Serial from Arduino to Processing reducing communication time and the odds of communication interference
the app runs on a computer hence changing the command is simpler to do on software side as opposed to having to change the Arduino code and re-upload each time.
Arduino:
const int btnPin = 12;//button pin
const int ledPin = 13;
boolean wasPressed;
void setup(){
//setup pins
pinMode(btnPin,INPUT_PULLUP);
pinMode(ledPin,OUTPUT);
//setup communication
Serial.begin(9600);
}
void loop() {
int currentButtonState = digitalRead(btnPin);//read button state
if(!wasPressed && currentButtonState == LOW){//if the state of the pin changed
Serial.write('R');//send the data
wasPressed = true;//update the last button state
//turn on LED
digitalWrite(ledPin,HIGH);
}
if(currentButtonState == HIGH) wasPressed = false;
}
void serialEvent(){//if any data was sent
if(Serial.available() > 0){//and there's at least 1 byte to look at
int data = Serial.read();//read the data
//do something with it if you want
//turn off the LED
digitalWrite(ledPin,LOW);
}
}
Processing:
import processing.serial.*;
String[] command = {"/Applications/TextEdit.app", "myText.txt"};
void setup() {
try {
Serial arduino = new Serial(this, "/dev/tty.usbmodemfa141", 9600);
}
catch(Exception e) {
System.err.println("Error opening serial connection! (check cables and port/baud settings!");
e.printStackTrace();
}
}
void draw() {
}
void serialEvent(Serial s) {
if (s.read() == 'R') {
launch(command);//run the command
s.write("A");//send a message back to flag that the command is finished (turn LED off)
}
}
(btw, 'R' is an arbitrary single character, can be something else as long it's the same char on both Serial send and receive sides)
Also, bare in mind launch() returns Proccess which can be useful to get more information from the software launched.

Dunno if it will help you as much as it did me but this question shows a simple example of how to use the script with a simple button in an android app
Run script with android app
Hope it helps

I found a workaround in Linux. It's a little messy but it works. I use Coolterm to capture the serial output from the arduino to a text file and I wrote a small python script that reads the file (or simply, in my case, executes the command I want if the file is not empty).

Related

Reading Data from Bluetooth using HC-05 Serial

I am having trouble reading data from the bluetooth serial interface on the Arduino.
Here my code:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(8, 7); // RX, TX
void setup() {
mySerial.begin(38400);
Serial.begin(38400);
}
String Data = "";
void loop(){
//mySerial.println("Bluetooth Out");
while(mySerial.available()){
char character = mySerial.read();
Data.concat(character);
if (character == '\n'){
Serial.print("Received: ");
Serial.println(Data);
Data = "";
}
}
}
This should take whatever I enter into the bluetooth serial and print it on the regular serial port. Here is what I've tried:
If I uncomment mySerial.println("Bluetooth Out"); then I see the message bring printed out to the bluetooth terminal.
I tried similar to above to print to normal serial out and I see it being printed.
I've tried multiple ways (from some tutorials online) to decode the string and the data coming from mySerial, but nothing is happening.
I am using arduino Serial Monitor to check the ports, however I also tried to use the bluetooth terminal on my laptop and same behavior.
So I guess, what is the proper way for me to read data from the bluetooth serial port?

use another serial to send data from arduino to processing

i need to use another serial to send data from arduino teensy to processing because default serial (Serial.begin(9600)) already used for big program
i try to read some reference about how maybe i can change from which serial i want to receive (https://processing.org/reference/libraries/serial/Serial.html), but i dont think it can be change
void setup() {
Serial.begin(115200); // already used
Serial2.begin(9600); // processing
}
void loop() {
Serial.println("...") //big code that i am not allow to change
Serial2.println("hello world");
delay(1000);
}
i expected to get "hello world" in my processing repeatly, but i really dont have any idea how to write the code so i can get value from Serial2 instead from Serial
It depends on what Teensy module you are using and how you're doing the wiring.
Please see the Teensy Using the Hardware Serial Ports article for more details.
If possible I'd try their UART/USB example:
// set this to the hardware serial port you wish to use
#define HWSERIAL Serial1
void setup() {
Serial.begin(9600);
HWSERIAL.begin(9600);
}
void loop() {
int incomingByte;
if (Serial.available() > 0) {
incomingByte = Serial.read();
Serial.print("USB received: ");
Serial.println(incomingByte, DEC);
HWSERIAL.print("USB received:");
HWSERIAL.println(incomingByte, DEC);
}
if (HWSERIAL.available() > 0) {
incomingByte = HWSERIAL.read();
Serial.print("UART received: ");
Serial.println(incomingByte, DEC);
HWSERIAL.print("UART received:");
HWSERIAL.println(incomingByte, DEC);
}
}
If that hows with the same USB connection at the same time, negotiate with your colleague so you get to use the easier one that simply shows up as another Serial port in Processing.
If that is not an option:
double check the pinout the Serial Ports article above but also the logic level voltage (e.g. might be 3.3V, not 5V)
get a USB Serial converter (for the right logic level) - this will show up as a different Serial port using Processing's Serial.list()
connect Serial2's TX pin to the convertor's RX pin and read the data in Processing (similar to process to how you'd read Serial, just a different port name)

Arduino Values arriving differently in Processing and Arduino Serial Monitor

I have an Arduino Mega2560 which reads analog values from a sensor (Grove Loudness Sensor) and sends them to a Raspberry Pie 3b+ via USB. The values arrive perfectly and without delay in the serial monitor of the Arduino IDE. But when I try to receive them in Processing I get mostly Zeros no matter how much noise I make, with random peaks here and there.
My first guess was that my Processing code garbles the received data, so I changed the Arduino sketch to send an incrementing Integer instead of the sensor value - and those test values show correctly in Processing! Next I tried padding the sensor value in some String like "MICRO("+theSensorValue+");". The serial monitor shows the whole String and the correct sensor value, Processing shows the whole String but the value inside is still garbage..
This doesn't make any sense to me. Processing can receive any value from the Arduino correctly, except when it's the sensor value...
Arduino:
void setup() {
Serial.begin(9600);
}
void loop() {
int micLevel = analogRead(A0);
Serial.println(micLevel,DEC);
}
Processing:
Serial port;
void setup() {
port = new Serial(this, "/dev/ttyACM0", 9600);
}
void draw() {
String s = "";
if(port.available() > 0) {
s = port.readStringUntil(10);
println(s);
}
}
In Serial.println(micLevel,DEC); why are you casting the value as decimal?
Try to just Serial.println(micLevel); or convert to String if you want to send text with it Serial.println("Value is: " + String(micLevel));

Garbage text in serial monitor from Arduino

I have a problem with my brand new Arduino, it seems that
no matter what I print with
Serial.println()
be it numbers, strings or anything else, I get garbage
on the Arduino serial monitor:
Not even the simplest hello world program works.
Could you help me identify the problem and solve it?
I found the solution :)
I wrote a test program and found a working baud-rate at 600.
My test program:
long baudrates[] = {600,1200,2400,4800,9600,14400,19200,28800,38400,56000,57600,115200,128000,256000};
unsigned char baudcounter = 0;
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication
Serial.begin(baudrates[baudcounter]);
}
// the loop routine runs over and over again forever:
void loop() {
Serial.println();
Serial.println(baudrates[baudcounter]);
Serial.println(" !\"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
Serial.println();
baudcounter++;
baudcounter %= sizeof(baudrates)/sizeof(long);
delay(1000); // delay
Serial.begin(baudrates[baudcounter]); // switch baudrate
}

PC to Arduino RS-485 connection via converters

I'm trying to make modbus RS-485 connection between PC (Windows) and Arduino.
On the PC side I use USB-to-RS485 converter like this one http://ru.aliexpress.com/item/USB-to-485-RS485-converter-Adapter-Support-Windows-7-8-for-Arduino/1577970568.html
On the Arduino side I use TTL-to-RS-485 like this one http://ru.aliexpress.com/item/5pcs-lot-MAX485-Module-RS-485-TTL-to-RS485-Module-for-Arduino/32262338107.html
Problem1:
When I send byte from PC to Arduino. Nothing happens. Arduino does not receive anything. In this case i upload to Arduino this code:
#include <SoftwareSerial.h>
#include "RS485_protocol.h"
SoftwareSerial rs485 (10, 11); // receive pin, transmit pin
const byte ENABLE_PIN = 3;
void setup()
{
Serial.begin(9600);
rs485.begin (28800);
pinMode (ENABLE_PIN, OUTPUT); // driver output enable
}
void loop()
{
byte buf [1];
byte received = recvMsg (fAvailable, fRead, buf, sizeof (buf));
if (received)
{
Serial.println(buf[0]);
} else {
Serial.println("--");
}
} // end of loop
int fAvailable ()
{
return rs485.available ();
}
int fRead ()
{
return rs485.read ();
}
And open Serial Monitor in Arduino IDE to show received data.
Then I open new instance of Arduino IDE, chose proper USB-to-RS485 COM port and opens it Serial Monitor to send some data.
So in Arduino side Serial Monitor I see only "--" lines. Even when I'm trying to send something in PC side Serial Monitor.
The other problem is:
Vice versa. When i sending some byte from Arduino to PC I receive some odd symbols instead sent byte.
The Arduino code in this case is:
#include <SoftwareSerial.h>
#include "RS485_protocol.h"
SoftwareSerial rs485 (10, 11); // receive pin, transmit pin
const byte ENABLE_PIN = 3;
void setup()
{
rs485.begin (28800);
pinMode (ENABLE_PIN, OUTPUT); // driver output enable
}
void loop()
{
byte msg[1] = {3};
sendMsg(msg);
} // end of loop
void sendMsg(byte msg[])
{
delay (1); // give the master a moment to prepare to receive
digitalWrite (ENABLE_PIN, HIGH); // enable sending
sendMsg (fWrite, msg, 1);
digitalWrite (ENABLE_PIN, LOW); // disable sending
}
void fWrite (const byte what)
{
rs485.write (what);
}
int fAvailable ()
{
return rs485.available ();
}
On the PC side (in the Arduino IDEs Serial Monitor) I receive odd symbols instead "3" symbol.
=======
RS485 converters wired with twisted pare A to A and B to B.
RS485 to TTL converter connected to Arduino properly. (Communication between two arduinos works fine).
Please help.
Example of RS485 :
Using a SN75176 IC.
RE (pin 2) connect to ground (for always reading )
Arduino control only DE PIN for writing data
But PC side problems:
Where bridged DE pins ? (CTS,DTR,RTD if supported)
What is your flow control ? (related #1)
Did you connect any resistor to A, B pin ?<+5V>----[560R]-----(A)----[120R]-----(B)------[560R]------<-5V> So mean line end
Did you filter DE Pin 2 signal (for noise)
A tricks : Use SN75176 on arduino side because this IC a RS232(UART) to (RS485) converter.
Edit : Modbus got 2 type on serial (RTU, ASCII). Dont care RS232/485 differences because different signal, same protocol.
Example packet type:
ASCII : :010300200004+CRC+FE(crc =packet check code, fe=end delimeter)
RTU : \x01\x03\x00\x20\x00\x04\x +CRC
On rtu : every byte need 1.5 char space and without start and end delimeter.
And Modbus node type meaning master and slave.
I hope helpfull.

Resources