Montag, 4. November 2013
Firmware V1.0 b9
schultzc, 23:25h
/*
* ****************************************************************************
* Crawlee Firmware on RP6 ROBOT SYSTEM
* ****************************************************************************
* Author(s): Christoph Schultz
* Version 1.0 - 2013-09-12
* Copyright 2013
* ****************************************************************************
* Description:
* TThe firmware shall allow to access all sensors and actuators via UART
* ****************************************************************************
*/
/*****************************************************************************/
// Includes:
#include "RP6RobotBaseLib.h" // The RP6 Robot Base Library.
// Always needs to be included!
// The behaviour command data type:
typedef struct {
uint8_t speed_left; // left speed (is used for rotation and
// move distance commands - if these commands are
// active, speed_right is ignored!)
uint8_t speed_right; // right speed
unsigned dir:2; // direction (FWD, BWD, LEFT, RIGHT)
unsigned move:1; // move flag
unsigned rotate:1; // rotate flag
uint16_t move_value; // move value is used for distance and angle values
uint8_t state; // state of the behaviour
} behaviour_command_t;
#define IDLE 0
behaviour_command_t mv_cmd = {0, 0, FWD, false, false, 0, IDLE};
#define P_BUFFLEN 16
char buffer[P_BUFFLEN];
uint8_t ind;
uint8_t acs_level;
int8_t speed;
int8_t offset;
uint8_t direction;
uint16_t movetimer;
void reportACSState(void)
{
char bl,br;
writeString_P(">S");
switch(acs_level)
{
case 0:
writeChar('0');
break;
case 1:
writeChar('1');
break;
case 2:
writeChar('2');
break;
case 3:
writeChar('3');
break;
}
writeChar('\n');
if(obstacle_left)
bl = '1';
else
bl = '0';
if(obstacle_right)
br = '1';
else
br = '0';
writeString_P(">L");
writeChar(bl);
writeChar('\n');
writeString_P(">R");
writeChar(br);
writeChar('\n');
}
void reportBatteryState(void)
{
writeString_P(">");
writeInteger(adcBat,DEC);
writeChar('\n');
}
void reportEngineState(void)
{
writeString_P(">L");
writeInteger(adcMotorCurrentLeft,DEC);
writeChar('\n');
writeString_P(">R");
writeInteger(adcMotorCurrentRight,DEC);
writeChar('\n');
}
void reportLightState(void)
{
uint8_t ind;
char temp[16];
for(int i = 0; i < 16; i ++)
{
temp[i] = '\0';
}
snprintf(temp,16,"%d",adcLSL);
writeString_P(">L");
ind = 0;
while(ind < 16 && temp[ind] != '\0')
{
writeChar(temp[ind]);
ind ++;
}
writeChar('\n');
for(int i = 0; i < 16; i ++)
{
temp[i] = '\0';
}
snprintf(temp,16,"%d",adcLSR);
writeString_P(">R");
ind = 0;
while(ind < 16 && temp[ind] != '\0')
{
writeChar(temp[ind]);
ind ++;
}
writeChar('\n');
}
void reportBumperState(void)
{
char bl,br;
if(bumper_left)
bl = '1';
else
bl = '0';
if(bumper_right)
br = '1';
else
br = '0';
writeString_P(">L");
writeChar(bl);
writeChar('\n');
writeString_P(">R");
writeChar(br);
writeChar('\n');
}
/*****************************************************************************/
// Parser
void parseSpeedCommand(const char* cmd)
{
int8_t spTmp;
spTmp = atoi(cmd);
if(spTmp < 0)
{
spTmp = -spTmp;
direction = BWD;
}
else
{
direction = FWD;
}
speed = spTmp;
if(offset > speed)
offset = speed;
if(offset < -speed)
offset = -speed;
offset = spTmp;
writeString_P(">");
writeInteger(spTmp, DEC);
writeChar('\n');
}
void parseOffsetCommand(const char* cmd)
{
int8_t spTmp;
spTmp = atoi(cmd);
if(spTmp > speed)
spTmp = speed;
if(spTmp < -((int8_t)speed))
spTmp = -((int8_t)speed);
offset = spTmp;
writeString_P(">");
writeInteger(spTmp, DEC);
writeChar('\n');
}
void parseACSCommand(const char* cmd)
{
switch(cmd[0])
{
case '+':
if(acs_level < 3)
acs_level ++;
break;
case '-':
if(acs_level > 0)
acs_level --;
break;
case '0':
acs_level = 0;
break;
case '1':
acs_level = 1;
break;
case '2':
acs_level = 2;
break;
case '3':
acs_level = 3;
break;
default:
reportACSState();
break;
}
}
void parseMoveTimedCommand(const char* buffer)
{
movetimer = 10;
if(buffer[0] != '\0')
{
movetimer = atoi(&buffer[0]);
}
writeString_P(">");
writeInteger(movetimer,DEC);
mv_cmd.dir = direction;
mv_cmd.speed_left = speed+offset;
mv_cmd.speed_right = speed-offset;
mv_cmd.move = 0;
mv_cmd.rotate = 0;
mv_cmd.move_value = 0;
setStopwatch6(0);
}
void parseCommands(void)
{
uint16_t dist;
//Loop input
for(int i = 0; i < ind; i ++)
{
writeChar(buffer[i]);
}
switch(buffer[0])
{
case 'c':
case 'C':
writeString_P(" - move timed\n");
parseMoveTimedCommand((const char*)&buffer[1]);
break;
case 'o':
case 'O':
writeString_P(" - set offset\n");
parseOffsetCommand((const char*)&buffer[1]);
break;
case 'q':
case 'Q':
writeString_P(" - set speed\n");
parseSpeedCommand((const char*)&buffer[1]);
break;
case 'd':
case 'D':
dist = 15;
writeString_P(" - rotate right\n");
if(buffer[1] != '\0')
{
dist = atoi(&buffer[1]);
}
mv_cmd.dir = RIGHT;
mv_cmd.speed_left = speed;
mv_cmd.speed_right = speed;
mv_cmd.move = 0;
mv_cmd.rotate = 1;
mv_cmd.move_value = dist;
break;
case 'a':
case 'A':
dist = 15;
writeString_P(" - rotate left\n");
if(buffer[1] != '\0')
{
dist = atoi(&buffer[1]);
}
mv_cmd.dir = LEFT;
mv_cmd.speed_left = speed;
mv_cmd.speed_right = speed;
mv_cmd.move = 0;
mv_cmd.rotate = 1;
mv_cmd.move_value = dist;
break;
case 's':
case 'S':
dist = 150;
writeString_P(" - move backward\n");
if(buffer[1] != '\0')
{
dist = atoi(&buffer[1]);
}
mv_cmd.dir = BWD;
mv_cmd.speed_left = speed;
mv_cmd.speed_right = speed;
mv_cmd.move = 1;
mv_cmd.rotate = 0;
mv_cmd.move_value = dist;
break;
case 'w':
case 'W':
dist = 150;
writeString_P(" - move forward\n");
if(buffer[1] != '\0')
{
dist = atoi(&buffer[1]);
}
mv_cmd.dir = FWD;
mv_cmd.speed_left = speed;
mv_cmd.speed_right = speed;
mv_cmd.move = 1;
mv_cmd.rotate = 0;
mv_cmd.move_value = dist;
break;
case 'i':
case 'I':
writeString_P(" - obstacle sensor status/ctrl\n");
parseACSCommand((const char*)&buffer[1]);
break;
case 'l':
case 'L':
writeString_P(" - Report light sensor status\n");
//No parameters - nothing to parse
reportLightState();
break;
case 'V':
case 'v':
writeString_P(" - Report VDD status");
writeChar('\n');
//No parameters - nothing to parse
reportBatteryState();
break;
case 'e':
case 'E':
writeString_P(" - Engine status");
writeChar('\n');
//No parameters - nothing to parse
reportEngineState();
break;
case 'b':
case 'B':
writeString_P(" - Report bumper status");
writeChar('\n');
//No parameters - nothing to parse
reportBumperState();
break;
default:
writeChar('\n');
writeString_P("!E0 - Unknown command!\n");
break;
}
}
void clearBuffer(void)
{
ind = 0;
for(int i = 1; i < P_BUFFLEN; i ++)
{
buffer[i] = '\0';
}
}
void checkCommands(void)
{
while(getBufferLength()) // Check if we have data
{
//Read character
buffer[ind] = readChar(); // get next character from reception buffer
//Check if newline has been detected
if(buffer[ind] == '\n')
{
buffer[ind] = '\0';
parseCommands();
clearBuffer();
}
else if(buffer[ind] == '\r') //Remove \r; otherwise increase index
{
buffer[ind] = '\0';
}
else if(ind < P_BUFFLEN - 1) //If buffer has still capacity increase index, last char has to remain '\0'
{
ind ++;
}
else
{
writeString_P("!E1 - Buffer length exceeded!\n");
//Clear all buffers
clearBuffer();
clearReceptionBuffer();
}
}
}
void updateACS(void)
{
static uint8_t old_acs = 255;
if(acs_level == old_acs)
return;
else
old_acs = acs_level;
if(acs_level == 1)
{
setACSPwrLow();
}
else if(acs_level == 2)
{
setACSPwrMed();
}
else if(acs_level == 3)
{
setACSPwrHigh();
}
else
{
setACSPwrOff();
}
}
void acsStateChanged(void)
{
if(obstacle_left && obstacle_right)
statusLEDs.byte = 0b100100;
else
statusLEDs.byte = 0b000000;
statusLEDs.LED5 = obstacle_left;
statusLEDs.LED4 = (!obstacle_left);
statusLEDs.LED2 = obstacle_right;
statusLEDs.LED1 = (!obstacle_right);
updateStatusLEDs();
}
/**
* This function processes the movement commands that the behaviours generate.
* Depending on the values in the behaviour_command_t struct, it sets motor
* speed, moves a given distance or rotates.
*/
void moveCommand(behaviour_command_t * cmd)
{
if(cmd->move_value > 0)
{
if(cmd->rotate)
rotate(cmd->speed_left, cmd->dir, cmd->move_value, false);
else if(cmd->move)
move(cmd->speed_left, cmd->dir, DIST_MM(cmd->move_value), false);
cmd->move_value = 0;
}
else if(!(cmd->move || cmd->rotate))
{
changeDirection(cmd->dir);
if(getStopwatch6()<=movetimer)
{
moveAtSpeed(cmd->speed_left,cmd->speed_right);
startStopwatch6();
}
else
{
moveAtSpeed(0,0);
stopStopwatch6();
}
}
else if(isMovementComplete())
{
cmd->rotate = false;
cmd->move = false;
cmd->speed_left = 0;
cmd->speed_right = 0;
}
}
/*****************************************************************************/
// Main function - The program starts here:
int main(void)
{
initRobotBase(); // Always call this first! The Processor will not work
// correctly otherwise.
setLEDs(0b111111); // Turn all LEDs on
mSleep(500); // delay 500ms
setLEDs(0b000000); // All LEDs off
// Write a message to UART:
writeString_P("\nHello! My name is Crawlee #0 (b9) 2013-11-04!\n\n");
clearBuffer();
clearReceptionBuffer();
acs_level = 2;
ACS_setStateChangedHandler(acsStateChanged);
speed = 80;
offset = 0;
direction = FWD;
powerON(); // Turn on Encoders, Current sensing, ACS and Power LED.
enableACS();
setACSPwrMed();
setLEDs(0b001001);
// ---------------------------------------
// Main loop:
while(true)
{
//Check commands
checkCommands();
//Update ACS
updateACS();
//Execute move command
moveCommand(&mv_cmd);
//Perform system tasks and update data-fields
task_RP6System();
//Sleep to save power
//-ATTENTION:ACS Function does not work well with this mSleep command!
//-It has been therefore deactivated in b8 - CS
//mSleep(5);
}
// End of main loop
// ---------------------------------------
return 0;
}
/*****************************************************************************/
// EOF
... comment