PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : M32 Master-Problem mit RC5



ComputerKind
17.01.2009, 14:35
Hi,
ich hab heut durch Zufall eine Fernbedienung gefunden, die RC5 senden kann. Ich hab auch schon ein Programm geschrieben um damit die Base fahren zu lassen und klappt bisher wunderbar. Beim Versuch es auf die M32 zu exportieren habe ich festgestellt, dass es nicht mehr funktioniert. Ich glaube das es daran liegt, das irgendwie keine RC5 daten vom RP6 zum M32 geschickt werden. Im RP6 ist das normale Slave-Programm und im Master ist folgendes:



#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"


void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}

void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}

void receiveRC5Data(RC5data_t rc5data){
writeInteger(rc5data.key_code,DEC);
writeString_P("\n");
}

int main(void)
{
initRP6Control();
startStopwatch1();
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
mSleep(500);
IRCOMM_setRC5DataReadyHandler(receiveRC5Data);

while(1)
{
task_checkINT0();
task_I2CTWI();
}
return 0;
}

Ich weiß nicht wie ich das Problem beheben kann.

Dirk
17.01.2009, 16:27
Hallo ComputerKind,

die RC5-Daten sind ja über die "Register" 27 und 28 abfragbar:
#define I2C_REG_RC5_ADR 27
#define I2C_REG_RC5_DATA 28
(Siehe z.B. RP6Control_07_I2CMaster.c!)

Das kann dann so aussehen:
I2CTWI_transmitByte(I2C_RP6_BASE_ADR, I2C_REG_RC5_ADR); // Start with register 27
I2CTWI_readBytes(I2C_RP6_BASE_ADR,RP6data, 2); // and read 2 registers

Gruß Dirk

P.S.: Was ist in der "RP6Control_I2CMasterLib.h"???

ComputerKind
17.01.2009, 16:44
In der RP6Control_I2CMasterLib.h und RP6Control_I2CMasterLib.c sind dafür da, dass man die wichtigsten MEthoden wie move im Mastermodus über I2C laufen lassen kann .Ich hab dann meine main-Funktion erweitert. Sie sieht jetzt folgendermaßen aus:

if(getStopwatch1() > 500){
I2CTWI_transmitByte(I2C_RP6_BASE_ADR, 27); // Start with register 27
I2CTWI_readBytes(I2C_RP6_BASE_ADR,RP6data, 2); // and read 2 registers
writeInteger(RP6data,DEC);
writeString_P("\n");
setStopwatch1(0);
RP6data ist vom Typ uint16_t. Wenn ich jetzt des Programm starte schreibt er mir nur 0 als ausgabe. also scheint das auch nicht die lösung zu sein

Dirk
17.01.2009, 17:01
Hallo ComputerKind,

sorry! Die RP6Control_I2CMasterLib stammt aus dem Example_08_I2CMaster, hatte ich übersehen.

Mein Code sollte ohne diese Lib funktionieren.

MIT der Lib sind die RC5-Daten, denke ich, in rc5data.device und rc5data.key_code zu finden.

Gruß Dirk

ComputerKind
17.01.2009, 17:06
Genau das ist ja das Problem! Irgendwie scheinen die Daten vom RP6 nicht zum M32 zu gelangen, da ja nicht mal der Event-Handler anspricht und etwas ausgibt. Ich hab auch mal getAllSensors(); eingefügt um wenigstens die anderen Sensordaten zu erhalten, wie z.B. Batteriespannung, aber die RC5-Daten bleiben weiterhin verschollen.
Mfg Computerkind

RP6conrad
17.01.2009, 18:21
Du musst auch der "ACS" function von basis einschalten. Das geht mit folgendes : I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_LOW);
Ohne das functioniert der RC5-empfang nicht.
Bei mir functioniert es problemlos.

