How can I get and process a text command while saving the servos orientation?
If I don't put a delay(1000) in the main loop, the printSerialString() function won't do some math I need correctly. Instead of 1+700, it returns something like 695. Odd. At startup, I also get something like -4895. These functions work fine in code without the servo code.
Some background, I want to control my servos through text commands sent through a com port. I need to wait for a line and then parse it. The first letter indicates (P)an or (T)ilt. The next 3 characters are a 3-digit degrees number I want to orient the pan and tilt servos from. For example P090, (Pan 90 degrees), or T045 (Tilt 45 degrees)
With the delay I assume that I won't be able to keep the servos refreshed with their current positions. I need this because I want to send the absolute position and have them go there.
So, how can I get the Arduino (Duemileuouv) to keep the servos refreshed while waiting for a text string from which to process a new command and orient the servos?
At this point I'm completely lost (and this Arduino stuff is new to me as of a few days ago)
Any other improvements to code greatly appreciated! Hopefully the end result would be useful to others too.
Thanks! Code below hopefullly.
// SERIAL PORT VARS
int serIn; // var that will hold the bytes-in read from the serialBuffer
char serInString[100]; // array that will hold the different bytes 100=100characters;
// -> you must state how long the array will be else it won't work.
int serInIndx = 0; // index of serInString[] in which to insert the next incoming byte
int serOutIndx = 0; // index of the outgoing serInString[] array;
// SERVO VARS
char panval[2];
char tiltval[2];
int icount = 0;
long pval = 0;
long tval = 0;
int servoPanPin = 9; // Control pin for servo motor
int servoTiltPin = 10; // Control pin for servo motor
int pulsePanWidth = 0; // Amount to pulse the servo
int pulseTiltWidth = 0; // Amount to pulse the servo
long lastPanPulse = 0; // the time in millisecs of the last pulse
long lastTiltPulse = 0; // the time in millisecs of the last pulse
int refreshTime = 20; // the time in millisecs needed in between pulses
int minPulse = 700; // minimum pulse width
void setup() {
pinMode(servoPanPin, OUTPUT); // Set servo pin as an output pin
pinMode(servoTiltPin, OUTPUT); // Set servo pin as an output pin
// pulsePanWidth = minPulse; // Set the motor position to the minimum
// pulseTiltWidth = minPulse; // Set the motor position to the minimum
Serial.begin(9600); // connect to the serial port
Serial.println("servos_ready");
}
void loop() {
//read the serial port and create a string out of what you read
//readSerialString(serInString, serInIndx);
readSerialString();
//try to print out collected information. it will do it only if there actually is some info.
printSerialString();
// updatePanServo(); // update pan servo position
// updateTiltServo(); // update tilt servo position
//delay(1000);
}
// called every loop().
// uses global variables servoPi, pulsewidth, lastPulse, & refreshTime
void updatePanServo() {
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastPanPulse >= refreshTime) {
digitalWrite(servoPanPin, HIGH); // Turn the motor on
delayMicroseconds(pulsePanWidth); // Length of the pulse sets the motor position
digitalWrite(servoPanPin, LOW); // Turn the motor off
lastPanPulse = millis(); // save the time of the last pulse
}
}
// called every loop().
// uses global variables servoPi, pulsewidth, lastPulse, & refreshTime
void updateTiltServo() {
// pulse the servo again if rhe refresh time (20 ms) have passed:
if (millis() - lastTiltPulse >= refreshTime) {
digitalWrite(servoPanPin, HIGH); // Turn the motor on
delayMicroseconds(pulseTiltWidth); // Length of the pulse sets the motor position
digitalWrite(servoTiltPin, LOW); // Turn the motor off
lastTiltPulse = millis(); // save the time of the last pulse
}
}
//read a string from the serial and store it in an array
//this func uses globally set variable so it's not so reusable
//I need to find the right syntax to be able to pass to the function 2 parameters:
// the stringArray and (eventually) the index count
void readSerialString () {
int sb;
if(Serial.available()) {
//Serial.print("reading Serial String: "); //optional confirmation
while (Serial.available()){
sb = Serial.read();
serInString[serInIndx] = sb;
serInIndx++;
//serialWrite(sb); //optional confirmation
}
//Serial.println();
}
}
//print the string all in one time
//this func as well uses global variables
void printSerialString() {
if( serInIndx > 0) {
Serial.print("Command: ");
//loop through all bytes in the array and print them out
for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++) {
Serial.print( serInString[serOutIndx] ); //print out the byte at the specified index
//serInString[serOutIndx] = ""; //optional: flush out the content
}
Serial.println();
if(serInString[0] == 'P')
{
Serial.print("Pan!");
for(icount=0; icount<3; icount++)
{
panval[icount] = serInString[icount+1];
}
pval = stringToNumber(panval, 3);
pval = pval + 700;
pulsePanWidth = pval;
Serial.println();
Serial.print("Value to pan servo: ");
Serial.print(pval, DEC);
pval = 0;
icount = 0;
//updatePanServo();
}
if(serInString[0] == 'T')
{
Serial.print("Tilt!");
for(icount=0; icount<3; icount++)
{
tiltval[icount] = serInString[icount+1];
}
tval = stringToNumber(tiltval, 3);
tval = tval + 700;
pulseTiltWidth = tval;
Serial.println();
Serial.print("Value to tilt servo: ");
Serial.print(tval, DEC);
tval = 0;
icount = 0;
//updateTiltServo();
}
//reset all the functions to be able to fill the string back with content
serOutIndx = 0;
serInIndx = 0;
Serial.println();
}
}
/*
THANKS tigoe.net for string to number functions!
This method converts a string if ASCII numbers to a decimal number.
There's no error checking in it, so it can return mistakes
if you give it non-numeric ASCII.
When I wrote this program, the standard C lib was not part of
Arduino, so I couldn't use atoi().
*/
long stringToNumber(char thisString[], int length)
{
int thisChar = 0;
long value = 0;
for (thisChar = length-1; thisChar >=0; thisChar--)
{
char thisByte = thisString[thisChar] - 48;
value = value + powerOfTen(thisByte, (length-1)-thisChar);
}
return value;
}
/*
This method takes a number between 0 and 9,
and multiplies it by ten raised to a second number.
*/
long powerOfTen(char digit, int power) {
long val = 1;
if (power == 0) {
return digit;
}
else {
for (int i = power; i >=1 ; i--) {
val = 10 * val;
}
return digit * val;
}
}