Here we go again (lost session and computer deleted the message when I sent it...).
I've been running into problems trying to run some tests on my start sequencer for a gas turbine engine.
Here's what I've been trying to do very simply : I type a value (byte) on the serial console, the Arduino reads it and sends the value (through PPM servo) to my starter motor ESC which makes the motor turns to the corresponding RPM.
The code goes like this :
#include<servo.h>
Servo starter1
const int starter = 42; // the pin that the LED is attached to
void setup()
{
Serial.begin(9600);
starter1.attach(starter);
}
void loop() {
byte test;
// check if data has been sent from the computer:
if (Serial.available()) {
test = Serial.read();
starter1.write(test);
}
}
Problem is, this sketch won't make the motor turn. It sometimes jerk when I type in a value but it won't turn at all…
Now I've tried to debug it with an LCD display and had an instruction in the loop to watch the test byte but it will return only 10. As soon as I type the first value, the LCD only displays 10 (and the sentence I wrote before so no pb in the LCD).
The only way I had it to work was to put a delay(1000) just after the starter1.write(test) instructions and in this case the motor will turn to the desired RPM but only for one second… So something is putting my test value to 0 right after it exits the if loop?
I have the feeling that there's a huge gorilla in the room but can't find it…
Look at the settings for the IDE's terminal program - assuming you're using it. It sounds like you have it set to send a line ending (character 10) after the byte that you're expecting to command the servo and it immediately tells the servo to forget what you told it and go to position 10 instead.
marc426:
I have the feeling that there's a huge gorilla in the room but can't find it…
Two gorillas, methinks.
First one is the speed the Arduino works at - it will not give the servo time to respond to the new number.
Second one is that you are reading an unlimited amount of characters from the Serial port but you are only sending them to the servo one at a time so the last one is the only one that has any effect.
Another potential problem is that you can only send Ascii characters from the Serial Monitor and you are assuming their Ascii value is the angle for the servo. For example the digit 3 is 51 and the letter 'y' is 121.
You might like to look at this demo for a more sophisticated way of receiving data.
As for the CR or NL etc... I tried all the settings and while it changed the number I had on the display (all very randoms and not what I had typed whatsoever), it didn't do anything for the control of the motor.
And as for the speed of the Arduino, what's the matter with that? I'm using the servo library which send the correct PPM according to the value I'm giving it. It works on the rest of my sketch so I tend to think it's not the problem...
Take another look at Robin's post. You're not sending a value of 155 to the servo, you're sending the ascii numbers for those characters i.e. 49 followed by 53 and another 53.
Take a look at atoi. You're going to need to store the characters you send in a zero terminated buffer to get the number you're looking for. Again per Robin though, you should be able to get the servo to move by sending stuff like lower case y.
see if this works.. I don't have a servo to see...
#include<Servo.h>
unsigned int currentValue;
Servo starter1;
const int starter = 42;
void setup()
{
Serial.begin(9600);
starter1.attach(starter);
}
void loop() {
// check if data has been sent from the computer:
while (Serial.available ())
processIncomingByte (Serial.read ());
// do other stuff in loop as required
}
void processIncomingByte (const byte c)
{
if (isdigit (c))
{
currentValue *= 10;
currentValue += c - '0';
}
// end of digit
else
{
Serial.println(currentValue);
starter1.write(currentValue);
currentValue =0;
}
}
marc426:
And as for the speed of the Arduino, what's the matter with that?
Using @wildbill's example, it sends the bytes 49, 53 and 53 to the servo with only a few milliseconds gap between them. The servo can't respond that quickly so it just appears to respond to the last value - which might actually be the CR or NL.
Ok so I mistakingly thought sending an int or byte using the serial monitor was going to be a really simple task...
Robin, I've looked at your example in the link you gave and I kinda succeed in making sense out of it (so I just have to replace to atoi to get an integer out of it, right?).
But kycountry,
I don't understand what is this part and what it is supposed to give :
if (isdigit (c))
{
currentValue *= 10;
currentValue += c - '0';
}
if (isdigit (c))
{
currentValue *= 10;
currentValue += c - '0';
}
If you have received a digit - let's say it's '4'
move the existing number one space to the left to make room for the new digit
e.g, 123 becomes 1230
add the numeric value of the digit i.e. the Ascii value - the Ascii value for 0
so 1230 becomes 1234
OR just use atoi()
Ok so I mistakingly thought sending an int or byte using the serial monitor was going to be a really simple task...
Put the code for receiving the data into a function and then just forget about it. If you want to do the same thing in another project just use the same function. That way you only have to do the work once.
There is no standard function because everyone's need is a little different.
Ok so I mistakingly thought sending an int or byte using the serial monitor was going to be a really simple task...
Robin, I've looked at your example in the link you gave and I kinda succeed in making sense out of it (so I just have to replace to atoi to get an integer out of it, right?).
But kycountry,
I don't understand what is this part and what it is supposed to give :
if (isdigit (c))
{
currentValue *= 10;
currentValue += c - '0';
}
Thanks for the help,
Marc
This works exactly as Robin explained... This code is part of a "state machine" example I found while researching serial parsing with switch statements..
It can be found here - Code included below..
With the state machine.. you can send multiple commands in one transmission... example is S112,R114,G1... the "S" isn't a digit so it calls handlePreviousState (); with no state then switches the "state" to GOT_S.. then "if(isdigit(c))" catches the value of "S" until it finds the "," which breaks the "if" statement and runs the handlePreviousState () again with the "state" of GOT_S and the value of 112 and sets the "state" back to NONE.. This repeats through R and G until the "\n" breaks the "if" statement and there is nothing else to read..
I have found this code extremely helpful with serial communication between computer software and the board when updating more than one variable at a time..
This code is not my work.. Author is included to give credit where credit is due..
// Example state machine reading serial input
// Author: Nick Gammon
// Date: 17 December 2011
// the possible states of the state-machine
typedef enum { NONE, GOT_R, GOT_S, GOT_G } states;
// current state-machine state
states state = NONE;
// current partial number
unsigned int currentValue;
void setup ()
{
Serial.begin (115200);
state = NONE;
} // end of setup
void processRPM (const unsigned int value)
{
// do something with RPM
Serial.print ("RPM = ");
Serial.println (value);
} // end of processRPM
void processSpeed (const unsigned int value)
{
// do something with speed
Serial.print ("Speed = ");
Serial.println (value);
} // end of processSpeed
void processGear (const unsigned int value)
{
// do something with gear
Serial.print ("Gear = ");
Serial.println (value);
} // end of processGear
void handlePreviousState ()
{
switch (state)
{
case GOT_R:
processRPM (currentValue);
break;
case GOT_S:
processSpeed (currentValue);
break;
case GOT_G:
processGear (currentValue);
break;
} // end of switch
currentValue = 0;
} // end of handlePreviousState
void processIncomingByte (const byte c)
{
if (isdigit (c))
{
currentValue *= 10;
currentValue += c - '0';
} // end of digit
else
{
// The end of the number signals a state change
handlePreviousState ();
// set the new state, if we recognize it
switch (c)
{
case 'R':
state = GOT_R;
break;
case 'S':
state = GOT_S;
break;
case 'G':
state = GOT_G;
break;
default:
state = NONE;
break;
} // end of switch on incoming byte
} // end of not digit
} // end of processIncomingByte
void loop ()
{
while (Serial.available ())
processIncomingByte (Serial.read ());
// do other stuff in loop as required
} // end of loop