ComputerKind
17.01.2009, 18:38
Ok, danke das hat mir sehr geholfen. Jetzt funktioniert es. Ich frag mich blos warum es bei der Base auch ohne vorheriges aktivieren des acs funktioniert...

inka
17.10.2013, 18:27
hallo,

ich habe den hier weiter unten geposteten code kaum geändert, er lässt sich kompilieren (code:blocks) aber nicht starten, auf dem display des RP6 erscheint sofort wieder die startanzeige...

edit: der mit make compilierter code startet auch nicht...

ich finde den grund nicht...könnte bitte jemand drüberschauen wo diesmal der detailteufel steckt?


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
//#include "standard.h"

#define I2C_RP6_BASE_ADR 10
/**************************************/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}
/**************************************/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}
/***************************************/
void receiveRC5Data(RC5data_t rc5data)
{
writeInteger(rc5data.key_code,DEC);
/*************/
writeString_P(" | Device Address:");
writeInteger(rc5data.device, DEC);
writeString_P(" | Key Code:");
writeInteger(rc5data.key_code, DEC);

/*************/
writeString_P("\n");
}
/****************************************/
int main(void)
{
initRP6Control();
while(true)
{

task_I2CTWI();
task_checkINT0();

I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_LOW);
mSleep(500);
IRCOMM_setRC5DataReadyHandler(receiveRC5Data);


}
return 0;
}

Dirk
17.10.2013, 21:56
Hi inka,

hier mal ein Programm für die M32, das das Beispiel 10 Move2 für die M32 kombiniert mit der Steuerung des RP6 durch eine RC5-Fernbedienung.

Wenn du Lust hast, experimentier mal damit.
Auf der Base läuft das Original-Slave Programm.
Eingebunden wird die RP6Control_I2CMasterLib.
Ich habe die "TOTAL Control" Fernbedienung von CONRAD, so dass im Programm die Definition RC_TOTAL_CONTROL aktiviert ist. Du müßtest ggf. einen eigenen Set von Befehlen für deine Fernbedienung bei "#ifdef RC_YOUR_OWN" definieren und dann RC_YOUR_OWN anstelle von RC_TOTAL_CONTROL definieren.

Der RP6 kann damit weiter autonom herumfahren (wie im Beispiel 10), kann aber mit einer Taste der Fernbedienung (bei mir ENTER) in den "Fernbedienungsmodus" geschaltet werden und reagiert damit auf alle Fahrbefehle.
Mit der Taste 0 (bei mir) schalte ich den "Fernbedienungsmodus" wieder aus, so dass der RP6 autonom weiter fahren kann.
Natürlich könnte man das Verhalten ganz anders machen: It's up to you!

/*
* ************************************************** **************************
* RP6 ROBOT SYSTEM - RP6 CONTROL M32 Examples
* ************************************************** **************************
* Example: I2C Master 10 - Behaviour based Robot with TV remote control
* Author(s): Dominik S. Herwald, Dirk (RC)
* ************************************************** **************************
* Description:
* This is a rather large example. We ported one of the behaviour based Robot
* Examples for the RP6 CONTROL M32 and added some new Behaviours.
* Now there is a Behaviour that lets the Robot wait until you clapped your
* hands three times or made some other noises.
* There is also a behaviour that checks if the Battery voltage is too low.
* If this is the case, the robot is stopped.
* In addition to the original example a new behaviour is implemented to
* control the robot with a RC5 TV remote control.
*
* Of course the Robot still drives around and tries to avoid collisions.
* The only difference is that it is controlled by the RP6 CONTROL M32.
*
* ################################################## ##########################
* #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+ #+#+#+#+#+#+#+#+#+#+#+#+#+
*
* ATTENTION: THE ROBOT MOVES AROUND IN THIS EXAMPLE! PLEASE PROVIDE ABOUT
* 2m x 2m OR MORE FREE SPACE FOR THE ROBOT!
*
* >>> DO NOT FORGET TO REMOVE THE FLAT CABLE CONNECTION TO THE USB INTERFACE
* BEFORE YOU START THIS PROGRAM BY PRESSING THE START BUTTON ON THE ROBOT!
*
* #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+ #+#+#+#+#+#+#+#+#+#+#+#+#+
* ################################################## ##########################
* ************************************************** **************************
*/

