Hi Leute,
ich versuche, das 10. Beispielprogramm des M32 (Example_10_Move2), das einen verhaltensgesteuerten Roboter realisiert, um ein zusätzliches Verhalten zu erweitern. Das Verhalten hab ich erstmal OBEY genannt, der RP6 soll damit auf RC5-Signale hören (dafür hab ich weitgehend das Beispielprogramm der RP6Base - Example_08_TV_REMOTE - übernommen).
Hintergrund dafür ist einfach nur, dass ich jederzeit die Kontrolle übernehmen können will, und z.B. nach einer Kurskorrektur mit der Promo 8 Fernbedienung wieder in das autonome Verhalten (CRUISE, ESCAPE, AVOID) umschalten will.
Das Umschalten zwischen den Verhaltensweisen funktioniert auch ohne Probleme. Allerdings funktioniert die Steuerung nicht richtig.
Der RP6 stoppt beim Aktivieren der Fernsteuerung nur kurz, gibt dann aber wieder Gas. Er wird auf der rechten Seite immer langsamer, auf der linken Seite bleibt die Geschwindigkeit konstant. Und er verringert die Geschwindigkeit nicht, wenn er 0,25 Sekunden lang kein RC5 Signal mehr bekommen hat.
Nachdem ich mir jetzt die letzten 3 Wochenenden den Kopf darüber zerbrochen hab, wo zum Geier da der Fehler liegen könnte, frag ich lieber mal euch hier, in der Hoffnung, dass ihr mir weiterhelfen könnt ;)
Ich bin für jeden Tip und Hinweis dankbar! Im Anhang ist der aktuelle Stand des Codes.
schönes Restwochenende noch,
V:X
Hi V:X,
ich habe als Ausgangspunkt für weitere Entwicklungen mal einen Ersatz für die RP6Control_10_Move2.c Datei angehängt. Die I2CMasterLib bleibt unverändert:
// Includes:
#include "RP6ControlLib.h" // The RP6 Control Library.
// Always needs to be included!
#include "RP6I2CmasterTWI.h" // I2C Master Library
// Include our new "RP6 Control I2C Master library":
#include "RP6Control_I2CMasterLib.h"
// Behaviour command type:
#define IDLE 0
// 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;
behaviour_command_t STOP = {0, 0, FWD, false, false, 0, IDLE};
/************************************************** ***************************/
// Cruise Behaviour:
#define CRUISE_SPEED_FWD 80 // Default speed
#define MOVE_FORWARDS 1
behaviour_command_t cruise = {CRUISE_SPEED_FWD, CRUISE_SPEED_FWD, FWD,
false, false, 0, MOVE_FORWARDS};
/**
* Cruise Behaviour
*/
void behaviour_cruise(void)
{
}
/************************************************** ***************************/
// Escape Behaviour:
#define ESCAPE_SPEED_BWD 80
#define ESCAPE_SPEED_ROTATE 60
#define ESCAPE_FRONT 1
#define ESCAPE_FRONT_WAIT 2
#define ESCAPE_LEFT 3
#define ESCAPE_LEFT_WAIT 4
#define ESCAPE_RIGHT 5
#define ESCAPE_RIGHT_WAIT 6
#define ESCAPE_WAIT_END 7
behaviour_command_t escape = {0, 0, FWD, false, false, 0, IDLE};
/**
* This is the Escape behaviour for the Bumpers.
*/
void behaviour_escape(void)
{
static uint8_t bump_count = 0;
switch(escape.state)
{
case IDLE:
break;
case ESCAPE_FRONT:
escape.speed_left = ESCAPE_SPEED_BWD;
escape.dir = BWD;
escape.move = true;
if(bump_count > 3)
escape.move_value = 200;
else
escape.move_value = 140;
escape.state = ESCAPE_FRONT_WAIT;
bump_count+=2;
break;
case ESCAPE_FRONT_WAIT:
if(!escape.move)
{
escape.speed_left = ESCAPE_SPEED_ROTATE;
if(bump_count > 3)
{
escape.move_value = 110;
escape.dir = RIGHT;
bump_count = 0;
}
else
{
escape.dir = LEFT;
escape.move_value = 75;
}
escape.rotate = true;
escape.state = ESCAPE_WAIT_END;
}
break;
case ESCAPE_LEFT:
escape.speed_left = ESCAPE_SPEED_BWD;
escape.dir = BWD;
escape.move = true;
if(bump_count > 3)
escape.move_value = 160;
else
escape.move_value = 100;
escape.state = ESCAPE_LEFT_WAIT;
bump_count++;
break;
case ESCAPE_LEFT_WAIT:
if(!escape.move)
{
escape.speed_left = ESCAPE_SPEED_ROTATE;
escape.dir = RIGHT;
escape.rotate = true;
if(bump_count > 3)
{
escape.move_value = 100;
bump_count = 0;
}
else
escape.move_value = 65;
escape.state = ESCAPE_WAIT_END;
}
break;
case ESCAPE_RIGHT:
escape.speed_left = ESCAPE_SPEED_BWD ;
escape.dir = BWD;
escape.move = true;
if(bump_count > 3)
escape.move_value = 160;
else
escape.move_value = 100;
escape.state = ESCAPE_RIGHT_WAIT;
bump_count++;
break;
case ESCAPE_RIGHT_WAIT:
if(!escape.move)
{
escape.speed_left = ESCAPE_SPEED_ROTATE;
escape.dir = LEFT;
escape.rotate = true;
if(bump_count > 3)
{
escape.move_value = 100;
bump_count = 0;
}
else
escape.move_value = 65;
escape.state = ESCAPE_WAIT_END;
}
break;
case ESCAPE_WAIT_END:
if(!(escape.move || escape.rotate))
escape.state = IDLE;
break;
}
}
/**
* Bumpers Event handler
*/
void bumpersStateChanged(void)
{
if(bumper_left && bumper_right)
{
sound(200,100,0);
escape.state = ESCAPE_FRONT;
}
else if(bumper_left)
{
sound(200,25,10);
sound(150,25,0);
if(escape.state != ESCAPE_FRONT_WAIT)
escape.state = ESCAPE_LEFT;
}
else if(bumper_right)
{
sound(200,25,10);
sound(150,25,0);
if(escape.state != ESCAPE_FRONT_WAIT)
escape.state = ESCAPE_RIGHT;
}
}
/************************************************** ***************************/
// Avoid Behaviour:
#define AVOID_SPEED_L_ARC_LEFT 20
#define AVOID_SPEED_L_ARC_RIGHT 80
#define AVOID_SPEED_R_ARC_LEFT 80
#define AVOID_SPEED_R_ARC_RIGHT 20
#define AVOID_SPEED_ROTATE 60
#define AVOID_OBSTACLE_RIGHT 1
#define AVOID_OBSTACLE_LEFT 2
#define AVOID_OBSTACLE_MIDDLE 3
#define AVOID_OBSTACLE_MIDDLE_WAIT 4
#define AVOID_END 5
behaviour_command_t avoid = {0, 0, FWD, false, false, 0, IDLE};
/**
* Avoid behaviour with ACS IR Sensors.
*/
void behaviour_avoid(void)
{
static uint8_t last_obstacle = LEFT;
static uint8_t obstacle_counter = 0;
switch(avoid.state)
{
case IDLE:
if(obstacle_right && obstacle_left)
avoid.state = AVOID_OBSTACLE_MIDDLE;
else if(obstacle_left)
avoid.state = AVOID_OBSTACLE_LEFT;
else if(obstacle_right)
avoid.state = AVOID_OBSTACLE_RIGHT;
break;
case AVOID_OBSTACLE_MIDDLE:
avoid.dir = last_obstacle;
avoid.speed_left = AVOID_SPEED_ROTATE;
avoid.speed_right = AVOID_SPEED_ROTATE;
if(!(obstacle_left || obstacle_right))
{
if(obstacle_counter > 3)
{
obstacle_counter = 0;
setStopwatch4(0);
}
else
setStopwatch4(400);
startStopwatch4();
avoid.state = AVOID_END;
}
break;
case AVOID_OBSTACLE_RIGHT:
avoid.dir = FWD;
avoid.speed_left = AVOID_SPEED_L_ARC_LEFT;
avoid.speed_right = AVOID_SPEED_L_ARC_RIGHT;
if(obstacle_right && obstacle_left)
avoid.state = AVOID_OBSTACLE_MIDDLE;
if(!obstacle_right)
{
setStopwatch4(500);
startStopwatch4();
avoid.state = AVOID_END;
}
last_obstacle = RIGHT;
obstacle_counter++;
break;
case AVOID_OBSTACLE_LEFT:
avoid.dir = FWD;
avoid.speed_left = AVOID_SPEED_R_ARC_LEFT;
avoid.speed_right = AVOID_SPEED_R_ARC_RIGHT;
if(obstacle_right && obstacle_left)
avoid.state = AVOID_OBSTACLE_MIDDLE;
if(!obstacle_left)
{
setStopwatch4(500);
startStopwatch4();
avoid.state = AVOID_END;
}
last_obstacle = LEFT;
obstacle_counter++;
break;
case AVOID_END:
if(getStopwatch4() > 1000)
{
stopStopwatch4();
setStopwatch4(0);
avoid.state = IDLE;
}
break;
}
}
/**
* ACS Event Handler
*/
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();
if(obstacle_left && obstacle_right)
{
sound(160,20,0);
}
else
{
if(obstacle_left)
sound(120,10,0);
if(obstacle_right)
sound(140,10,0);
}
}
/************************************************** ***************************/
// Behaviour RC5 Reception:
#define RC5RECEPTION_MOVE 1
#define RC5RECEPTION_SHOW 2
behaviour_command_t rc5Reception = {0, 0, FWD, false, false, 0, IDLE};
/**
* Behaviour with RC5 Reception.
*/
void behaviour_rc5Reception(void)
{
}
/**
* RC5 Event Handler
*/
void receiveRC5Data(RC5data_t rc5data)
{
switch(rc5data.key_code)
{
case 1 : rc5Reception.state = RC5RECEPTION_MOVE;
break;
case 2 : rc5Reception.state = RC5RECEPTION_SHOW;
break;
case 3 : rc5Reception.state = IDLE;
break;
}
if(rc5Reception.state == RC5RECEPTION_SHOW)
{
if(getStopwatch2() > 500)
{
clearPosLCD(1, 0, 13);
setCursorPosLCD(1, 0);
// Output the received data:
writeStringLCD_P("RC5 ");
writeCharLCD(rc5data.toggle_bit + '0');
writeStringLCD_P(" |");
writeIntegerLCD(rc5data.device, DEC);
writeStringLCD_P(" |");
writeIntegerLCD(rc5data.key_code, DEC);
setStopwatch2(0);
}
}
}
/************************************************** ***************************/
// Behaviour waitForStart:
#define PREPARE 1
#define WAIT 2
behaviour_command_t waitForStart = {0, 0, FWD,
false, false, 0, PREPARE};
/**
* Wait for start Behaviour.
* You need to clap your hands (or make other noise) three times in order
* to start the Robot!
*/
void behaviour_waitForStart(void)
{
static uint8_t peak_count = 3;
if(waitForStart.state == PREPARE)
{
if(getStopwatch2() > 250)
{
setCursorPosLCD(1, 6);
writeIntegerLengthLCD( peak_count, DEC, 1);
dischargePeakDetector();
waitForStart.state = WAIT;
setStopwatch2(0);
}
}
else if(waitForStart.state == WAIT)
{
uint8_t key = checkReleasedKeyEvent();
if(key)
waitForStart.state = IDLE;
if(getStopwatch2() > 50)
{
uint16_t tmp = getMicrophonePeak();
if(tmp > 4)
{
externalPort.LEDS = 0;
uint16_t i;
uint8_t j;
for(i = 0, j = 2; i < tmp; i+= 40)
{
if(i < 40)
{
externalPort.LEDS++;
}
else
{
externalPort.LEDS <<=1;
externalPort.LEDS++;
}
}
outputExt();
if(tmp > 120)
{
waitForStart.state = PREPARE;
peak_count--;
}
if(peak_count == 0)
waitForStart.state = IDLE;
}
else
setLEDs(0b0000);
setStopwatch2(0);
}
}
}
/************************************************** ***************************/
// Behaviour check low Battery:
#define BATTERY_LOW 1
behaviour_command_t checkLowBattery = {0, 0, FWD,
false, false, 0, IDLE};
/**
* In this behaviour routine, we have nothing to do
*/
void behaviour_checkLowBattery(void)
{
}
/**
* This is a new Event Handler and it gets called when the Battery Voltage
* is getting low! The Parameter isVoltageLow is true, when the voltage
* is low and false, when the voltage is OK.
*/
void batteryVoltageLow(uint8_t isVoltageLow)
{
if(isVoltageLow)
checkLowBattery.state = BATTERY_LOW;
}
/************************************************** ***************************/
// Behaviour control:
/**
* 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) // move or rotate?
{
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; // clear move value - the move commands are only
// given once and then runs in background.
}
else if(!(cmd->move || cmd->rotate)) // just move at speed?
{
changeDirection(cmd->dir);
moveAtSpeed(cmd->speed_left,cmd->speed_right);
}
else if(isMovementComplete()) // movement complete? --> clear flags!
{
cmd->rotate = false;
cmd->move = false;
}
}
/**
* A small helper function to display the current behaviour on the
* LCD. It only prints out the active behaviour ONCE, otherwise the
* text would flicker on the LCD!
*/
void displayBehaviour(uint8_t behave)
{
static uint8_t compare = 0;
if(compare != behave)
{
compare = behave;
clearPosLCD(1, 0, 13);
setCursorPosLCD(1, 0);
switch(behave)
{
case 7: writeStringLCD_P("RC5 CONTROL"); setLEDs(0b0000); break;
case 6: writeStringLCD_P("LOW BATTERY!"); setLEDs(0b0000); break;
case 5: writeStringLCD_P("WAIT"); setLEDs(0b0000); break;
case 4: writeStringLCD_P("ESCAPE"); setLEDs(0b0110); break;
case 3: writeStringLCD_P("AVOID"); setLEDs(0b1001); break;
case 2: writeStringLCD_P("CRUISE"); setLEDs(0b0000); break;
case 1: writeStringLCD_P("STOP"); setLEDs(0b0000); break;
}
}
if(behave == 2) // If Cruise behaviour is active, show a running light...
{
static uint8_t runLEDs = 1;
static uint8_t dir = 0;
if(getStopwatch2() > 100)
{
setLEDs(runLEDs);
if(dir == 0)
runLEDs <<= 1;
else
runLEDs >>= 1;
if(runLEDs > 7 )
dir = 1;
else if (runLEDs < 2 )
dir = 0;
setStopwatch2(0);
}
}
if(behave == 6) // If Battery is low - beep all 3 seconds!
{
if(getStopwatch2() > 3000) // We can use Stopwatch2 here and
{ // for several other things because only
sound(200,20,20); // one of these things can be active at
sound(225,20,60); // the same time! You could not do this if
sound(200,20,20); // there were things that could be active
sound(225,20,0); // at the same time!
setStopwatch2(0);
}
}
}
/**
* The behaviourController task controls the subsumption architechture.
* It implements the priority levels of the different behaviours.
*
* Here we also show which behaviour is active on the LC-Display!
*
*/
void behaviourController(void)
{
// Call all the behaviour tasks:
behaviour_checkLowBattery();
behaviour_waitForStart();
behaviour_cruise();
behaviour_avoid();
behaviour_escape();
behaviour_rc5Reception();
// Execute the commands depending on priority levels:
if(checkLowBattery.state != IDLE) // Highest priority - 6
{
displayBehaviour(6);
moveCommand(&checkLowBattery);
}
else if(rc5Reception.state != IDLE) // Priority - 5a
{
displayBehaviour(7);
moveCommand(&rc5Reception);
}
else if(waitForStart.state != IDLE) // Priority - 5
{
displayBehaviour(5);
moveCommand(&waitForStart);
}
else if(escape.state != IDLE) // Priority - 4
{
displayBehaviour(4);
moveCommand(&escape);
}
else if(avoid.state != IDLE) // Priority - 3
{
displayBehaviour(3);
moveCommand(&avoid);
}
else if(cruise.state != IDLE) // Priority - 1
{
displayBehaviour(2);
moveCommand(&cruise);
}
else // Lowest priority - 0
{
displayBehaviour(1);
moveCommand(&STOP); // Default command - do nothing!
// In the current implementation this never
// happens.
}
}
/************************************************** ***************************/
/**
* Prints all Sensor Values on the Serial Interface.
*/
void printAllSensorValues(void)
{
getAllSensors();
writeString_P("\nRead Sensor Values:\n");
writeString_P("PL:");writeIntegerLength(mleft_power,DEC,3);
writeString_P(" | PR:");writeIntegerLength(mright_power,DEC,3);
writeString_P(" | VL:");writeIntegerLength(mleft_speed,DEC,3);
writeString_P(" | VR:");writeIntegerLength(mright_speed,DEC,3);
writeString_P(" | DL:");writeIntegerLength(mleft_des_speed,DEC,3);
writeString_P(" | DR:");writeIntegerLength(mright_des_speed,DEC,3);
writeChar('\n');
writeString_P("DSTL:");writeIntegerLength(mleft_dist,DEC,5);
writeString_P(" | DSTR:");writeIntegerLength(mright_dist,DEC,5);
writeChar('\n');
writeString_P("LSL:");writeIntegerLength(adcLSL,DEC,4);
writeString_P(" | LSR:");writeIntegerLength(adcLSR,DEC,4);
writeString_P(" | MCL:");writeIntegerLength(adcMotorCurrentLeft,DEC,4);
writeString_P(" | MCR:");writeIntegerLength(adcMotorCurrentRight,DEC,4);
writeString_P(" | BAT:");writeIntegerLength(adcBat,DEC,4);
writeString_P(" | AD0:");writeIntegerLength(adc0,DEC,4);
writeString_P(" | AD1:");writeIntegerLength(adc1,DEC,4);
writeChar('\n');
}
/**
* Heartbeat function
*/
void task_LCDHeartbeat(void)
{
if(getStopwatch1() > 500)
{
static uint8_t heartbeat = false;
if(heartbeat)
{
clearPosLCD(1, 15, 1);
heartbeat = false;
}
else
{
setCursorPosLCD(1, 15);
writeStringLCD_P("*");
heartbeat = true;
printAllSensorValues();
}
setStopwatch1(0);
}
}
/**
* Timed Watchdog display - the other heartbeat function
* does not work in this example as we use blocked moving functions here.
*/
void watchDogRequest(void)
{
static uint8_t heartbeat2 = false;
if(heartbeat2)
{
clearPosLCD(1, 14, 1);
heartbeat2 = false;
}
else
{
setCursorPosLCD(1, 14);
writeStringLCD_P("#");
heartbeat2 = true;
}
}
/************************************************** ***************************/
// I2C Requests:
/**
* The I2C_requestedDataReady Event Handler
*/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}
/************************************************** ***************************/
// I2C Error handler
/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}
/************************************************** ***************************/
// Main function - The program starts here:
int main(void)
{
initRP6Control();
initLCD();
writeString_P("\n\nRP6 CONTROL M32 I2C Master Example Program!\n");
writeString_P("\nMoving...\n");
// ---------------------------------------
WDT_setRequestHandler(watchDogRequest);
BUMPERS_setStateChangedHandler(bumpersStateChanged );
ACS_setStateChangedHandler(acsStateChanged);
IRCOMM_setRC5DataReadyHandler(receiveRC5Data);
BATTERY_setLowVoltageHandler(batteryVoltageLow);
// ---------------------------------------
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
sound(180,80,25);
sound(220,80,25);
setLEDs(0b1111);
showScreenLCD("################", "################");
mSleep(500);
showScreenLCD("I2C-Master", "Behaviours");
mSleep(1000);
setLEDs(0b0000);
// ---------------------------------------
// Setup ACS power:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
// Enable Watchdog for Interrupt requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
// Enable timed watchdog requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, true);
startStopwatch1();
startStopwatch2();
showScreenLCD("Active Behaviour", "");
while(true)
{
task_LCDHeartbeat();
task_checkINT0();
task_I2CTWI();
behaviourController();
}
return 0;
}
Damit kennt der RP6 3 RC5-Befehle:
a) Taste 1: MOVE, noch ohne Funktion. An die Stelle kommen die weiteren Fahrbefehle.
b) Taste 2: SHOW, Remote-Modus wird eingeschaltet, jede weitere Taste wird auf dem LCD angezeigt.
c) Taste 3: IDLE, Ende des Remote-Modus.
Hilft das?
Gruß Dirk
Hi Dirk,
die Signale der Fernbedienung empfangen und damit in ein anderes Verhalten wechseln hab ich schon selbst hinbekommen.
Aber in mindestens einem Punkt hast du mir schon geholfen: ich werd mein Programm mal etwas vereinfachen und es dann Schritt für Schritt wieder aufbauen. Dann kann ich hoffentlich den Fehler genauer eingrenzen.
Und eine Sache ist mir noch aufgefallen: Bei deinem Programm stoppen auch die Motoren des RP6, wenn ich die entsprechende Taste auf der Fernbedienung drücke. Bei meinem Programm war das nicht der Fall, obwohl ich eine stop()-Anweisung drin hatte und zusätzlich speed_left und -right im Behaviour-Struct auf 0 standen.
Ich hab das Gefühl, dass sich die Beschleunigungs-Anweisungen und die deccelerate-Funktion in meinem Programm gegenseitig stören.
Ich werds mal am Wochenende mit weniger Code für die RC5-Signale probieren und schauen, ob ich nen Fehler finde.
Weitere Tips und Anregungen sind aber immernoch erwünscht ;)
mfg,
V:X
Hallo V:X,
Weitere Tips und Anregungen sind aber immernoch erwünscht
Noch mehr?
Hier z.B. das Verhalten "RC5 Empfang":
/************************************************** ***************************/
// RC5 Reception Behaviour:
// The TV Remote Control definitions
// ###########################
// Uncomment __one__ (only one!) of the following definitions:
//#define RC_EURO_SKY
//#define RC_PROMO8
#define RC_TOTAL_CONTROL
//#define RC_YOUR_OWN
// ...
// ###########################
// Change the keymapping here:
#ifdef RC_EUROSKY // RC Type: Conrad - EuroSky
#define RC5_KEY_LEFT 22
#define RC5_KEY_RIGHT 21
#define RC5_KEY_FORWARDS 16
#define RC5_KEY_BACKWARDS 17
#define RC5_KEY_STOP 23
#define RC5_KEY_CURVE_LEFT 1
#define RC5_KEY_CURVE_RIGHT 3
#define RC5_KEY_CURVE_BACK_LEFT 7
#define RC5_KEY_CURVE_BACK_RIGHT 9
#define RC5_KEY_LEFT_MOTOR_FWD 1
#define RC5_KEY_LEFT_MOTOR_BWD 7
#define RC5_KEY_RIGHT_MOTOR_FWD 3
#define RC5_KEY_RIGHT_MOTOR_BWD 9
#define RC5_KEY_CONTROL_START ?
#define RC5_KEY_CONTROL_END ?
#endif
#ifdef RC_PROMO8 // RC Type: Conrad - Promo8
#define RC5_KEY_LEFT 21
#define RC5_KEY_RIGHT 22
#define RC5_KEY_FORWARDS 32
#define RC5_KEY_BACKWARDS 33
#define RC5_KEY_STOP 11
#define RC5_KEY_CURVE_LEFT 29
#define RC5_KEY_CURVE_RIGHT 13
#define RC5_KEY_CURVE_BACK_LEFT 10
#define RC5_KEY_CURVE_BACK_RIGHT 62
#define RC5_KEY_LEFT_MOTOR_FWD 1
#define RC5_KEY_LEFT_MOTOR_BWD 7
#define RC5_KEY_RIGHT_MOTOR_FWD 3
#define RC5_KEY_RIGHT_MOTOR_BWD 9
#define RC5_KEY_CONTROL_START ?
#define RC5_KEY_CONTROL_END ?
#endif
#ifdef RC_TOTAL_CONTROL // RC Type: Conrad - TOTAL control
#define RC5_KEY_LEFT 4 // 4
#define RC5_KEY_RIGHT 6 // 6
#define RC5_KEY_FORWARDS 2 // 2
#define RC5_KEY_BACKWARDS 8 // 8
#define RC5_KEY_STOP 5 // 5
#define RC5_KEY_CURVE_LEFT 32 // P+
#define RC5_KEY_CURVE_RIGHT 16 // L+
#define RC5_KEY_CURVE_BACK_LEFT 33 // P-
#define RC5_KEY_CURVE_BACK_RIGHT 17 // L-
#define RC5_KEY_LEFT_MOTOR_FWD 1 // 1
#define RC5_KEY_LEFT_MOTOR_BWD 7 // 7
#define RC5_KEY_RIGHT_MOTOR_FWD 3 // 3
#define RC5_KEY_RIGHT_MOTOR_BWD 9 // 9
#define RC5_KEY_CONTROL_START 23 // ENTER
#define RC5_KEY_CONTROL_END 0 // 0
#endif
#ifdef RC_YOUR_OWN // Your own RC!
#define RC5_KEY_LEFT 4
#define RC5_KEY_RIGHT 6
#define RC5_KEY_FORWARDS 2
#define RC5_KEY_BACKWARDS 8
#define RC5_KEY_STOP 5
#define RC5_KEY_CURVE_LEFT 1
#define RC5_KEY_CURVE_RIGHT 3
#define RC5_KEY_CURVE_BACK_LEFT 7
#define RC5_KEY_CURVE_BACK_RIGHT 9
#define RC5_KEY_LEFT_MOTOR_FWD 10
#define RC5_KEY_LEFT_MOTOR_BWD 11
#define RC5_KEY_RIGHT_MOTOR_FWD 12
#define RC5_KEY_RIGHT_MOTOR_BWD 13
#define RC5_KEY_CONTROL_START ?
#define RC5_KEY_CONTROL_END ?
#endif
//... you can add more Remote control keymappings or implement something
// better than this if you like...
#define RC5RECEPTION_MOVE 1
behaviour_command_t rc5Reception = {0, 0, FWD, false, false, 0, IDLE};
/**
* Behaviour with RC5 Reception.
*/
void behaviour_rc5Reception(void)
{
}
#define RC5RECEPTION_SPEED_ROTATE 60
#define RC5RECEPTION_SPEED_MAX 80
#define RC5RECEPTION_SPEED_L_ARC_LEFT 20
#define RC5RECEPTION_SPEED_L_ARC_RIGHT 80
#define RC5RECEPTION_SPEED_R_ARC_LEFT 80
#define RC5RECEPTION_SPEED_R_ARC_RIGHT 20
/**
* RC5 Event Handler
*/
void receiveRC5Data(RC5data_t rc5data)
{
// Check which key is pressed:
switch(rc5data.key_code)
{
case RC5_KEY_LEFT: // Turn left:
rc5Reception.speed_left = RC5RECEPTION_SPEED_ROTATE;
rc5Reception.speed_right = 0;
rc5Reception.dir = LEFT;
rc5Reception.move = false;
rc5Reception.rotate = true;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_RIGHT: // Turn right:
rc5Reception.speed_left = RC5RECEPTION_SPEED_ROTATE;
rc5Reception.speed_right = 0;
rc5Reception.dir = RIGHT;
rc5Reception.move = false;
rc5Reception.rotate = true;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_FORWARDS: // Move forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_BACKWARDS: // Move backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_STOP: // Stop!
rc5Reception.speed_left = 0;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = false;
rc5Reception.rotate = false;
rc5Reception.move_value = 0;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_LEFT: // Drive curve left - forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_L_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_L_ARC_RIGHT;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_RIGHT: // Drive curve right - forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_R_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_R_ARC_RIGHT;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_BACK_LEFT: // Drive curve left - backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_L_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_L_ARC_RIGHT;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_BACK_RIGHT: // Drive curve right - backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_R_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_R_ARC_RIGHT;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_LEFT_MOTOR_FWD: // Only left motor on - forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_LEFT_MOTOR_BWD: // Only left motor on - backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = 0;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_RIGHT_MOTOR_FWD: // Only right motor on - forwards
rc5Reception.speed_left = 0;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_RIGHT_MOTOR_BWD: // Only right motor on - backwards
rc5Reception.speed_left = 0;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CONTROL_START: // Start of the RC5 control mode
rc5Reception.speed_left = 0;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = false;
rc5Reception.rotate = false;
rc5Reception.move_value = 0;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CONTROL_END: // End of the RC5 control mode
rc5Reception.speed_left = 0;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = false;
rc5Reception.rotate = false;
rc5Reception.move_value = 0;
rc5Reception.state = IDLE;
break;
}
if(rc5Reception.state == RC5RECEPTION_MOVE)
{
if(getStopwatch2() > 500)
{
clearPosLCD(1, 0, 13);
setCursorPosLCD(1, 0);
// Display the received data:
writeStringLCD_P("RC5 ");
writeCharLCD(rc5data.toggle_bit + '0');
writeStringLCD_P(" |");
writeIntegerLCD(rc5data.device, DEC);
writeStringLCD_P(" |");
writeIntegerLCD(rc5data.key_code, DEC);
setStopwatch2(0);
}
}
}
/************************************************** ***************************/
Gruß Dirk
klausjuergen
06.11.2010, 13:15
Hallo V:X,
Weitere Tips und Anregungen sind aber immernoch erwünscht
Noch mehr?
Hier z.B. das Verhalten "RC5 Empfang":
/************************************************** ***************************/
// RC5 Reception Behaviour:
// The TV Remote Control definitions
// ###########################
// Uncomment __one__ (only one!) of the following definitions:
//#define RC_EURO_SKY
//#define RC_PROMO8
#define RC_TOTAL_CONTROL
//#define RC_YOUR_OWN
// ...
// ###########################
// Change the keymapping here:
#ifdef RC_EUROSKY // RC Type: Conrad - EuroSky
#define RC5_KEY_LEFT 22
#define RC5_KEY_RIGHT 21
#define RC5_KEY_FORWARDS 16
#define RC5_KEY_BACKWARDS 17
#define RC5_KEY_STOP 23
#define RC5_KEY_CURVE_LEFT 1
#define RC5_KEY_CURVE_RIGHT 3
#define RC5_KEY_CURVE_BACK_LEFT 7
#define RC5_KEY_CURVE_BACK_RIGHT 9
#define RC5_KEY_LEFT_MOTOR_FWD 1
#define RC5_KEY_LEFT_MOTOR_BWD 7
#define RC5_KEY_RIGHT_MOTOR_FWD 3
#define RC5_KEY_RIGHT_MOTOR_BWD 9
#define RC5_KEY_CONTROL_START ?
#define RC5_KEY_CONTROL_END ?
#endif
#ifdef RC_PROMO8 // RC Type: Conrad - Promo8
#define RC5_KEY_LEFT 21
#define RC5_KEY_RIGHT 22
#define RC5_KEY_FORWARDS 32
#define RC5_KEY_BACKWARDS 33
#define RC5_KEY_STOP 11
#define RC5_KEY_CURVE_LEFT 29
#define RC5_KEY_CURVE_RIGHT 13
#define RC5_KEY_CURVE_BACK_LEFT 10
#define RC5_KEY_CURVE_BACK_RIGHT 62
#define RC5_KEY_LEFT_MOTOR_FWD 1
#define RC5_KEY_LEFT_MOTOR_BWD 7
#define RC5_KEY_RIGHT_MOTOR_FWD 3
#define RC5_KEY_RIGHT_MOTOR_BWD 9
#define RC5_KEY_CONTROL_START ?
#define RC5_KEY_CONTROL_END ?
#endif
#ifdef RC_TOTAL_CONTROL // RC Type: Conrad - TOTAL control
#define RC5_KEY_LEFT 4 // 4
#define RC5_KEY_RIGHT 6 // 6
#define RC5_KEY_FORWARDS 2 // 2
#define RC5_KEY_BACKWARDS 8 // 8
#define RC5_KEY_STOP 5 // 5
#define RC5_KEY_CURVE_LEFT 32 // P+
#define RC5_KEY_CURVE_RIGHT 16 // L+
#define RC5_KEY_CURVE_BACK_LEFT 33 // P-
#define RC5_KEY_CURVE_BACK_RIGHT 17 // L-
#define RC5_KEY_LEFT_MOTOR_FWD 1 // 1
#define RC5_KEY_LEFT_MOTOR_BWD 7 // 7
#define RC5_KEY_RIGHT_MOTOR_FWD 3 // 3
#define RC5_KEY_RIGHT_MOTOR_BWD 9 // 9
#define RC5_KEY_CONTROL_START 23 // ENTER
#define RC5_KEY_CONTROL_END 0 // 0
#endif
#ifdef RC_YOUR_OWN // Your own RC!
#define RC5_KEY_LEFT 4
#define RC5_KEY_RIGHT 6
#define RC5_KEY_FORWARDS 2
#define RC5_KEY_BACKWARDS 8
#define RC5_KEY_STOP 5
#define RC5_KEY_CURVE_LEFT 1
#define RC5_KEY_CURVE_RIGHT 3
#define RC5_KEY_CURVE_BACK_LEFT 7
#define RC5_KEY_CURVE_BACK_RIGHT 9
#define RC5_KEY_LEFT_MOTOR_FWD 10
#define RC5_KEY_LEFT_MOTOR_BWD 11
#define RC5_KEY_RIGHT_MOTOR_FWD 12
#define RC5_KEY_RIGHT_MOTOR_BWD 13
#define RC5_KEY_CONTROL_START ?
#define RC5_KEY_CONTROL_END ?
#endif
//... you can add more Remote control keymappings or implement something
// better than this if you like...
#define RC5RECEPTION_MOVE 1
behaviour_command_t rc5Reception = {0, 0, FWD, false, false, 0, IDLE};
/**
* Behaviour with RC5 Reception.
*/
void behaviour_rc5Reception(void)
{
}
#define RC5RECEPTION_SPEED_ROTATE 60
#define RC5RECEPTION_SPEED_MAX 80
#define RC5RECEPTION_SPEED_L_ARC_LEFT 20
#define RC5RECEPTION_SPEED_L_ARC_RIGHT 80
#define RC5RECEPTION_SPEED_R_ARC_LEFT 80
#define RC5RECEPTION_SPEED_R_ARC_RIGHT 20
/**
* RC5 Event Handler
*/
void receiveRC5Data(RC5data_t rc5data)
{
// Check which key is pressed:
switch(rc5data.key_code)
{
case RC5_KEY_LEFT: // Turn left:
rc5Reception.speed_left = RC5RECEPTION_SPEED_ROTATE;
rc5Reception.speed_right = 0;
rc5Reception.dir = LEFT;
rc5Reception.move = false;
rc5Reception.rotate = true;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_RIGHT: // Turn right:
rc5Reception.speed_left = RC5RECEPTION_SPEED_ROTATE;
rc5Reception.speed_right = 0;
rc5Reception.dir = RIGHT;
rc5Reception.move = false;
rc5Reception.rotate = true;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_FORWARDS: // Move forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_BACKWARDS: // Move backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_STOP: // Stop!
rc5Reception.speed_left = 0;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = false;
rc5Reception.rotate = false;
rc5Reception.move_value = 0;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_LEFT: // Drive curve left - forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_L_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_L_ARC_RIGHT;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_RIGHT: // Drive curve right - forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_R_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_R_ARC_RIGHT;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_BACK_LEFT: // Drive curve left - backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_L_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_L_ARC_RIGHT;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CURVE_BACK_RIGHT: // Drive curve right - backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_R_ARC_LEFT;
rc5Reception.speed_right = RC5RECEPTION_SPEED_R_ARC_RIGHT;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_LEFT_MOTOR_FWD: // Only left motor on - forwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_LEFT_MOTOR_BWD: // Only left motor on - backwards
rc5Reception.speed_left = RC5RECEPTION_SPEED_MAX;
rc5Reception.speed_right = 0;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_RIGHT_MOTOR_FWD: // Only right motor on - forwards
rc5Reception.speed_left = 0;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = FWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_RIGHT_MOTOR_BWD: // Only right motor on - backwards
rc5Reception.speed_left = 0;
rc5Reception.speed_right = RC5RECEPTION_SPEED_MAX;
rc5Reception.dir = BWD;
rc5Reception.move = true;
rc5Reception.rotate = false;
rc5Reception.move_value = 100;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CONTROL_START: // Start of the RC5 control mode
rc5Reception.speed_left = 0;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = false;
rc5Reception.rotate = false;
rc5Reception.move_value = 0;
rc5Reception.state = RC5RECEPTION_MOVE;
break;
case RC5_KEY_CONTROL_END: // End of the RC5 control mode
rc5Reception.speed_left = 0;
rc5Reception.speed_right = 0;
rc5Reception.dir = FWD;
rc5Reception.move = false;
rc5Reception.rotate = false;
rc5Reception.move_value = 0;
rc5Reception.state = IDLE;
break;
}
if(rc5Reception.state == RC5RECEPTION_MOVE)
{
if(getStopwatch2() > 500)
{
clearPosLCD(1, 0, 13);
setCursorPosLCD(1, 0);
// Display the received data:
writeStringLCD_P("RC5 ");
writeCharLCD(rc5data.toggle_bit + '0');
writeStringLCD_P(" |");
writeIntegerLCD(rc5data.device, DEC);
writeStringLCD_P(" |");
writeIntegerLCD(rc5data.key_code, DEC);
setStopwatch2(0);
}
}
}
/************************************************** ***************************/
Gruß Dirk
Hallo
Mir ist nicht klar, wie dieser Code in das weiter oben vorgestellte erweiterte move Programm eingefügt werden muß.
kann mir hier jemand helfen?
Gruß Klaus
Ich habe da ein ähnliches Problem, wenn auch kleiner und auf der BASE!
Ich möchte zunächst nur, dass mein Robot zwar mit TV-Remote rumfährt, aber er soll später auch auf Knopfdruck in eigene Routinen fahren (z.B. Lichtverfolgung etc).
Da ich noch Anfänger bin, will ichs mal nicht übertreiben und habe einfach einen Bumper_stateChangeHandler eingebaut / einbauen wollen.
Aber es passiert rein gar nichts, wenn ich diese auslöse.
Kann sich das mal jemand ansehen, der was davon versteht?
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.