I fly RC and wanted to break in a new gas engine. Being gas it takes about 2 gallons of fuel to do a good break in. Wanting to automate this to running on a test bench so I talked with the electronics group on RCGroups.com and went with the Arduino board.
The program is a pseudo menu interface and functions can be stacked for a varied run sequence. Right now the function choices are; fullt(hrottle), idle, midt, center, menu, manual, stop; some take options. Manual drives the servo with the up down arrow keys. I'm using Putty for terminal interface ( my laptop is running Vista).
TODO:
- Code isn't LMC, I think it's clumsy in many places and I've had an occasional glitch with passing options
- Interface is crude, I'm thinking of adapting ansiterm or sdfruit.
3.Needs an interrupt routine to kill a run from the keyboard. I having trouble with this. Plan on also having an interrupt button at the Arduino; no racing for the PC in a panic.
4.Need to have a better understanding of the UART interface. I can't make the menu too verbose without the program locking.
5.If I get this far I may start interfacing some data recording; an RPM interface would be great.
/**************************************************************************************/
#define PROGRAM "EngineRunIn"
#define VERSION "0.9"
/*
* PROGRAM: EngineRunIn (YASP Yet Another Servo Program)
* VERSION: 0.9 8/14/2010
* DESCRIPTION: Automate engine run-in program using command line arguements to vary throttle position
* and duration.
**************************************************************************************/
/* Throttle control */
#include <Servo.h>
#include <stdio.h> /* we need fundamental FILE definitions and printf declarations */
#define SERVOPIN 2 /* pin used for servo */
#define PORTSPEED 38400 /* Baud rate */
/* tune these 2 to fit your installation */
#define LOWT 45 /* Low throttle. */
#define HIGHT 155 /* High throttle. */
#define NL "\r\n"
#define PROMPT ">:"
#define IFS ' ' /* Internal field separator */
#define CS ';' /* command separator */
#define BEL '\7' /* Bell */
#define DEBUG 0 /* 1 on, 0 off */
#define DELAY 1000
#define OPT_DELIM '-'
/* Set up the serial port and servos. */
Servo Tservo; /* create servo object */
/* All the routines look at Lthrottle & Hthrottle
** Setup() routine can change Lthrottle & Hthrottle,
** used to determine travel setting for your installation.
** LOWT & HIGHT are then permanently changed
*/
int Lthrottle = LOWT;
int Hthrottle = HIGHT;
int CPOS = Lthrottle; /* current servo position; tracked in every subroutine */
#define SERVOCENTER Hthrottle/2 /* Center servo */
/* cliBuildCommand */
#define MAX_COMMAND_LEN (32) /* max # of chars */
#define MAX_PARAMETER_LEN (32)
#define COMMAND_TABLE_SIZE (32) /* for command_t */
#define TO_UPPER(x) (((x >= 'a') && (x <= 'z')) ? ((x) - ('a' - 'A')) : (x))
char gCommandBuffer[MAX_COMMAND_LEN + 1];
char gParamBuffer[MAX_PARAMETER_LEN + 1];
char strBuf[COMMAND_TABLE_SIZE + 1];
char functionBuf[COMMAND_TABLE_SIZE + 1];
char optionBuf[COMMAND_TABLE_SIZE + 1];
int gParamValue = false;
char *cmdptr = gCommandBuffer;
char *optptr = gParamBuffer;
char *str = strBuf;
char *str1 = functionBuf;
char *str2 = optionBuf;
/* PRINTF CODE */
static FILE uartout = {0} ; /* create a FILE structure to reference our UART output function */
/* create a output function; this works because Serial.write,
** although of type virtual, already exists.
*/
static int uart_putchar (char c, FILE *stream)
{Serial.write(c) ;return 0 ;}
/* sample code practice:
** printf("Alive %d sec\n\r", seconds ) ;
** printf("%d hello m%cworld\n", seconds,c);
*/
typedef struct {
char const *name;
void (*function)(void);
}
command_t;
command_t const gCommandTable[COMMAND_TABLE_SIZE] = {
{"MENU", menu, },
{"BLIP", blip, },
{"B", blip, }, /* shortcut */
{"CENTER", centerservo, },
{"CNTR", centerservo, },
{"CYCLE", cycleservo, }, /* For testing, NOT on menu, may not work */
{"MIDT", midt, },
{"FULLT", fullt, },
{"IDLE", idle, },
{"EXIT", stopProgram, },
{"E", stopProgram, },/* shortcut */
{"STOP", stopProgram, },
{"S", stopProgram, },/* shortcut */
{"QUIT", stopProgram, },
{"Q", stopProgram, },/* shortcut */
{"KILL", stopProgram, },
{"K", stopProgram, },/* shortcut */
{"HELP", menu, },
{"SETUP", setupTravel, },/* write this */
{"MANUAL", manualT, },
{"M", manualT, },/* shortcut */
{NULL, NULL }
};
void setup() {
Tservo.attach(SERVOPIN);
Serial.begin(PORTSPEED); /* opens serial port, sets data rate */
/* PRINTF STARTUP: fill in the UART file descriptor with pointer to writer. */
fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
stdout = &uartout ; /* The uart is the standard output device STDOUT. */
printf("%s%s Version: %s%s", NL, PROGRAM, VERSION, NL);
prompt();
}
void loop() {
char rcvChar;
int bCommandReady = false;
if (Serial.available() > 0) {
rcvChar = Serial.read(); /* Wait for a character. */
Serial.print(rcvChar); /* Echo the character back to the serial port. */
bCommandReady = BldCmds(rcvChar); /* Build a new command. */
}
/* Call the CLI command processing routine to verify the command entered */
/* and call the command function; then output a new prompt. */
if (bCommandReady == true) {
bCommandReady = false;
ProcessCmd();
prompt();
}
cmdptr = &gCommandBuffer[0];
optptr = &gParamBuffer[0];
}/* END loop() */
int BldCmds(char nextChar) {
static uint8_t idx = 0; //index for command buffer
static uint8_t idx2 = 0; //index for parameter buffer
enum { COMMAND, PARAM };
static uint8_t state = COMMAND;
if ( (nextChar == ' ') || (nextChar == '\t')) /* skip space & tab */
return false;
if( (nextChar == 'k') && (idx == 0) )
printf("GOT A K\n");
if ((nextChar == '\n') || (nextChar == '\r')) /* end of command line */
{
gCommandBuffer[idx] = '\0';
gParamBuffer[idx2] = '\0';
idx = 0;
idx2 = 0;
state = COMMAND;
return true;
}
gCommandBuffer[idx] = TO_UPPER(nextChar);
idx++;
return false;
} /* END BldCmds */
void ProcessCmd(void)
{
int bCommandFound = false;
int idx;
/* Command & options */
while ((str = strtok_r(cmdptr, ";", &cmdptr)) != NULL) { /* semicolon delimiter */
/* Function w/o commands */
str1 = strtok_r(str, "-", &str);
/* Options to function */
optptr = strtok_r(str, ";", &str);
for (idx = 0; gCommandTable[idx].name != NULL; idx++) {
if (strcmp(gCommandTable[idx].name, str1) == 0) {/* Found CMD */
strcpy(str1,gCommandBuffer);
bCommandFound = true;
break;
}
}
/* Check for options */
if ( optptr != '\0' ) {
gParamValue = true;
}
if (bCommandFound == true) { /* Execute command */
(*gCommandTable[idx].function)();
bCommandFound = false;
}else {
printf("\t\t[%s] Not Found",str1);
bCommandFound = false;
}
gParamValue = false;
delay(250);
printf("%s", NL);
} /* End while */
}/* END ProcessCmd */
void prompt() {printf("%s", PROMPT);}
/* blip throttle N times then return to start position */
void blip() {
int c = 1, pos, cycles = 0, sleep= 700, blipthrottle = 0;
char *opt;
printf("%sblip:", NL);
if ( (CPOS < Lthrottle) || (CPOS > Hthrottle) ) {
printf(" CPOS out of range%s", NL);
return;
}
blipthrottle = CPOS * 1.4;
if(blipthrottle > Hthrottle)
blipthrottle = Hthrottle;
if (gParamValue == true) {
opt = strtok_r(optptr, "-", &optptr); /* take only the first option */
/* Convert the parameter to an integer value. */
/* If the parameter is empty, cycles becomes 1 */
cycles = strtol(opt, NULL, 0);
} else {
cycles = 1;
}
pos = CPOS; /* save */
if(cycles > 1){
printf("BLIP RUN: [%d]",blipthrottle);
}
do { /* at least once */
if(cycles > 1){
printf("%d ", c);
}
//Tservo.write(Hthrottle);
Tservo.write(blipthrottle);
delay(sleep);
Tservo.write(pos);
delay(sleep);
c++;
} while(c <= cycles);
gParamValue = false;
delay(DELAY); /* settle time */
CPOS = pos; /* restore */
}/* END blip() */
void help() { }
void menu() {
printf("\tUsage: [Action](-Option); %s%s", NL, NL);
printf("\tSeparate multiple action with ';' character%s%s", NL, NL);
printf("\t[Action](-Option);Action;Action(-option);Action;%s%s", NL, NL);
printf("\texit Stop program, throttle to idle, ignition shutdown %s", NL);
printf(" stop kill e s k also work%s%s", NL, NL);
printf("\tcenter%s", NL);
printf("\thight%s", NL);
printf("\tidle%s", NL);
printf("\tfullt%s", NL);
printf("\tblip%s", NL);
printf("\tcycle%s", NL);
printf("\tmidt%s", NL);
printf("\tmanual%s", NL);
printf("\tmenu%s", NL);
}/* END menu() */
void idle() {/* Move to idle */
int i;
printf("%sidle:", NL);
Tservo.write(Lthrottle);
delay(DELAY);
CPOS = Lthrottle;
}/* END idle() */
void stopProgram(){/* Shutdown program */
printf("%s\t%s shutdown%s", NL, PROGRAM, NL);
delay(100); /* settle time */