/************************************************** ***************************/
// 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);
}
}

/************************************************** ***************************/
// 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);
}
}
}

/************************************************** ***************************/
// 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);
}
}
if(behave == 7) // If RC5 control is active - beep every second!
{
if(getStopwatch2() > 1000)
{
sound(240,50,25); // Beep (C4)
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 - 5.5
{
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;
}

inka
18.10.2013, 20:11
Hi Dirk,

danke für die datei, damit zu xperimentieren braucht mehr zeit, als ich momentan habe, bin auch die ganze nächste woche weg. Aber - ich konnte die datei compilieren, an meine fernbedienung anpassen und es funktioniert...:-) - also nicht alles umsonst gewesen...

ich habe jetzt relativ viele baustellen hier - alle hängen sie mit meinem ladestation-projekt zusammen, auch das thema mit der Ir-testroutine (https://www.roboternetz.de/community/threads/63090-IR-testroutine) oder der USRBUS und der start-stop taster.

Der code hier
#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
//#include "standard.h"

#define I2C_RP6_BASE_ADR 10
/**************************************/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}
/**************************************/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}
/***************************************/
void receiveRC5Data(RC5data_t rc5data)
{
writeInteger(rc5data.key_code,DEC);
/*************/
writeString_P(" | Device Address:");
writeInteger(rc5data.device, DEC);
writeString_P(" | Key Code:");
writeInteger(rc5data.key_code, DEC);

/*************/
writeString_P("\n");
}
/****************************************/
int main(void)
{
initRP6Control();
showScreenLCD(" RP6Control M32", "rc5_test_1");
mSleep(2500);
clearLCD();

while(true)
{



task_I2CTWI();
task_checkINT0();

I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_LOW);
mSleep(500);
IRCOMM_setRC5DataReadyHandler(receiveRC5Data);


}
return 0;
}

sollte mir z.b. helfen die reaktion des RP6 auf IR-signale zu verstehen (ich muss ja auch eine(?) bake bauen) - das gelingt mir nur teilweise, ich habe z.b. keine ahnung warum die meldungen im terminal zweimal kommen?

zweite frage: kann das ACS eigentlich auch andere IR-dioden "sehen" oder nur die eigenen, die zum ACS gehören?

Dirk
19.10.2013, 12:07
Hi inka,

...kann das ACS eigentlich auch andere IR-dioden "sehen" oder nur die eigenen, die zum ACS gehören?
Der RP6 hat ja den IR-Empfänger (http://www.rn-wissen.de/index.php/RP6#Anti_Collision_System_.28ACS.29), der alle mit 36 kHz modulierten IR-Signale empfangen kann.
Allerdings hat er wenig "Richtwirkung", d.h. er empfängt überwiegend Signale von vorn, aber auch von allen Seiten durch Reflexionen von Wänden.

IR-Baken kann er unterscheiden, wenn jede z.B. einen eigenen (RC5-)Code rundum sendet. Wenn er die Richtung zur Bake feststellen will, gibt es 2 Möglichkeiten:
1. Er kennt die Position der Bake im Raum und fährt zu dieser Position
2. Er verfügt über einen Empfänger mit "Richtwirkung", kann Reflexionen ausblenden und fährt dann "auf dem IR-Strahl" zur Bake oder interpoliert 2 Strahlen, um die Position festzustellen.

Eine andere Möglichkeit wären IR-Baken, die nicht rundum, sondern eng gebündeltes IR-Licht aussenden. Die könnte der RP6 (mit Rundumempfang) erkennen, wenn er den Strahl kreuzt (Leuchtturm-Effekt).
Viele Möglichkeiten ...