Added lot's of code-files used during work

This commit is contained in:
sicarius 2007-02-11 18:32:03 +00:00
parent 644121b478
commit 56d9bdd39e
155 changed files with 23423 additions and 0 deletions

View file

@ -0,0 +1,41 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_avoid_border.c
* @brief Vermeide Abgruende
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_AVOID_BORDER_AVAILABLE
/*!
* Verhindert, dass der Bot in Graeben faellt
* @param *data der Verhaltensdatensatz
*/
void bot_avoid_border_behaviour(Behaviour_t *data){
if (sensBorderL > BORDER_DANGEROUS)
speedWishLeft=-BOT_SPEED_NORMAL;
if (sensBorderR > BORDER_DANGEROUS)
speedWishRight=-BOT_SPEED_NORMAL;
}
#endif

View file

@ -0,0 +1,142 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_avoid_col.c
* @brief Vermeide Kollisionen
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
#define ZONE_CLOSEST 0 /*!< Zone fuer extremen Nahbereich */
#define ZONE_NEAR 1 /*!< Zone fuer Nahbereich */
#define ZONE_FAR 2 /*!< Zone fuer Fernbereich */
#define ZONE_CLEAR 3 /*!< Zone fuer Freien Bereich */
#define BRAKE_CLOSEST -1.0 /*!< Bremsfaktor fuer extremen Nahbereich ( <1 ==> bremsen <0 ==> rueckwaerts) */
#define BRAKE_NEAR 0.6 /*!< Bremsfaktor fuer Nahbereich ( <1 ==> bremsen <0 ==> rueckwaerts) */
#define BRAKE_FAR 0.8 /*!< Bremsfaktor fuer Fernbereich ( <1 ==> bremsen <0 ==> rueckwaerts) */
uint8 col_zone_l=ZONE_CLEAR; /*!< Kollisionszone, in der sich der linke Sensor befindet */
uint8 col_zone_r=ZONE_CLEAR; /*!< Kollisionszone, in der sich der rechte Sensor befindet */
/*!
* Passt auf, dass keine Kollision mit Hindernissen an der Front des Roboters
* geschieht.
* TODO: Diese Funktion ist nur ein Dummy-Beispiel, wie eine Kollisionsvermeidung aussehen
* koennte. Hier ist ein guter Einstiegspunkt fuer eigene Experimente und Algorithmen!
* @param *data der Verhaltensdatensatz
*/
void bot_avoid_col_behaviour(Behaviour_t *data){
if (sensDistR < COL_CLOSEST) /* sehr nah */
col_zone_r=ZONE_CLOSEST; /* dann auf jeden Fall CLOSEST Zone */
else
/* sind wir naeher als NEAR und nicht in der inneren Zone gewesen */
if ((sensDistR < COL_NEAR) && (col_zone_r > ZONE_CLOSEST))
col_zone_r=ZONE_NEAR; /* dann auf in die NEAR-Zone */
else
/* sind wir naeher als FAR und nicht in der NEAR-Zone gewesen */
if ((sensDistR < COL_FAR) && (col_zone_r > ZONE_NEAR))
col_zone_r=ZONE_FAR; /* dann auf in die FAR-Zone */
else
/* wir waren in einer engeren Zone und verlassen sie in Richtung NEAR */
if (sensDistR < (COL_NEAR * 0.50))
col_zone_r=ZONE_NEAR; /* dann auf in die NEAR-Zone */
else
if (sensDistR < (COL_FAR * 0.50))
col_zone_r=ZONE_FAR; /* dann auf in die NEAR-Zone */
else
col_zone_r=ZONE_CLEAR; /* dann auf in die CLEAR-Zone */
if (sensDistL < COL_CLOSEST) /* sehr nah */
col_zone_l=ZONE_CLOSEST; /* dann auf jeden Fall CLOSEST-Zone */
else
/* sind wir naeher als NEAR und nicht in der inneren Zone gewesen */
if ((sensDistL < COL_NEAR) && (col_zone_l > ZONE_CLOSEST))
col_zone_l=ZONE_NEAR; /* dann auf in die NEAR-Zone */
else
/* sind wir naeher als FAR und nicht in der NEAR-Zone gewesen */
if ((sensDistL < COL_FAR) && (col_zone_l > ZONE_NEAR))
col_zone_l=ZONE_FAR; /* dann auf in die FAR-Zone */
else
/* wir waren in einer engeren Zone und verlassen sie in Richtung NEAR */
if (sensDistL < (COL_NEAR * 0.50))
col_zone_l=ZONE_NEAR; /* dann auf in die NEAR-Zone */
else
if (sensDistL < (COL_FAR * 0.50))
col_zone_l=ZONE_FAR; /* dann auf in die NEAR-Zone */
else
col_zone_l=ZONE_CLEAR; /* dann auf in die CLEAR-Zone */
// Nur reagieren, wenn der Bot vorwaerts faehrt
if ((speed_l > 0) && (speed_r >0)) {
// wenn auf beiden Seiten in der Kollisionszone
if ((col_zone_r == ZONE_CLOSEST)&&(col_zone_l == ZONE_CLOSEST)){
// Drehe Dich zur Seite, wo mehr Platz ist
if (sensDistR < sensDistL)
bot_turn(data,20);
else
bot_turn(data,-20);
return;
}
switch (col_zone_l){
case ZONE_CLOSEST:
faktorWishRight = BRAKE_CLOSEST;
break;
case ZONE_NEAR:
faktorWishRight = BRAKE_NEAR;
break;
case ZONE_FAR:
faktorWishRight = BRAKE_FAR;
break;
case ZONE_CLEAR:
faktorWishRight = 1;
break;
default:
col_zone_l = ZONE_CLEAR;
break;
}
switch (col_zone_r){
case ZONE_CLOSEST:
faktorWishLeft = BRAKE_CLOSEST;
break;
case ZONE_NEAR:
faktorWishLeft = BRAKE_NEAR;
break;
case ZONE_FAR:
faktorWishLeft = BRAKE_FAR;
break;
case ZONE_CLEAR:
faktorWishLeft = 1;
break;
default:
col_zone_r = ZONE_CLEAR;
break;
}
}
}
#endif

View file

@ -0,0 +1,106 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_catch_pillar.c
* @brief sucht nach einer Dose und fängt sie ein
*
* @author Benjamin Benz (bbe@heise.de)
* @date 08.12.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_CATCH_PILLAR_AVAILABLE
#include <math.h>
#define MAX_PILLAR_DISTANCE 350
#define START 0
#define LEFT_FOUND 1
#define TURN_MIDDLE 2
#define GO 3
static uint8 pillar_state=START;
/*!
* Fange eine Dose ein
* @param *data der Verhaltensdatensatz
*/
void bot_catch_pillar_behaviour(Behaviour_t *data){
static float angle;
switch (pillar_state){
case START:
if (sensDistL < MAX_PILLAR_DISTANCE){ // sieht der linke Sensor schon was?
angle=heading;
pillar_state=LEFT_FOUND;
} else
speedWishLeft=-BOT_SPEED_SLOW;
speedWishRight=+BOT_SPEED_SLOW;
//bot_turn(data,5); // Ein Stueck drehen
break;
case LEFT_FOUND:
if (sensDistR < MAX_PILLAR_DISTANCE){ // sieht der rechte Sensor schon was?
angle= heading- angle;
if (angle < 0)
angle+=360;
angle= heading - angle/2;
pillar_state=TURN_MIDDLE;
// bot_turn(data,-angle/2);
}else
speedWishLeft=-BOT_SPEED_SLOW;
speedWishRight=+BOT_SPEED_SLOW;
// bot_turn(data,5); // Eins Stueck drehen
break;
case TURN_MIDDLE:
if (fabs(heading - angle) > 2){
speedWishLeft=+BOT_SPEED_SLOW;
speedWishRight=-BOT_SPEED_SLOW;
} else {
bot_servo(data,SERVO1,DOOR_OPEN); // Klappe auf
pillar_state=GO;
}
break;
case GO:
if (sensTrans ==0){
speedWishLeft=+BOT_SPEED_SLOW;
speedWishRight=+BOT_SPEED_SLOW;
} else {
bot_servo(data,SERVO1,DOOR_CLOSE);
pillar_state++;
}
break;
default:
pillar_state=START;
return_from_behaviour(data);
break;
}
}
/*!
* Fange ein Objekt ein
* @param caller Der obligatorische Verhaltensdatensatz des Aufrufers
*/
void bot_catch_pillar(Behaviour_t * caller){
pillar_state=0;
// Zielwerte speichern
switch_to_behaviour(caller,bot_catch_pillar_behaviour,OVERRIDE);
}
#endif

View file

@ -0,0 +1,120 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_drive_distance.c
* @brief Bot faehrt ein Stueck
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#include "log.h"
#ifdef BEHAVIOUR_DRIVE_DISTANCE_AVAILABLE
/* Parameter fuer das bot_drive_distance_behaviour() */
int16 drive_distance_target; /*!< Zu fahrende Distanz bzw. angepeilter Stand der Radencoder sensEncL bzw. sensEncR */
int8 drive_distance_curve; /*!< Kruemmung der zu fahrenden Strecke. */
int16 drive_distance_speed; /*!< Angepeilte Geschwindigkeit. */
/*!
* laesst den Bot in eine Richtung fahren.
* Es handelt sich hierbei nicht im eigentlichen Sinn um ein Verhalten, sondern ist nur eine Abstraktion der Motorkontrollen.
* @param curve Gibt an, ob der Bot eine Kurve fahren soll. Werte von -127 (So scharf wie moeglich links) ueber 0 (gerade aus) bis 127 (so scharf wie moeglich rechts)
* @param speed Gibt an, wie schnell der Bot fahren soll. */
void bot_drive(int8 curve, int16 speed){
// Wenn etwas ausgewichen wurde, bricht das Verhalten hier ab, sonst wuerde es evtl. die Handlungsanweisungen von bot_avoid_harm() stoeren.
//if(bot_avoid_harm()) return;
if(curve < 0) {
speedWishLeft = speed * (1.0 + 2.0*((float)curve/127));
speedWishRight = speed;
} else if (curve > 0) {
speedWishRight = speed * (1.0 - 2.0*((float)curve/127));
speedWishLeft = speed;
} else {
speedWishLeft = speed;
speedWishRight = speed;
}
}
/*!
* Das Verhalten laesst den Bot eine vorher festgelegte Strecke fahren.
* @param *data der Verhaltensdatensatz
* @see bot_drive_distance()
*/
void bot_drive_distance_behaviour(Behaviour_t* data){
int16 *encoder;
int16 to_drive;
if (drive_distance_curve > 0){
// Es handelt sich um eine Rechtskurve, daher wird mit dem linken Encoder gerechnet
encoder = (int16*)&sensEncL;
} else {
encoder = (int16*)&sensEncR;
}
to_drive = drive_distance_target - *encoder;
if(drive_distance_speed < 0) to_drive = -to_drive;
if(to_drive <= 0){
return_from_behaviour(data);
} else {
if((drive_distance_speed > BOT_SPEED_SLOW || drive_distance_speed < -BOT_SPEED_SLOW) && to_drive < (0.1 * ENCODER_MARKS)) bot_drive(drive_distance_curve, drive_distance_speed / 2);
else bot_drive(drive_distance_curve, drive_distance_speed);
}
}
/*!
* Das Verhalten laesst den Bot eine vorher festgelegte Strecke fahren. Dabei legt die Geschwindigkeit fest, ob der Bot vorwaerts oder rueckwaerts fahren soll.
* @param curve Gibt an, ob der Bot eine Kurve fahren soll. Werte von -127 (So scharf wie moeglich links) ueber 0 (gerade aus) bis 127 (so scharf wie moeglich rechts)
* @param speed Gibt an, wie schnell der Bot fahren soll. Negative Werte lassen den Bot rueckwaerts fahren.
* @param cm Gibt an, wie weit der Bot fahren soll. In cm :-) Die Strecke muss positiv sein, die Fahrtrichtung wird ueber speed geregelt.
*/
void bot_drive_distance(Behaviour_t* caller,int8 curve, int16 speed, int16 cm){
// LOG_DEBUG(("curve= %d, speed= %d, cm =%d",curve, speed, cm));
int32 tmp = cm;
tmp*= 10 * ENCODER_MARKS;
tmp /= WHEEL_PERIMETER;
int16 marks_to_drive = (int16) tmp;
int16 *encoder;
drive_distance_curve = curve;
drive_distance_speed = speed;
if (curve > 0){
// Es handelt sich um eine Rechtskurve, daher wird mit dem linken Encoder gerechnet
encoder = (int16*)&sensEncL;
} else {
encoder = (int16*)&sensEncR;
}
if(speed < 0){
// Es soll rueckwaerts gefahren werden. Der Zielwert ist also kleiner als der aktuelle Encoder-Stand.
drive_distance_target = *encoder - marks_to_drive;
} else {
drive_distance_target = *encoder + marks_to_drive;
}
switch_to_behaviour(caller, bot_drive_distance_behaviour,NOOVERRIDE);
}
#endif

View file

@ -0,0 +1,76 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_drive_square.c
* @brief Bot faehrt im Quadrat
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_DRIVE_SQUARE_AVAILABLE
/*!
* Laesst den Roboter ein Quadrat abfahren.
* Einfaches Beispiel fuer ein Verhalten, das einen Zustand besitzt.
* Es greift auf andere Behaviours zurueck und setzt daher
* selbst keine speedWishes.
* @param *data der Verhaltensdatensatz
*/
void bot_drive_square_behaviour(Behaviour_t *data){
#define STATE_TURN 1
#define STATE_FORWARD 0
#define STATE_INTERRUPTED 2
static uint8 state = STATE_FORWARD;
if (data->subResult == SUBFAIL) // letzter Auftrag schlug fehl?
state= STATE_INTERRUPTED;
switch (state) {
case STATE_FORWARD: // Vorwaerts
bot_goto(data,100,100);
state = STATE_TURN;
break;
case STATE_TURN: // Drehen
bot_goto(data,22,-22);
state=STATE_FORWARD;
break;
case STATE_INTERRUPTED:
return_from_behaviour(data); // Beleidigt sein und sich selbst deaktiviern
break;
default: /* Sind wir fertig, dann Kontrolle zurueck an Aufrufer */
return_from_behaviour(data);
break;
}
}
/*!
* Laesst den Roboter ein Quadrat abfahren.
* @param caller Der obligatorische Verhaltensdatensatz des aufrufers
*/
void bot_drive_square(Behaviour_t* caller){
switch_to_behaviour(caller, bot_drive_square_behaviour,OVERRIDE);
}
#endif

View file

@ -0,0 +1,176 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_follow_line.c
* @brief Linienverfolger
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_FOLLOW_LINE_AVAILABLE
/*! Folgt einer Linie, sobald beide Liniensensoren ausloesen
* Die Linie sollte in etwa die Breite beider CNY70 haben
*/
void bot_follow_line_behaviour(Behaviour_t *data) {
/* Konstanten fuer das Verhalten */
#define CORNER_LEFT 1
#define CORNER_RIGHT 2
/* Zustaende fuer das Verhalten */
#define CHECK_LINE 0 /* !< Feststellen ob wir ueber einer Linie sind */
#define FOLLOW_LINE 1 /* !< Folgen einer geraden oder leicht gekruemmten Linie */
#define CHECK_BORDER 2 /* !< Abgrundsensoren haben Alarm geschlagen. Feststellen ob wirklich Abgrund oder Ecke */
#define CORNER_TURN 3 /* !< Drehung in Richtun detektiertem Abgrund */
#define CORRECT_POS 4 /* !< Nach der Drehung 1cm vorfahren zum Ausgleichen */
#define ADVANCE_CORNER 5 /* !< Auf die Ecke zufahren, bis die Linie verschwindet */
#define RETREAT_AND_STOP 6 /* !< Zurueckfahren mit voller Geschwindigkeit, dann Stop und Verhalten verlassen */
/* Status- und Hilfsvariablen */
static int8 lineState=CHECK_LINE;
static int8 cornerDetected=False;
switch(lineState) {
case CHECK_LINE: /* sind beide Sensoren ueber einer Linie? */
if (sensLineL>=LINE_SENSE && sensLineR>=LINE_SENSE) {
/* zunaechst alle Hilfsverhalten ausschalten, die den Algorithmus stoeren */
/* Abgrund- und Kollisions-Verhalten ausschalten */
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
deactivateBehaviour(bot_avoid_col_behaviour);
#endif
#ifdef BEHAVIOUR_AVOID_BORDER_AVAILABLE
deactivateBehaviour(bot_avoid_border_behaviour);
#endif
/* bot_glance() stoert bot_turn() */
//deactivateBehaviour(bot_glance_behaviour);
/* losfahren und nach FOLLOW_LINE wechseln */
speedWishLeft=BOT_SPEED_FOLLOW;
speedWishRight=BOT_SPEED_FOLLOW;
lineState=FOLLOW_LINE;
}
break;
case FOLLOW_LINE:
/* Pruefen, ob die Abgrundsensoren einen Abgrund sehen */
if (sensBorderL>BORDER_DANGEROUS || sensBorderR>BORDER_DANGEROUS) {
/* Abgrund erkannt, das kann jetzt eine Linie sein oder ein richtiger Abgrund.*/
if (sensBorderL>BORDER_DANGEROUS && sensBorderR>BORDER_DANGEROUS) {
/* Wenn beidseitig erkannt, koennen wir damit nicht umgehen ->
* Ende des Verhaltens */
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
lineState=CHECK_LINE; /* Verhaltensstatus zuruecksetzen */
//LOG_INFO(("Stopp in FOLLOW_LINE"));
return_from_behaviour(data);
break;
}
/* nachsehen, ob der linke oder rechte Liniensensor ohne Kontakt zur Linie ist
* und ggfs. gegensteuern */
if (sensBorderL>BORDER_DANGEROUS) {
cornerDetected=CORNER_LEFT;
} else {
cornerDetected=CORNER_RIGHT;
}
/* nun zur vermuteten Ecke vorfahren */
lineState=CHECK_BORDER;
bot_drive_distance(data,0,BOT_SPEED_FOLLOW,3);
break;
}
if (sensLineL<LINE_SENSE && sensLineR>LINE_SENSE) {
/* links von der Linie abgekommen, daher nach rechts drehen */
//LOG_DEBUG(("Drehe rechts"));
speedWishLeft=BOT_SPEED_FOLLOW;
speedWishRight=-BOT_SPEED_FOLLOW;
} else if (sensLineL>LINE_SENSE && sensLineR<LINE_SENSE) {
/* andersrum, also links drehen */
//LOG_DEBUG(("Drehe links"));
speedWishLeft=-BOT_SPEED_FOLLOW;
speedWishRight=BOT_SPEED_FOLLOW;
} else if (sensLineL>LINE_SENSE && sensLineR>LINE_SENSE) {
/* noch ueber der Linie, also einfach geradeaus weiter */
//LOG_DEBUG(("Fahre geradeaus"));
speedWishLeft=BOT_SPEED_FOLLOW;
speedWishRight=BOT_SPEED_FOLLOW;
}
break;
case CHECK_BORDER:
/* wir sollten jetzt direkt an der Kante zum Abgrund stehen, wenn es
* denn wirklich eine ist. In dem Fall fahren wir ein Stueck zurueck.
* sonst gehen wir von einer Linie aus, drehen uns in die Richtung,
* in der wir den "Abgrund" entdeckt haben und machen dann weiter mit
* der Linienverfolgung */
if (sensBorderL>BORDER_DANGEROUS || sensBorderR>BORDER_DANGEROUS) {
/* scheint wirklich ein Abgrund zu sein */
lineState=RETREAT_AND_STOP;
speedWishLeft=-BOT_SPEED_MAX;
speedWishRight=-BOT_SPEED_MAX;
break;
}
/* war nur eine Ecke, noch weiter darauf zu bis kein Kontakt mehr zur Linie */
lineState=ADVANCE_CORNER;
speedWishLeft=BOT_SPEED_FOLLOW;
speedWishRight=BOT_SPEED_FOLLOW;
break;
case ADVANCE_CORNER:
/* auf die Ecke zufahren, bis die Linie verschwindet */
if (sensLineL<LINE_SENSE && sensLineR<LINE_SENSE) {
/* Linie weg, also Stop, kurz zurueck und drehen */
lineState=CORNER_TURN;
speedWishLeft=-BOT_SPEED_SLOW;
speedWishRight=-BOT_SPEED_SLOW;
break;
}
speedWishLeft=BOT_SPEED_FOLLOW;
speedWishRight=BOT_SPEED_FOLLOW;
break;
case CORNER_TURN:
/* 90<39> in Richtung des detektierten Abgrunds drehen */
lineState=CORRECT_POS;
bot_turn(data,(cornerDetected==CORNER_LEFT)?90:-90);
cornerDetected=False;
break;
case CORRECT_POS:
lineState=FOLLOW_LINE;
bot_drive_distance(data,0,BOT_SPEED_SLOW,2);
break;
case RETREAT_AND_STOP:
/* wir sind an einem Abgrund, Stop und Ende des Verhaltens */
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
cornerDetected=False;
lineState=CHECK_LINE;
return_from_behaviour(data);
break;
}
}
/*! Folgt einer Linie, sobald beide Liniensensoren ausloesen
* Die Linie sollte in etwa die Breite beider CNY70 haben
*/
void bot_follow_line(Behaviour_t *caller) {
switch_to_behaviour(caller, bot_follow_line_behaviour,NOOVERRIDE);
}
#endif

View file

@ -0,0 +1,141 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_goto.c
* @brief Bot faehrt einen punkt an
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_GOTO_AVAILABLE
#include <stdlib.h>
#define MOT_GOTO_MAX 4 /*!< Richtungsaenderungen, bis goto erreicht sein muss */
#define GOTO_REACHED 2 /*!< Wenn Encoder-Distanz <= GOTO_REACHED dann stop */
#define GOTO_SLOW 4 /*!< Wenn Encoder-Distanz < GOTO_SLOW dann langsame Fahrt */
#define GOTO_NORMAL 10 /*!< Wenn Encoder-Distanz < GOTO_NORMAL dann normale Fahrt */
#define GOTO_FAST 40 /*!< Wenn Encoder-Distanz < GOTO_FAST dann schnelle Fahrt, sonst maximale Fahrt */
int16 mot_l_goto=0; /*!< Speichert wie weit der linke Motor drehen soll */
int16 mot_r_goto=0; /*!< Speichert wie weit der rechte Motor drehen soll */
/*!
* Kuemmert sich intern um die Ausfuehrung der goto-Kommandos,
* @param *data der Verhaltensdatensatz
* @see bot_goto()
*/
void bot_goto_behaviour(Behaviour_t *data){
static int16 mot_goto_l=0; /*!< Muss der linke Motor noch drehen? */
static int16 mot_goto_r=0; /*!< Muss der rechte Motor noch drehen? */
int16 diff_l; /* Restdistanz links */
int16 diff_r; /* Restdistanz rechts */
/* Sind beide Zaehler Null und ist die Funktion active
* -- sonst waeren wir nicht hier --
* so ist dies der erste Aufruf ==> initialisieren */
if (( mot_goto_l ==0) && ( mot_goto_r ==0)){
/* Zaehler einstellen */
if (mot_l_goto !=0)
mot_goto_l= MOT_GOTO_MAX;
if (mot_r_goto !=0)
mot_goto_r=MOT_GOTO_MAX;
/* Encoder zuruecksetzen */
sensEncL=0;
sensEncR=0;
}
/* Motor L hat noch keine MOT_GOTO_MAX Nulldurchgaenge gehabt */
if (mot_goto_l >0){
diff_l = sensEncL - mot_l_goto; /* Restdistanz links */
if (abs(diff_l) <= GOTO_REACHED){ /* 2 Encoderstaende Genauigkeit reicht */
speedWishLeft = BOT_SPEED_STOP; /* Stop */
mot_goto_l--; /* wie Nulldurchgang behandeln */
}else if (abs(diff_l) < GOTO_SLOW)
speedWishLeft= BOT_SPEED_SLOW;
else if (abs(diff_l) < GOTO_NORMAL)
speedWishLeft= BOT_SPEED_NORMAL;
else if (abs(diff_l) < GOTO_FAST)
speedWishLeft= BOT_SPEED_FAST;
else speedWishLeft= BOT_SPEED_MAX;
// Richtung
if (diff_l>0) { // Wenn uebersteuert,
speedWishLeft= -speedWishLeft; //Richtung umkehren
}
// Wenn neue Richtung ungleich alter Richtung
if (((speedWishLeft<0)&& (direction.left == DIRECTION_FORWARD))|| ( (speedWishLeft>0) && (direction.left == DIRECTION_BACKWARD) ) )
mot_goto_l--; // Nulldurchgang merken
}
// Motor R hat noch keine MOT_GOTO_MAX Nulldurchgaenge gehabt
if (mot_goto_r >0){
diff_r = sensEncR - mot_r_goto; /* Restdistanz rechts */
if (abs(diff_r) <= GOTO_REACHED){ // 2 Encoderstaende Genauigkeit reicht
speedWishRight = BOT_SPEED_STOP; //Stop
mot_goto_r--; // wie Nulldurchgang behandeln
}else if (abs(diff_r) < GOTO_SLOW)
speedWishRight= BOT_SPEED_SLOW;
else if (abs(diff_r) < GOTO_NORMAL)
speedWishRight= BOT_SPEED_NORMAL;
else if (abs(diff_r) < GOTO_FAST)
speedWishRight= BOT_SPEED_FAST;
else speedWishRight= BOT_SPEED_MAX;
// Richtung
if (diff_r>0) { // Wenn uebersteurt,
speedWishRight= -speedWishRight; //Richtung umkehren
}
// Wenn neue Richtung ungleich alter Richtung
if (((speedWishRight<0)&& (direction.right == DIRECTION_FORWARD))|| ( (speedWishRight>0) && (direction.right == DIRECTION_BACKWARD) ) )
mot_goto_r--; // Nulldurchgang merken
}
/* Sind wir fertig, dann Regel deaktivieren */
if ((mot_goto_l == 0) && (mot_goto_r == 0)){
return_from_behaviour(data);
}
}
/*!
* Drehe die Raeder um die gegebene Zahl an Encoder-Schritten weiter
* @param left Schritte links
* @param right Schritte rechts
*/
void bot_goto(Behaviour_t * caller, int16 left, int16 right){
// Zielwerte speichern
mot_l_goto=left;
mot_r_goto=right;
switch_to_behaviour(caller,bot_goto_behaviour,OVERRIDE);
}
#endif

View file

@ -0,0 +1,141 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_gotoxy.c
* @brief Bot faehrt eine Position an
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_GOTOXY_AVAILABLE
#include <math.h>
/* Parameter fuer bot_gotoxy_behaviour-Verhalten */
float target_x; /*!< Zielkoordinate X */
float target_y; /*!< Zielkoordinate Y */
float initialDiffX; /*!< Anfangsdifferenz in X-Richtung */
float initialDiffY; /*!< Anfangsdifferenz in Y-Richtung */
/*!
* Auslagerung der Berechnung der benoetigten Drehung aus dem gotoxy_behaviour
* @param xDiff
* @param yDiff
*/
int16 bot_gotoxy_calc_turn(float xDiff, float yDiff){
float newHeading;
if(fabs(yDiff)>0.001 && fabs(xDiff)>0.001){
newHeading=atan(yDiff/xDiff)*180/(M_PI);
if (xDiff<0)
newHeading+=180;
} else{
if(fabs(xDiff)<=0.001)
newHeading=(yDiff>0)?90:(-90);
else
newHeading=(xDiff>0)?0:(180);
}
int16 toTurn=(int16)newHeading-heading;
if (toTurn > 180) toTurn-=360;
if (toTurn < -180) toTurn+=360;
return toTurn;
}
/*!
* Das Verhalten faehrt von der aktuellen Position zur angegebenen Position (x/y)
* @param *data der Verhaltensdatensatz
* Verbessert von Thomas Noll, Jens Schoemann, Ben Horst (Philipps-Universitaet Marburg)
*/
void bot_gotoxy_behaviour(Behaviour_t *data){
#define INITIAL_TURN 0
#define GOTO_LOOP 1
#define CORRECT_HEAD 2
#define REACHED_POS 3
static int16 speedLeft=BOT_SPEED_FOLLOW;
static int16 speedRight=BOT_SPEED_FOLLOW;
static int8 gotoState=INITIAL_TURN;
/* aus aktueller Position und Ziel neuen Zielwinkel berechnen */
float xDiff=target_x-x_pos;
float yDiff=target_y-y_pos;
if(xDiff*initialDiffX <0 || yDiff*initialDiffY <0){ // Hier kann noch verbessert werden
gotoState=REACHED_POS; // z.B. Abfragen statt *-Operation
speedWishLeft=BOT_SPEED_STOP; // bzw. neue Drehung statt Stehenbleiben
speedWishRight=BOT_SPEED_STOP;
}
switch(gotoState) {
case INITIAL_TURN:
gotoState=GOTO_LOOP;
bot_turn(data,bot_gotoxy_calc_turn(xDiff,yDiff));
break;
case GOTO_LOOP:
/* Position erreicht? */
if ((xDiff)<10 || (yDiff)<10) {
gotoState=CORRECT_HEAD;
bot_turn(data,bot_gotoxy_calc_turn(xDiff,yDiff));
break;
}
speedWishLeft=speedLeft;
speedWishRight=speedRight;
break;
case CORRECT_HEAD:
/* Position erreicht? */
if ((xDiff)<3 && (yDiff)<3) {
gotoState=REACHED_POS;
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
break;
}
speedWishLeft=BOT_SPEED_SLOW;
speedWishRight=BOT_SPEED_SLOW;
break;
case REACHED_POS:
gotoState=INITIAL_TURN;
return_from_behaviour(data);
break;
}
}
/*!
* Botenfunktion: Das Verhalten faehrt von der aktuellen Position zur angegebenen Position (x/y)
* @param caller Aufrufendes Verhalten
* @param x X-Ordinate an die der Bot fahren soll
* @param y Y-Ordinate an die der Bot fahren soll
*/
void bot_gotoxy(Behaviour_t *caller, float x, float y){
target_x=x;
target_y=y;
initialDiffX=x-x_pos;
initialDiffY=y-y_pos;
switch_to_behaviour(caller, bot_gotoxy_behaviour, NOOVERRIDE);
}
#endif

View file

@ -0,0 +1,428 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_olympic.c
* @brief Bot sucht saeulen und faehrt dann slalom
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_OLYMPIC_AVAILABLE
#include <stdlib.h>
/* Zustaende des bot_explore-Verhaltens */
#define EXPLORATION_STATE_GOTO_WALL 1 /*!< Zustand: Bot sucht eine Wand o.ae. Hinderniss */
#define EXPLORATION_STATE_TURN_PARALLEL_LEFT 2 /*!< Zustand: Bot dreht sich nach links, bis er parallel zur Wand blickt. */
#define EXPLORATION_STATE_TURN_PARALLEL_RIGHT 3 /*!< Zustand: Bot dreht sich nach rechts, bis er parallel zur Wand blickt. */
#define EXPLORATION_STATE_DRIVE_PARALLEL_LEFT 4 /*!< Zustand: Bot faehrt parallel zur Wand links von sich. */
#define EXPLORATION_STATE_DRIVE_PARALLEL_RIGHT 5 /*!< Zustand: Bot faehrt parallel zur Wand rechts von sich. */
#define EXPLORATION_STATE_TURN_ORTHOGONAL_LEFT 6 /*!< Zustand: Bot dreht sich nach links, bis er senkrecht zur Wand steht. */
#define EXPLORATION_STATE_TURN_ORTHOGONAL_RIGHT 7 /*!< Zustand: Bot dreht sich nach rechts, bis er senkrecht zur Wand steht. */
#define EXPLORATION_STATE_DRIVE_ARC 8 /*!< Zustand: Bot faehrt einen Bogen. Der Winkel des Bogens sollte in einer
*!< weiteren static Variablen (z.B. curve) gespeichert sein. */
/* Zustaende des bot_olympic_behaviour-Verhaltens */
#define CB_STATE_EXPLORATION 0 /*!< Zustand: Bot erforscht die Umgebung. */
#define CB_STATE_DOING_SLALOM 1 /*!< Zustand: Bot ist dabei Slalom zu fahren. */
/* Zustaende des bot_do_slalom-Verhaltens */
#define SLALOM_STATE_START 0 /*!< Zustand: Bot startet eine Slalomlauf und positioniert sich vor der Saeule. */
#define SLALOM_STATE_TURN_1 1 /*!< Zustand: Bot dreht sich um 90<39>. */
#define SLALOM_STATE_DRIVE_ARC 2 /*!< Zustand: Bot faehrt den Bogen um die Saeule. */
#define SLALOM_STATE_TURN_2 3 /*!< Zustand: Bot dreht sich fuer den Sweep um 45<34>. */
#define SLALOM_STATE_SWEEP_RUNNING 4 /*!< Zustand: Bot macht den Sweep. */
#define SLALOM_STATE_SWEEP_DONE 5 /*!< Zustand: Bot ist fertig mit dem Sweep. */
#define SLALOM_STATE_CHECK_PILLAR 6 /*!< Zustand: Bot ueberprueft, ob er den Slalom fortsetzen kann. */
#define SLALOM_ORIENTATION_LEFT 0
#define SLALOM_ORIENTATION_RIGHT 1
/* Parameter fuer das bot_explore_behaviour() */
int8 (*exploration_check_function)(void); /*!< Die Funktion, mit der das bot_explore_behaviour() feststellt, ob es etwas gefunden hat.
* Die Funktion muss True (1) zurueck geben, wenn dem so ist, sonst False (0).
* Beispiele fuer eine solche Funktion sind check_for_light, is_good_pillar_ahead etc.*/
/*!
* Das Verhalten dreht den Bot so, dass er auf eine Lichtquelle zufaehrt. */
void bot_goto_light(void){
int16 speed, curve = (sensLDRL - sensLDRR)/1.5;
if(curve < -127) curve = -127;
if(curve > 127) curve = 127;
if(abs(sensLDRL - sensLDRR) < 20){
speed = BOT_SPEED_MAX;
}else if(abs(sensLDRL - sensLDRR) < 150) {
speed = BOT_SPEED_FAST;
}else {
speed = BOT_SPEED_NORMAL;
}
bot_drive(curve, speed);
}
/*!
* Gibt aus, ob der Bot Licht sehen kann.
* @return True, wenn der Bot Licht sieht, sonst False. */
int8 check_for_light(void){
// Im Simulator kann man den Bot gut auf den kleinsten Lichtschein
// reagieren lassen, in der Realitaet gibt es immer Streulicht, so dass
// hier ein hoeherer Schwellwert besser erscheint.
// Simulator:
if(sensLDRL >= 1023 && sensLDRR >= 1023) return False;
// Beim echten Bot eher:
// if(sensLDRL >= 100 && sensLDRR >= 100) return False;
else return True;
}
/*!
* Die Funktion gibt aus, ob sich innerhalb einer gewissen Entfernung ein Objekt-Hindernis befindet.
* @param distance Entfernung in mm, bis zu welcher ein Objekt gesichtet wird.
* @return Gibt False (0) zurueck, wenn kein Objekt innerhalb von distance gesichtet wird. Ansonsten die Differenz
* zwischen dem linken und rechten Sensor. Negative Werte besagen, dass das Objekt naeher am linken, positive, dass
* es naeher am rechten Sensor ist. Sollten beide Sensoren den gleichen Wert haben, gibt die Funktion 1 zurueck, um
* von False unterscheiden zu koennen. */
int16 is_obstacle_ahead(int16 distance){
if(sensDistL > distance && sensDistR > distance) return False;
if(sensDistL - sensDistR == 0) return 1;
else return (sensDistL - sensDistR);
}
/*!
* Gibt aus, ob der Bot eine fuer sein Slalomverhalten geeignete Saeule vor sich hat.
* @return True, wenn er eine solche Saeule vor sich hat, sonst False.*/
int8 is_good_pillar_ahead(void){
if(is_obstacle_ahead(COL_NEAR) != False && sensLDRL < 600 && sensLDRR < 600) return True;
else return False;
}
/*!
* Das Verhalten verhindert, dass dem Bot boese Dinge wie Kollisionen oder Abstuerze widerfahren.
* @return Bestand Handlungsbedarf? True, wenn das Verhalten ausweichen musste, sonst False.
* TODO: Parameter einfuegen, der dem Verhalten vorschlaegt, wie zu reagieren ist.
* */
int8 bot_avoid_harm(void){
if(is_obstacle_ahead(COL_CLOSEST) != False || sensBorderL > BORDER_DANGEROUS || sensBorderR > BORDER_DANGEROUS){
speedWishLeft = -BOT_SPEED_NORMAL;
speedWishRight = -BOT_SPEED_NORMAL;
return True;
} else return False;
}
/*!
* Das Verhalten laesst den Roboter den Raum durchsuchen.
* Das Verhalten hat mehrere unterschiedlich Zustaende:
* 1. Zu einer Wand oder einem anderen Hindernis fahren.
* 2. Zu einer Seite drehen, bis der Bot parallel zur Wand ist.
* Es macht vielleicht Sinn, den Maussensor auszulesen, um eine Drehung um
* einen bestimmten Winkel zu realisieren. Allerdings muesste dafuer auch der
* Winkel des Bots zur Wand bekannt sein.
* 3. Eine feste Strecke parallel zur Wand vorwaerts fahren.
* Da bot_glance_behaviour abwechselnd zu beiden Seiten schaut, ist es fuer die Aufgabe,
* einer Wand auf einer Seite des Bots zu folgen, nur bedingt gewachsen und muss
* evtl. erweitert werden.
* 4. Senkrecht zur Wand drehen.
* Siehe 2.
* 5. Einen Bogen fahren, bis der Bot wieder auf ein Hindernis stoesst.
* Dann das Ganze von vorne beginnen, nur in die andere Richtung und mit einem
* weiteren Bogen. So erforscht der Bot einigermassen systematisch den Raum.
*
* Da das Verhalten jeweils nach 10ms neu aufgerufen wird, muss der Bot sich
* 'merken', in welchem Zustand er sich gerade befindet.
* */
void bot_explore_behaviour(Behaviour_t *data){
static int8 curve = 0,state = EXPLORATION_STATE_GOTO_WALL, running_curve = False;
if((*exploration_check_function)()) return_from_behaviour(data);
switch(state){
// Volle Fahrt voraus, bis ein Hindernis erreicht ist.
case EXPLORATION_STATE_GOTO_WALL:
// Der Bot steht jetzt vor einem Hindernis und soll sich nach rechts drehen
if(bot_avoid_harm()) {
state = EXPLORATION_STATE_TURN_PARALLEL_RIGHT;
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
deactivateBehaviour(bot_avoid_col_behaviour);
#endif
}
// Es befindet sich kein Hindernis direkt vor dem Bot.
else {
if(sensDistL < COL_NEAR || sensDistR < COL_NEAR){
bot_drive(0,BOT_SPEED_FAST);
} else {
bot_drive(0,BOT_SPEED_MAX);
}
}
break;
// Nach links drehen, bis der Bot parallel zum Hindernis auf der rechten Seite steht.
/* TODO: Aufgabe: Entwickle ein Verhalten, dass auch bei Loechern funktioniert.
* Tipp dazu: Drehe den Roboter auf das Loch zu, bis beide Bodensensoren das Loch 'sehen'. Anschliessend drehe den Bot um 90 Grad.
* Es ist noetig, neue Zustaende zu definieren, die diese Zwischenschritte beschreiben.
* TODO: Drehung mit dem Maussensor ueberwachen. */
case EXPLORATION_STATE_TURN_PARALLEL_LEFT:
if(sensDistR < COL_FAR){
// Volle Drehung nach links mit ca. 3Grad/10ms
bot_drive(-127,BOT_SPEED_FAST);
} else {
// Nachdem das Hindernis nicht mehr in Sicht ist, dreht der Bot noch ca. 3 Grad weiter.
// Im Zweifelsfall dreht das den Bot zu weit, aber das ist besser, als ihn zu kurz zu drehen.
bot_drive(-127,BOT_SPEED_FAST);
state = EXPLORATION_STATE_DRIVE_PARALLEL_RIGHT;
}
break;
// Nach rechts drehen, bis der Bot parallel zum Hindernis auf der linken Seite steht.
/* Aufgabe: siehe EXPLORATION_STATE_TURN_PARALLEL_LEFT */
case EXPLORATION_STATE_TURN_PARALLEL_RIGHT:
if(sensDistL < COL_FAR){
// Volle Drehung nach rechts mit ca. 3Grad/10ms
bot_drive(127,BOT_SPEED_FAST);
} else {
/* Nachdem das Hindernis nicht mehr in Sicht ist, dreht der Bot noch ca. 3 Grad weiter.
* Im Zweifelsfall dreht das den Bot zu weit, aber das ist besser, als ihn zu kurz zu drehen. */
bot_drive(127,BOT_SPEED_FAST);
state = EXPLORATION_STATE_DRIVE_PARALLEL_LEFT;
}
break;
case EXPLORATION_STATE_DRIVE_PARALLEL_LEFT:
bot_drive_distance(data,0,BOT_SPEED_FAST,15);
state = EXPLORATION_STATE_TURN_ORTHOGONAL_RIGHT;
break;
case EXPLORATION_STATE_DRIVE_PARALLEL_RIGHT:
bot_drive_distance(data,0,BOT_SPEED_FAST,15);
state = EXPLORATION_STATE_TURN_ORTHOGONAL_LEFT;
break;
case EXPLORATION_STATE_TURN_ORTHOGONAL_LEFT:
// Drehe den Bot um 90 Grad nach links.
/* Da der Bot sich immer ein bisschen zu weit von der Wand weg dreht, soll er sich
* hier nur um 85 Grad drehen. Nicht schoen, aber klappt.*/
bot_turn(data,85);
state = EXPLORATION_STATE_DRIVE_ARC;
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
activateBehaviour(bot_avoid_col_behaviour);
#endif
break;
case EXPLORATION_STATE_TURN_ORTHOGONAL_RIGHT:
// Drehe den Bot um 90 Grad nach rechts.
/* Da der Bot sich immer ein bisschen zu weit von der Wand weg dreht, soll er sich
* hier nur um 85 Grad drehen. Nicht schoen, aber klappt.*/
bot_turn(data,-85);
state = EXPLORATION_STATE_DRIVE_ARC;
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
activateBehaviour(bot_avoid_col_behaviour);
#endif
break;
case EXPLORATION_STATE_DRIVE_ARC:
/* Fahre einen Bogen.
* Der Bot soll im Wechsel Links- und Rechtsboegen fahren. Daher muss das Vorzeichen von curve wechseln.
* Ausserdem soll der Bogen zunehmend weiter werden, so dass der absolute Wert von curve abnehmen muss.
* Ist der Wert 0, wird er auf den engsten Bogen initialisiert. Da der Bot am Anfang nach rechts abbiegt,
* muss der Wert positiv sein.
* Aufgabe: Manchmal kann es passieren, dass der Bot bei einer kleinen Kurve zu weit weg von der Wand
* startet und dann nur noch im Kreis faehrt. Unterbinde dieses Verhalten.
*/
if(curve == 0){
curve = 25;
running_curve = True;
} else if (running_curve == False){
curve *= -0.9;
running_curve = True;
}
/* Sobald der Bot auf ein Hindernis stoesst, wird der naechste Zyklus eingeleitet.
* Auf einen Rechtsbogen (curve > 0) folgt eine Linksdrehung und auf einen Linksbogen eine Rechtsdrehung.
* Wenn der Wert von curve (durch Rundungsfehler bei int) auf 0 faellt, beginnt das Suchverhalten erneut.*/
if(bot_avoid_harm()) {
state = (curve > 0) ? EXPLORATION_STATE_TURN_PARALLEL_LEFT : EXPLORATION_STATE_TURN_PARALLEL_RIGHT;
running_curve = False;
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
deactivateBehaviour(bot_avoid_col_behaviour);
#endif
} else {
bot_drive(curve, BOT_SPEED_MAX);
}
break;
default:
state = EXPLORATION_STATE_GOTO_WALL;
curve = 0;
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
activateBehaviour(bot_avoid_col_behaviour);
#endif
}
}
/*!
* Aktiviert bot_explore_behaviour. */
void bot_explore(Behaviour_t *caller, int8 (*check)(void)){
exploration_check_function = check;
switch_to_behaviour(caller,bot_explore_behaviour,NOOVERRIDE);
}
/*!
* Das Verhalten laesst den Bot einen Slalom fahren.
* @see bot_do_slalom()
* */
void bot_do_slalom_behaviour(Behaviour_t *data){
static int8 state = SLALOM_STATE_CHECK_PILLAR;
static int8 orientation = SLALOM_ORIENTATION_RIGHT;
static int8 sweep_state;
static int8 sweep_steps = 0;
int16 turn;
int8 curve;
switch(state){
case SLALOM_STATE_CHECK_PILLAR:
// Der Bot sollte jetzt Licht sehen koennen...
if(check_for_light()){
// Wenn der Bot direkt vor der Saeule steht, kann der Slalom anfangen, sonst zum Licht fahren
if(bot_avoid_harm()){
state = SLALOM_STATE_START;
} else bot_goto_light();
} else {// ... sonst muss er den Slalom-Kurs neu suchen.
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
activateBehaviour(bot_avoid_col_behaviour);
#endif
return_from_behaviour(data);
}
break;
case SLALOM_STATE_START:
// Hier ist Platz fuer weitere Vorbereitungen, falls noetig.
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
deactivateBehaviour(bot_avoid_col_behaviour);
#endif
state = SLALOM_STATE_TURN_1;
// break;
case SLALOM_STATE_TURN_1:
turn = (orientation == SLALOM_ORIENTATION_LEFT) ? 90 : -90;
bot_turn(data,turn);
state = SLALOM_STATE_DRIVE_ARC;
break;
case SLALOM_STATE_DRIVE_ARC:
// Nicht wundern: Bei einem Links-Slalom faehrt der Bot eine Rechtskurve.
curve = (orientation == SLALOM_ORIENTATION_LEFT) ? 25 : -25;
bot_drive_distance(data,curve,BOT_SPEED_FAST,20);
state = SLALOM_STATE_TURN_2;
break;
case SLALOM_STATE_TURN_2:
turn = (orientation == SLALOM_ORIENTATION_LEFT) ? 45 : -45;
bot_turn(data,turn);
state = SLALOM_STATE_SWEEP_RUNNING;
break;
case SLALOM_STATE_SWEEP_RUNNING:
if(sweep_steps == 0){
sweep_state = SWEEP_STATE_CHECK;
}
// Insgesamt 6 Schritte drehen
if(sweep_steps < 6) {
if(sweep_state == SWEEP_STATE_CHECK){
// Phase 1: Pruefen, ob vor dem Bot eine gute Saeule ist
if(is_good_pillar_ahead() == True){
// Wenn die Saeule gut ist, drauf zu und Slalom anders rum fahren.
state = SLALOM_STATE_CHECK_PILLAR;
orientation = (orientation == SLALOM_ORIENTATION_LEFT) ? SLALOM_ORIENTATION_RIGHT : SLALOM_ORIENTATION_LEFT;
sweep_steps = 0;
} else {
// Sonst drehen.
sweep_state = SWEEP_STATE_TURN;
}
}
if(sweep_state == SWEEP_STATE_TURN) {
// Phase 2: Bot um 15 Grad drehen
turn = (orientation == SLALOM_ORIENTATION_LEFT) ? 15 : -15;
bot_turn(data,turn);
sweep_state = SWEEP_STATE_CHECK;
sweep_steps++;
}
} else {
turn = (orientation == SLALOM_ORIENTATION_LEFT) ? -90 : 90;
bot_turn(data,turn);
state = SLALOM_STATE_SWEEP_DONE;
sweep_steps = 0;
}
break;
case SLALOM_STATE_SWEEP_DONE:
turn = (orientation == SLALOM_ORIENTATION_LEFT) ? -135 : 135;
bot_turn(data,turn);
state = SLALOM_STATE_CHECK_PILLAR;
break;
default:
state = SLALOM_STATE_CHECK_PILLAR;
}
}
/*!
* Das Verhalten laesst den Bot zwischen einer Reihe beleuchteter Saeulen Slalom fahren.
* Das Verhalten ist wie bot_explore() in eine Anzahl von Teilschritten unterteilt.
* 1. Vor die aktuelle Saeule stellen, so dass sie zentral vor dem Bot und ungefaehr
* COL_CLOSEST (100 mm) entfernt ist.
* 2. 90 Grad nach rechts drehen.
* 3. In einem relativ engen Bogen 20 cm weit fahren.
* 4. Auf der rechten Seite des Bot nach einem Objekt suchen, dass
* a) im rechten Sektor des Bot liegt, also zwischen -45 Grad und -135 Grad zur Fahrtrichtung liegt,
* b) beleuchtet und
* c) nicht zu weit entfernt ist.
* Wenn es dieses Objekt gibt, wird es zur aktuellen Saeule und der Bot faehrt jetzt Slalom links.
* 5. Sonst zurueck drehen, 90 Grad drehen und Slalom rechts fahren.
* In diesem Schritt kann der Bot das Verhalten auch abbrechen, falls er gar kein Objekt mehr findet.
*/
void bot_do_slalom(Behaviour_t *caller){
switch_to_behaviour(caller, bot_do_slalom_behaviour,NOOVERRIDE);
}
/*!
* Das Verhalten setzt sich aus 3 Teilverhalten zusammen:
* Nach Licht suchen, auf das Licht zufahren, im Licht Slalom fahren. */
void bot_olympic_behaviour(Behaviour_t *data){
if(check_for_light()){
/* Sobald der Bot auf ein Objekt-Hinderniss stoesst, versucht er, Slalom zu fahren.
* Aufgabe: Wenn der Bot vor einem Loch steht, hinter welchem sich die Lichtquelle
* befindet, wird er daran haengen bleiben. Schreibe ein Verhalten, dass das verhindert. */
if(bot_avoid_harm() && is_obstacle_ahead(COL_NEAR)){
bot_do_slalom(data);
} else bot_goto_light();
} else bot_explore(data,check_for_light);
}
/*!
* Initialisiert das Olympische Verhalten
* @param prio_main Prioritaet des Olympischen Verhalten (typ. 100)
* @param prio_helper Prioritaet der Hilfsfunktionen (typ. 52)
* @param active ACTIVE wenn es sofort starten soll, sonst INACTIVE
*/
void bot_olympic_init(int8 prio_main,int8 prio_helper, int8 active){
// unwichtigere Hilfsverhalten
insert_behaviour_to_list(&behaviour, new_behaviour(prio_helper--, bot_explore_behaviour,INACTIVE));
insert_behaviour_to_list(&behaviour, new_behaviour( prio_helper, bot_do_slalom_behaviour,INACTIVE));
// Demo-Verhalten fuer aufwendiges System, inaktiv
insert_behaviour_to_list(&behaviour, new_behaviour(prio_main, bot_olympic_behaviour, active));
}
#endif

View file

@ -0,0 +1,407 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_remotecall_behaviour.c
* @brief ruft auf ein Kommando hin andere Verhalten auf und bestaetigt dann ihre Ausfuehrung
*
* @author Benjamin Benz (bbe@heise.de)
* @date 07.12.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_REMOTECALL_AVAILABLE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "log.h"
#include "command.h"
#include "bot-logic/remote_calls.h"
#define REMOTE_CALL_IDLE 0
#define REMOTE_CALL_SCHEDULED 1
#define REMOTE_CALL_RUNNING 2
/*! Uebergabevariable fuer Remotecall-Verhalten */
static uint8 running_behaviour =REMOTE_CALL_IDLE;
static uint8 function_id = 255;
static uint8 parameter_count = 0; /*!< Anzahl der Paramter (ohne Zeiger auf Aufrufer) */
static uint8 parameter_data[8] = {0}; /*!< Hier liegen die eigentlichen Parameter, derzeit brauchen wir maximal 8 Byte (2 floats, 4 (u)int16 oder 4 (u)int8 */
#ifdef MCU
static uint8 parameter_length[REMOTE_CALL_MAX_PARAM] = {0}; /*!< Hier speichern wir die Laenge der jeweiligen Parameter */
#else
static uint8* parameter_length = NULL; /*!< Hier speichern wir die Laenge der jeweiligen Parameter */
#endif
#ifdef MCU
#include <avr/pgmspace.h>
#else
#define PROGMEM // Alibideklaration hat keine Funktion, verhindert aber eine Warning
#define strcmp_P strcmp // Auf dem PC gibt es keinen Flash, also auch kein eigenes Compare
#endif
/*!
* Hier muessen alle Boten-Funktionen rein, die Remote aufgerufen werden sollen
* Diese stoßen dann das zugehoerige Verhalten an
* Ein Eintrag erfolgt so:
* PREPARE_REMOTE_CALL(BOTENFUNKTION,NUMBER_OF_PARAMS, STRING DER DIE PARAMETER BESCHREIBT,laenge der jeweiligen Parameter in Byte)
*
* Alle Botenfunktionen muessen folgendem Schema entsprechen
* void bot_xxx(Behaviour_t * caller, ...);
*
* Erklaerung am Bsp:
* PREPARE_REMOTE_CALL(bot_gotoxy, 2, "float x, float y", 4, 4),
* Name der Botenfunktion --^ ^ ^ ^ ^
* Anzahl der Parameter --------- | | |
* Beschreibung der Parameter -------- | |
* Anzahl der Bytes Parameter 1 ------------------------ |
* Anzahl der Bytes Parameter 2 ---------------------------
*
* Zur Info:
* 1 Byte brauchen: uint8, int8,char
* 2 Byte brauchen: uint16, int16
* 4 Byte brauchen: uint32, int32, float
*/
const call_t calls[] PROGMEM = {
#ifdef BEHAVIOUR_DRIVE_DISTANCE_AVAILABLE
PREPARE_REMOTE_CALL(bot_drive_distance,3, "int8 curve, int16 speed, int16 cm", 1,2,2),
#endif
#ifdef BEHAVIOUR_GOTOXY_AVAILABLE
PREPARE_REMOTE_CALL(bot_gotoxy, 2, "float x, float y", 4, 4),
#endif
#ifdef BEHAVIOUR_SOLVE_MAZE_AVAILABLE
PREPARE_REMOTE_CALL(bot_solve_maze,0,""),
#endif
#ifdef BEHAVIOUR_CATCH_PILLAR_AVAILABLE
PREPARE_REMOTE_CALL(bot_catch_pillar,0,""),
#endif
#ifdef BEHAVIOUR_DRIVE_SQUARE_AVAILABLE
PREPARE_REMOTE_CALL(bot_drive_square,0,""),
#endif
#ifdef BEHAVIOUR_FOLLOW_LINE_AVAILABLE
PREPARE_REMOTE_CALL(bot_follow_line,0,""),
#endif
#ifdef BEHAVIOUR_GOTO_AVAILABLE
PREPARE_REMOTE_CALL(bot_goto,2," int16 left, int16 right",2,2),
#endif
#ifdef BEHAVIOUR_OLYMPIC_AVAILABLE
PREPARE_REMOTE_CALL(bot_do_slalom,0,""),
#endif
#ifdef BEHAVIOUR_SCAN_AVAILABLE
PREPARE_REMOTE_CALL(bot_scan,0,""),
#endif
#ifdef BEHAVIOUR_SERVO_AVAILABLE
PREPARE_REMOTE_CALL(bot_servo,2,"uint8 servo, uint8 pos",1,1),
#endif
#ifdef BEHAVIOUR_SIMPLE_AVAILABLE
PREPARE_REMOTE_CALL(bot_simple,0,""),
PREPARE_REMOTE_CALL(bot_simple2,1,"int16 light",2),
#endif
#ifdef BEHAVIOUR_TURN_AVAILABLE
PREPARE_REMOTE_CALL(bot_turn,1,"int16 degrees",2)
#endif
};
#define STORED_CALLS (sizeof(calls)/sizeof(call_t)) /*!< Anzahl der Remote calls im Array */
/*!
* Sucht den Index des Remote-Calls heraus
* @param call String mit dem namen der gesuchten fkt
* @return Index in das calls-Array. Wenn nicht gefunden, dann 255
*/
uint8 getRemoteCall(char * call){
// LOG_DEBUG(("Suche nach Funktion: %s",call));
uint8 i;
for (i=0; i< (STORED_CALLS); i++){
if (!strcmp_P (call, calls[i].name)){
LOG_DEBUG(("calls[%d].name=%s passt",i,call));
return i;
}
}
return 255;
}
#ifdef MCU
/*!
* Hilfsfunktion fuer bot_remotecall()
* Baut einen AVR-kompatiblen Parameterstream aus einem uint32-Parameterarray und einem Infoarray ueber die Parameter
* @param dest Zeiger auf das Ausgabearray (len[0]*2 Byte gross!)
* @param count Anzahl der Parameter
* @param len Zeiger auf ein Array, das die Anzahl der Bytes fuer die jeweiligen Parameter enthaelt
* @param data Zeiger auf die Daten (32 Bit, Laenge 8)
* @author Timo Sandmann (mail@timosandmann.de)
* @date 12.01.2007
*/
void remotecall_convert_params(uint8* dest, uint8 count, uint8* len, uint8* data){
uint8 i;
/* jeden Parameter behandeln */
for (i=0; i<count; i++){
int8 j;
if (len[i] == 1) *dest++ = 0; // auch (u)int8 beginnen immer in geraden Registern
/* pro Parameter LSB zuerst nach dest kopieren */
for (j=len[i]-1; j>=0; j--)
*dest++ = data[j];
data += 4; // data-Array ist immer in 32 Bit
}
}
#endif // MCU
/*!
* Dieses Verhalten kuemmert sich darum die Verhalten, die von aussen angefragt wurden zu starten und liefert ein feedback zurueck, wenn sie beendet sind.
* @param *data der Verhaltensdatensatz
*/
void bot_remotecall_behaviour(Behaviour_t *data){
uint8 call_id =255;
// LOG_DEBUG(("Enter bot_remotecall_behaviour"));
void (* func) (struct _Behaviour_t *data);
switch (running_behaviour) {
case REMOTE_CALL_SCHEDULED: // Es laueft kein Auftrag, aber es steht ein neuer an
// LOG_DEBUG(("REMOTE_CALL_SCHEDULED"));
call_id=function_id;
if (call_id >= STORED_CALLS){
// LOG_DEBUG(("keine Funktion gefunden. Exit"));
running_behaviour=REMOTE_CALL_IDLE;
return;
}
#ifdef PC
// Auf dem PC liegt die calls-Struktur im RAM
func = (void*) calls[call_id].func;
#else
// Auf dem MCU liegt die calls-Struktur im Flash und muss erst geholt werden
func = (void*) pgm_read_word (& calls[call_id].func);
#endif
if (parameter_count ==0 ){ // Kommen wir ohne Parameter aus?
// LOG_DEBUG(("call_id=%u",call_id));
func(data); // Die aufgerufene Botenfunktion starten
running_behaviour=REMOTE_CALL_RUNNING;
} else if (parameter_count <= REMOTE_CALL_MAX_PARAM){ // Es gibt gueltige Parameter
// TODO: Ja hier wird es spannend, denn jetzt muessen die Parameter auf den Stack
LOG_DEBUG(("call_id=%u",call_id));
LOG_DEBUG(("parameter_count=%u", parameter_count));
// asm-hacks here ;)
#ifdef PC
/* Prinzip auf dem PC: Wir legen alle Parameter einzeln auf den Stack, springen in die Botenfunktion und raeumen anschliessend den Stack wieder auf */
uint32 tmp;
uint8 i;
volatile uint8 td=1; // verwenden wir nur, damit der Compiler unsere inline-asm-Bloecke nicht umordnet
for (i=0; i<parameter_count*4 && td>0; i+=4,td++){ // Debug-Info ausgeben
// LOG_DEBUG(("parameter_data[%u-%u] = %lu",i, i+3, *(uint32*)(parameter_data+i)));
}
/* Erster Wert in parameter_length ist die Anzahl der Parameter (ohne Zeiger des Aufrufers) */
for (i=0; i<parameter_count && td>1; i++,td++){ // Check von td eigentlich sinnlos, aber wir brauchen eine echte Datenabhaengigkeit auf dieses Codestueck
/* cdecl-Aufrufkonvention => Parameter von rechts nach links auf den Stack */
tmp = *(uint32*)(parameter_data+(parameter_count-i-1)*4);
/* Parameter 2 bis n pushen */
asm volatile( // IA32-Support only
"pushl %0 # parameter i auf stack "
:: "g" (tmp)
: "memory"
);
}
/* Parameter 1 (data) und Funktionsaufruf */
asm volatile(
"pushl %0 # push data \n\t"
"movl %1, %%eax # adresse laden \n\t"
"call *%%eax # jump to callee \n\t"
:: "m" (data), "m" (func)
: "eax", "memory"
);
/* caller rauemt den Stack wieder auf */
for (i=0; i<=parameter_count && td>2; i++){ // Check von td erzwingt, dass das Aufraeumen erst jetzt passiert
asm volatile(
"pop %%eax # stack aufraeumen "
::: "eax", "memory"
);
}
#else
/* Prinzip auf der MCU: Keine komplizierten Rechnungen, sondern einfach alle Register ueberschreiben.
* Achtung: Derzeit braucht kein Verhalten mehr als 8 Register (2*float oder 4*int16 oder 4*int8), aendert sich das,
* muss man den Code hier erweitern!
* Die AVR-Konvention beim Funktionsaufruf:
* Die Groesse in Byte wird zur naechsten geraden Zahl aufgerundet, falls sie ungerade ist.
* Der Registerort faengt mit 26 an.
* Vom Registerort wird die berechete Groesse abgezogen und das Argument in diesen Registern uebergeben (LSB first).
* In r24/r25 legt der Compiler spaeter den Zeiger des Aufrufers, koennen wir hier also weglassen. */
// LOG_DEBUG(("r22:r23 = %u:%u", parameter_data[1], parameter_data[0]));
// LOG_DEBUG(("r21:r20 = %u:%u", parameter_data[3], parameter_data[2]));
// LOG_DEBUG(("r18:r19 = %u:%u", parameter_data[5], parameter_data[4]));
// LOG_DEBUG(("r16:r17 = %u:%u", parameter_data[7], parameter_data[6]));
asm volatile( // remotecall_convert_params() hat den Speicher bereits richtig sortiert, nur noch Werte laden
"ld r23, Z+ \n\t"
"ld r22, Z+ \n\t"
"ld r21, Z+ \n\t"
"ld r20, Z+ \n\t"
"ld r19, Z+ \n\t"
"ld r18, Z+ \n\t"
"ld r17, Z+ \n\t"
"ld r16, Z "
:: "z" (parameter_data)
: "r23", "r22", "r21", "r20", "r19", "r18", "r17", "r16"
);
func(data); // Die aufgerufene Botenfunktion starten
#endif
running_behaviour=REMOTE_CALL_RUNNING;
return;
} else {
// LOG_DEBUG(("Parameteranzahl unzulaessig!"));
}
break;
case REMOTE_CALL_RUNNING: // Es lief ein Verhalten und ist nun zuende (sonst waeren wir nicht hier)
{
// Antwort schicken
char * function_name;
#ifdef PC
function_name=(char*) &calls[function_id].name;
#else
// Auf dem MCU muessen wir die Daten erstmal aus dem Flash holen
char tmp[REMOTE_CALL_FUNCTION_NAME_LEN+1];
function_name=(char*)&tmp;
uint8* from= (uint8*)& calls[function_id].name;
uint8 i;
for (i=0; i<REMOTE_CALL_FUNCTION_NAME_LEN+1; i++)
*function_name++ = (uint8) pgm_read_byte ( from++ );
function_name=(char*)&tmp;
#endif
#ifdef COMMAND_AVAILABLE
int16 result = data->subResult;
command_write_data(CMD_REMOTE_CALL,SUB_REMOTE_CALL_DONE,&result,&result,function_name);
#endif
// LOG_DEBUG(("Remote-call %s beendet",function_name));
// Aufrauemen
function_id=255;
//parameter_length=NULL;
//parameter_data=NULL;
running_behaviour=REMOTE_CALL_IDLE;
return_from_behaviour(data); // und Verhalten auch aus
break;
}
default:
return_from_behaviour(data); // und Verhalten auch aus
break;
}
}
/*!
* Fuehre einen remote_call aus. Es gibt KEIN aufrufendes Verhalten!!
* @param func Zeiger auf den Namen der Fkt
* @param data Zeiger auf die Daten
*/
void bot_remotecall(char* func, remote_call_data_t* data){
function_id= getRemoteCall(func);
if (function_id >= STORED_CALLS){
// LOG_DEBUG(("Funktion %s nicht gefunden. Exit!",func));
return;
}
// parameter_length: Zeiger auf ein Array, das zuerst die Anzahl der Parameter und danach die Anzahl der Bytes fuer die jeweiligen Parameter enthaelt
#ifdef PC
parameter_count = calls[function_id].param_count;
parameter_length = (uint8*)calls[function_id].param_len;
#else
// Auf dem MCU muessen wir die Daten erstmal aus dem Flash holen
uint8* from= (uint8*)& calls[function_id].param_len;
uint8 i;
parameter_count = pgm_read_byte(&calls[function_id].param_count);
for (i=0; i<REMOTE_CALL_MAX_PARAM; i++)
parameter_length[i] = (uint8) pgm_read_byte ( from++ );
#endif
// LOG_DEBUG(("func=%s param_count=%d Len= %u %u %u %u",func,parameter_count,parameter_length[0],parameter_length[1],parameter_length[2]));
// if (data != NULL){
// LOG_DEBUG(("data= %u %u %u %u",data[0],data[1],data[2],data[3]));
// }
#ifdef MCU // Die MCU legt die Parameter nach einem anderen Verfahren ab, diese Funktion konvertiert sie deshalb
remotecall_convert_params(parameter_data, parameter_count, parameter_length, (uint8*)data);
#else // Auf dem PC kopieren wir die Daten einfach
memcpy(parameter_data, data, parameter_count*4);
#endif
running_behaviour=REMOTE_CALL_SCHEDULED;
activateBehaviour(bot_remotecall_behaviour);
}
/*!
* Fuehre einen remote_call aus. Es gibt KEIN aufrufendes Verhalten!!
* @param data Zeiger die Payload eines Kommandos. Dort muss zuerst ein String mit dem Fkt-Namen stehen. ihm folgen die Nutzdaten
*/
void bot_remotecall_from_command(uint8 * data){
char * function_name = (char*)data;
remote_call_data_t * params = (remote_call_data_t *)(data+ strlen(function_name)+1);
bot_remotecall(function_name,params);
}
/*!
* Listet alle verfuegbaren Remote-Calls auf und verschickt sie als einzelne Kommanods
*/
void remote_call_list(void){
#ifdef MCU
call_t call_storage;
uint8* to;
uint8* from;
#endif
call_t* call;
int16 i;
for (i=0; i< (STORED_CALLS); i++){
#ifdef MCU
// Auf dem MCU muessen die Daten erstmal aus dem Flash ins RAM
from= (uint8*)&calls[i];
to= (uint8*)&call_storage;
uint8 j;
for (j=0; j< sizeof(call_t); j++){
*to = (uint8) pgm_read_byte ( from++ );
to++;
}
call = &call_storage;
#else
call = (call_t*)&calls[i];
#endif
#ifdef COMMAND_AVAILABLE
// und uebertragen
command_write_rawdata(CMD_REMOTE_CALL,SUB_REMOTE_CALL_ENTRY,&i,&i, sizeof(call_t),(uint8*)call);
#endif
// LOG_DEBUG(("%s(%s)",call->name,call->param_info));
}
}
#endif

View file

@ -0,0 +1,144 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_scan.c
* @brief Scannt die Umgebung und traegt sie in die Karte ein
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#include "map.h"
#include <math.h>
#ifdef BEHAVIOUR_SCAN_AVAILABLE
/*!
* Der Roboter faehrt einen Vollkreis und scannt dabei die Umgebung
* @param *data der Verhaltensdatensatz
*/
void bot_scan_onthefly_behaviour(Behaviour_t *data){
#define ONTHEFLY_DIST_RESOLUTION 0.02 /*!< Alle wieviel gefahrene Strecke [m] soll die Karte aktualisiert werden. Achtung er prueft x und y getrennt, daher ist die tatsaechlich zurueckgelegte Strecke im worst case sqrt(2)*ONTHEFLY_DIST_RESOLUTION */
#define ONTHEFLY_ANGLE_RESOLUTION 10 /*!< Alle wieviel Gerad Drehung [m] soll die Karte aktualisiert werden */
#ifdef MAP_AVAILABLE
static float last_x, last_y, last_head;
float diff_x = fabs(x_pos-last_x);
float diff_y = fabs(y_pos-last_y);
// Wenn der Bot faehrt, aktualisieren wir alles
if ((diff_x > ONTHEFLY_DIST_RESOLUTION) ||( diff_y > ONTHEFLY_DIST_RESOLUTION)){
update_map_location(x_pos,y_pos);
update_map(x_pos,y_pos,heading,sensDistL,sensDistR);
last_x=x_pos;
last_y=y_pos;
last_head=heading;
return;
}
float diff_head = fabs(last_head-heading);
// Wenn der bot nur dreht, aktualisieren wir nur die Blickstrahlen
if ( diff_head > ONTHEFLY_ANGLE_RESOLUTION ){
update_map(x_pos,y_pos,heading,sensDistL,sensDistR);
last_head=heading;
}
/* if ((diff_x*diff_x + diff_y*diff_y > ONTHEFLY_DIST_RESOLUTION)||fabs(last_head-heading) > ONTHEFLY_ANGLE_RESOLUTION ){
last_x=x_pos;
last_y=y_pos;
last_head=heading;
print_map();
}
*/
#endif
}
#define BOT_SCAN_STATE_START 0
uint8 bot_scan_state = BOT_SCAN_STATE_START; /*!< Zustandsvariable fuer bot_scan_behaviour */
/*!
* Der Roboter faehrt einen Vollkreis und scannt dabei die Umgebung
* @param *data der Verhaltensdatensatz
*/
void bot_scan_behaviour(Behaviour_t *data){
#define BOT_SCAN_STATE_SCAN 1
#define ANGLE_RESOLUTION 5 /*!< Aufloesung fuer den Scan in Grad */
// static uint16 bot_scan_start_angle; /*!< Winkel, bei dem mit dem Scan begonnen wurde */
static float turned; /*!< Winkel um den bereits gedreht wurde */
static float last_scan_angle; /*!< Winkel bei dem zuletzt gescannt wurde */
float diff;
switch (bot_scan_state){
case BOT_SCAN_STATE_START:
turned=0;
last_scan_angle=heading-ANGLE_RESOLUTION;
bot_scan_state=BOT_SCAN_STATE_SCAN;
break;
case BOT_SCAN_STATE_SCAN:
diff = heading - last_scan_angle;
if (diff < -180)
diff+=360;
if (diff*1.15 >= ANGLE_RESOLUTION){
turned+= diff;
last_scan_angle=heading;
#ifdef MAP_AVAILABLE
// Eigentlicher Scan hier
update_map(x_pos,y_pos,heading,sensDistL,sensDistR);
////////////
#endif
}
if (turned >= 360-ANGLE_RESOLUTION) // Ende erreicht
bot_scan_state++;
break;
default:
bot_scan_state = BOT_SCAN_STATE_START;
#ifdef MAP_AVAILABLE
print_map();
#endif
return_from_behaviour(data);
break;
}
}
/*!
* Der Roboter faehrt einen Vollkreis und scannt dabei die Umgebung
* @param Der aufrufer
*/
void bot_scan(Behaviour_t* caller){
bot_scan_state = BOT_SCAN_STATE_START;
bot_turn(caller,360);
switch_to_behaviour(0, bot_scan_behaviour,OVERRIDE);
// update_map(x_pos,y_pos,heading,sensDistL,sensDistR);
// print_map();
}
#endif

View file

@ -0,0 +1,68 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_servo.c
* @brief kontrolliert die Servos
*
* @author Benjamin Benz (bbe@heise.de)
* @date 07.12.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_SERVO_AVAILABLE
#include "motor.h"
#include "timer.h"
/*! Uebergabevariable fuer Servo-Verhalten */
static uint16 servo_time;
static uint8 servo_nr;
static uint8 servo_pos;
uint8 servo_active = 0; /*!< 0, wenn kein Servo aktiv, sonst Bit der gerade aktiven Servos gesetzt */
/*!
* Dieses Verhalten fuehrt ein Servo-Kommando aus und schaltet danach den Servo wieder ab
*
* @param *data der Verhaltensdatensatz
*/
void bot_servo_behaviour(Behaviour_t *data){
/* Servo ausschalten, falls Klappe zu oder Countdown abgelaufen */
if ( (servo_pos == DOOR_CLOSE && sensDoor == 0) || (TIMER_GET_TICKCOUNT_16 - servo_time > MS_TO_TICKS(1000L)) ){
servo_set(servo_nr, SERVO_OFF); // Servo aus
servo_active &= ~servo_nr;
return_from_behaviour(data); // und Verhalten auch aus
}
}
/*!
* Fahre den Servo an eine Position
* @param servo Nummer des Servos
* @param pos Zielposition des Servos
*/
void bot_servo(Behaviour_t * caller, uint8 servo, uint8 pos){
servo_active |= servo;
servo_set(servo, pos); // Servo-PWM einstellen
servo_pos = pos; // Zielposition merken
servo_nr = servo; // Servo-Nr speichern
servo_time = TIMER_GET_TICKCOUNT_16; // Der Count down verschafft dem Servo etwas Zeit
switch_to_behaviour(caller,bot_servo_behaviour,OVERRIDE); // Warte-Verahlten an
}
#endif

View file

@ -0,0 +1,139 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_simple.c
* @brief ganz einfache Beispielverhalten
* Diese Datei sollte der Einstiegspunkt fuer eigene Experimente sein,
* den Roboter zu steuern.
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_SIMPLE_AVAILABLE
/*!
* Ein ganz einfaches Verhalten, es hat maximale Prioritaet
* Hier kann man auf ganz einfache Weise die ersten Schritte wagen.
* Wer die Moeglichkeiten des ganzen Verhaltensframeworks ausschoepfen will, kann diese Funktion getrost auskommentieren
* und findet dann in bot_behave_init() und bot_behave() weitere Hinweise fuer elegante Bot-Programmierung....
*
* Das Verhalten ist per default abgeschaltet. Daher muss man es erst in bot_behave_init() aktivieren.
* Dort steht aber bereits eine auskommentierte Zeile dazu, von der man nur die zwei Kommentarzeichen wegnehmen muss.
* Achtung, da bot_simple_behaviour() maximale Prioritaet hat, kommt es vor den anderen Regeln, wie dem Schutz vor Abgruenden, etc. zum Zuge
* Das sollte am Anfang nicht stoeren, spaeter sollte man jedoch die Prioritaet herabsetzen.
*
* @param *data der Verhaltensdatensatz
*/
void bot_simple_behaviour(Behaviour_t *data){
static uint8 state=0;
switch (state){
case 0:
bot_drive_distance(data ,0 , BOT_SPEED_MAX, 14);
state++;
break;
case 1:
bot_turn(data , 90);
state=0;
break;
default:
state=0;
return_from_behaviour(data);
break;
}
}
/*!
* Rufe das Simple-Verhalten auf
* @param caller Der obligatorische Verhaltensdatensatz des Aufrufers
*/
void bot_simple(Behaviour_t * caller, int16 light){
switch_to_behaviour(caller,bot_simple_behaviour,OVERRIDE);
}
/*! Uebergabevariable fuer SIMPLE2 */
static int16 simple2_light=0;
/*!
* Ein ganz einfaches Beispiel fuer ein Hilfsverhalten,
* das selbst SpeedWishes aussert und
* nach getaner Arbeit die aufrufende Funktion wieder aktiviert
* Zudem prueft es, ob eine Uebergabebedingung erfuellt ist.
*
* Zu diesem Verhalten gehoert die Botenfunktion bot_simple2()
*
* Hier kann man auf ganz einfache Weise die ersten Schritte wagen.
* Wer die Moeglichkeiten des ganzen Verhaltensframeworks ausschoepfen will, kann diese Funktion getrost auskommentieren
* und findet dann in bot_behave_init() und bot_behave() weitere Hinweise fuer elegante Bot-Programmierung....
*
* Das Verhalten ist per default abgeschaltet. Daher muss man es erst in bot_behave_init() aktivieren.
* Dort steht aber bereits eine auskommentierte Zeile dazu, von der man nur die zwei Kommentarzeichen wegnehmen muss.
* Achtung, da bot_simple2_behaviour() maximale Prioritaet hat, kommt es vor den anderen Regeln, wie dem Schutz vor Abgruenden, etc. zum Zuge
* Das sollte am Anfang nicht stoeren, spaeter sollte man jedoch die Prioritaet herabsetzen.
*
* bot_simple2_behaviour faehrt den Bot solange geradeaus, bis es dunkler als im Uebergabeparameter spezifiziert ist wird
*
* @param *data der Verhaltensdatensatz
*/
void bot_simple2_behaviour(Behaviour_t *data){
#define STATE_SIMPLE2_INIT 0
#define STATE_SIMPLE2_WORK 1
#define STATE_SIMPLE2_DONE 2
static uint8 state = 0;
switch (state) {
case STATE_SIMPLE2_INIT:
// Nichts zu tun
state=STATE_SIMPLE2_WORK;
break;
case STATE_SIMPLE2_WORK:
// Fahre ganz schnell
speedWishLeft = BOT_SPEED_FAST;
speedWishRight = BOT_SPEED_FAST;
if (sensLDRL< simple2_light) // Beispielbedingung
// Wenn es dunkler als angegeben wird, dann haben wir unserd Ziel erreicht
state=STATE_SIMPLE2_DONE;
break;
case STATE_SIMPLE2_DONE: /* Sind wir fertig, dann Kontrolle zurueck an Aufrufer */
state=STATE_SIMPLE2_INIT;
return_from_behaviour(data);
break;
}
}
/*!
* Rufe das Simple2-Verhalten auf und uebergebe light
* @param caller Der obligatorische Verhaltensdatensatz des Aufrufers
* @param light Uebergabeparameter
*/
void bot_simple2(Behaviour_t * caller, int16 light){
simple2_light=light;
// Zielwerte speichern
switch_to_behaviour(caller,bot_simple2_behaviour,OVERRIDE);
}
#endif

View file

@ -0,0 +1,660 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_solve_maze.c
* @brief Wandfolger durchs Labyrinth
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#include <math.h>
#include <stdlib.h>
#include "log.h"
#ifdef BEHAVIOUR_SOLVE_MAZE_AVAILABLE
/* Parameter fuer das check_wall_behaviour() */
int8 wall_detected; /*!< enthaelt True oder False, je nach Ergebnis des Verhaltens */
int8 check_direction; /*!< enthaelt CHECK_WALL_LEFT oder CHECK_WALL_RIGHT */
int16 wall_distance; /*!< enthaelt gemessene Entfernung */
/* Konstanten fuer check_wall_behaviour-Verhalten */
#define CHECK_WALL_RIGHT 0
#define CHECK_WALL_LEFT 1
/* Parameter fuer das measure_angle_behaviour() */
int8 measure_direction; /*!< enthaelt MEASURE_RIGHT oder MEASURE_LEFT */
int16 measure_distance; /*!< enthaelt maximale Messentfernung, enthaelt nach der Messung die Entfernung */
int16 measured_angle; /*!< enthaelt gedrehten Winkel oder 0, falls nichts entdeckt */
#ifdef MEASURE_MOUSE_AVAILABLE
int16 start_heading; /*!< Blickwinkel des Bots zu Beginn der Messung */
#else
int16 startEncL; /*!< enthaelt Encoderstand zu Beginn der Messung */
int16 startEncR; /*!< enthaelt Encoderstand zu Beginn der Messung */
#endif
/* Konstanten fuer measure_angle_behaviour-Verhalten */
#define MEASURE_LEFT 1
#define MEASURE_RIGHT -1
/*!
* Das Verhalten dreht sich um 45 Grad in die angegebene Richtung (0=rechts, 1=links)
* und prueft, ob auf dem Sensor auf der Seite der angegebenen Richtung eine Wand
* im Abstand von 12cm zu sehen ist. Wenn dem so ist, wird die Variable wall_present
* auf True gesetzt, sonst False */
void bot_check_wall_behaviour(Behaviour_t *data) {
/* Konstantenfuer check_wall_behaviour-Verhalten */
#define CORRECT_NEAR 0
#define CORRECT_NONE 1
#define CORRECT_FAR 2
/* Zustaende fuer check_wall_behaviour-Verhalten */
#define CHECK_WALL_TURN 0
#define CHECK_WALL_SENS 1
#define CHECK_WALL_TURN_BACK 2
#define CHECK_WALL_FINISHED 3
#define CHECK_WALL_CORRECT 4
static int8 checkState=CHECK_WALL_TURN;
/* wenn die Wand noch da ist aber aus dem Blickfeld rueckt, Entfernung und Winkel korrigieren */
static int8 correctDistance=CORRECT_NONE;
/* letzte, gueltige Distanz fuer Abweichungsberechnung */
static int16 lastDistance=0;
/* enthaelt anzahl der +/-5 identischen Messungen */
static int8 measureCount=0;
/* letzter Messwert */
static int16 lastSensor=0;
int16 sensor; /* fuer temporaer benutzte Senorwerte */
switch(checkState) {
case CHECK_WALL_TURN:
/* haben wir links oder rechts eine Wand? */
if (check_direction==CHECK_WALL_LEFT) {
checkState=CHECK_WALL_SENS;
bot_turn(data,45);
break;
} else {
checkState=CHECK_WALL_SENS;
bot_turn(data,-45);
break;
}
case CHECK_WALL_SENS:
if (check_direction==CHECK_WALL_LEFT) {
sensor=sensDistL;
} else {
sensor=sensDistR;
}
/* dafuer sorgen, dass wir nur verlaessliche Werte haben
* dazu muss der wert dreimal nacheinander max. um +/- 5
* unterschiedlich sein */
if (measureCount==0) {
lastSensor=sensor;
measureCount++;
break;
}
if (sensor>=lastSensor-5 && sensor<=lastSensor+5 && measureCount<4) {
/* Messwert ist ok */
measureCount++;
break;
} else if (measureCount<4) {
/* Messwert weicht zu doll ab -> von Neuem messen */
measureCount=0;
break;
}
/* ok, wir hatten drei Messungen mit nahezu identischen Werten */
/* keine wand in eingestellter Maximalentfernung? */
if (sensor>IGNORE_DISTANCE) {
correctDistance=CORRECT_NONE; /* dann auch keine Korrektur */
lastDistance=0; /* auch kein Vergleichswert */
wall_detected=False; /* keine Wand da */
} else if (sensor<OPTIMAL_DISTANCE-ADJUST_DISTANCE) {
/* bot hat den falschen Abstand zur Wand, zu nah dran */
wall_detected=True;
correctDistance=CORRECT_NEAR;
} else if (sensor>OPTIMAL_DISTANCE+ADJUST_DISTANCE) {
/* bot hat den falschen Abstand zur Wand, zu weit weg */
wall_detected=True;
correctDistance=CORRECT_FAR;
} else {
/* perfekter Abstand */
correctDistance=CORRECT_NONE;
wall_detected=True;
}
wall_distance=sensor;
/* Wenn Korrektur noetig, dann durchfuehren, sonst gleich zurueckdrehen */
if (correctDistance==CORRECT_NONE) checkState=CHECK_WALL_TURN_BACK;
else checkState=CHECK_WALL_CORRECT;
break;
case CHECK_WALL_TURN_BACK:
checkState=CHECK_WALL_FINISHED;
int16 turnAngle=45;
/* welcher Sensorwert wird gebraucht? */
if (check_direction==CHECK_WALL_LEFT) {
sensor=sensDistL;
} else {
sensor=sensDistR;
}
/* wenn vorhanden, aus letztem Abstand und aktuellem Abstand
* Korrekturwinkel berechnen, falls vorheriger Abstand da.
* wird durch Abstand>IGNORE_DISTANCE zurueckgesetzt */
if (lastDistance!=0) {
turnAngle=turnAngle+(lastDistance-wall_distance)/10;
}
if (sensor<IGNORE_DISTANCE) lastDistance=sensor;
if (check_direction==CHECK_WALL_LEFT) {
bot_turn(data,-turnAngle);
} else {
bot_turn(data,turnAngle);
}
break;
case CHECK_WALL_FINISHED:
/* ok, check beendet -> Verhalten verlassen */
checkState=CHECK_WALL_TURN;
return_from_behaviour(data);
break;
case CHECK_WALL_CORRECT:
/* Abhaengig von der Seite, auf der die Wand ist, Entfernung korrigieren */
if (check_direction==CHECK_WALL_LEFT) {
sensor=sensDistL;
} else {
sensor=sensDistR;
}
if (sensor-OPTIMAL_DISTANCE<0) {
speedWishLeft=-BOT_SPEED_SLOW;
speedWishRight=-BOT_SPEED_SLOW;
} else if (sensor-OPTIMAL_DISTANCE>0) {
speedWishLeft=BOT_SPEED_SLOW;
speedWishRight=BOT_SPEED_SLOW;
}
else {
checkState=CHECK_WALL_TURN_BACK;
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
}
break;
default:
checkState=CHECK_WALL_TURN;
return_from_behaviour(data);
break;
}
}
/*!
* Das Verhalten dreht sich um 45 Grad in die angegebene Richtung (0=rechts, 1=links)
* und prueft, ob auf dem Sensor auf der Seite der angegebenen Richtung eine Wand
* im Abstand von 12-22cm zu sehen ist. Wenn dem so ist, wird die Variable wall_present
* auf True gesetzt, sonst False */
void bot_check_wall(Behaviour_t *caller,int8 direction) {
check_direction=direction;
wall_detected=False;
switch_to_behaviour(caller, bot_check_wall_behaviour,NOOVERRIDE);
}
#ifdef MEASURE_MOUSE_AVAILABLE
/*!
* Das Verhalten dreht den Bot in die angegebene Richtung bis ein Hindernis
* im Sichtbereich erscheint, das eine Entfernung bis max. zur angegebenen
* Distanz zum Bot hat.
*/
void bot_measure_angle_behaviour(Behaviour_t *caller) {
/* Zustaende measure_angle_behaviour-Verhalten */
#define MEASURE_TURN 0
#define FOUND_OBSTACLE 1
#define MEASUREMENT_DONE 2
static int8 measureState=MEASURE_TURN;
/* enthaelt anzahl der +/-5 identischen Messungen */
static int8 measureCount=0;
/* letzter Messwert */
static int16 lastSensor=0;
/* bereits gedrehten Winkel */
int16 turned_angle=0;
if (measure_direction>0) {
if ((int16)heading_mou<start_heading) {
/* war ein ueberlauf */
turned_angle=360-start_heading+(int16)heading_mou;
} else {
/* sonst normale differenz berechnen */
turned_angle=(int16)heading_mou-start_heading;
}
} else {
if ((int16)heading_mou>start_heading) {
/* war ein ueberlauf */
turned_angle=360-(int16)heading_mou+start_heading;
} else {
turned_angle=start_heading-(int16)heading_mou;
}
}
/* sensorwert abhaengig von der Drehrichtung abnehmen */
int16 sensor=(measure_direction==MEASURE_LEFT)?sensDistL:sensDistR;
/* solange drehen, bis Hindernis innerhalb Messstrecke oder 360 Grad komplett */
switch(measureState){
case MEASURE_TURN:
/* nicht mehr als eine komplette Drehung machen! */
if (turned_angle>=360) {
measure_direction=-measure_direction;
measureState=MEASUREMENT_DONE;
bot_turn(caller,measure_direction*turned_angle);
measured_angle=0; /* kein Hindernis gefunden */
break;
}
/* Ist ein Objekt in Reichweite? */
if (sensor<=measure_distance) {
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
measureState=FOUND_OBSTACLE;
break;
}
/* Beginnen, zurueckzudrehen */
speedWishLeft = (measure_direction > 0) ? -BOT_SPEED_FOLLOW : BOT_SPEED_FOLLOW;
speedWishRight = (measure_direction > 0) ? BOT_SPEED_FOLLOW : -BOT_SPEED_FOLLOW;
break;
case FOUND_OBSTACLE:
/* dafuer sorgen, dass wir nur verlaessliche Werte haben
* dazu muss der wert dreimal nacheinander max. um +/- 5
* unterschiedlich sein */
if (measureCount==0) {
lastSensor=sensor;
measureCount++;
break;
}
if (sensor>=lastSensor-5 && sensor<=lastSensor+5 && measureCount<4) {
/* Messwert ist ok */
measureCount++;
break;
} else if (measureCount<4) {
/* Messwert weicht zu doll ab -> von Neuem messen */
measureCount=0;
break;
}
/* ok, wir hatten drei Messungen mit nahezu identischen Werten */
measure_distance=sensor;
/* Hindernis gefunden, nun Bot wieder in Ausgangsstellung drehen */
measure_direction=-measure_direction;
measured_angle=turned_angle;
measureState=MEASUREMENT_DONE;
bot_turn(caller,measure_direction*turned_angle);
break;
case MEASUREMENT_DONE:
measureState=MEASURE_TURN;
measureCount=0;
return_from_behaviour(caller);
break;
}
}
/*!
* Das Verhalten dreht den Bot in die angegebene Richtung bis ein Hindernis
* im Sichtbereich erscheint, das eine Entfernung bis max. zur angegebenen
* Distanz zum Bot hat.
*/
void bot_measure_angle(Behaviour_t *caller, int8 direction, int16 distance) {
/* maximale Messentfernung und Richtung setzen */
measure_direction=direction;
measure_distance=distance;
/* Heading zu Anfang des Verhaltens merken */
start_heading=(int16)heading_mou;
switch_to_behaviour(caller, bot_measure_angle_behaviour,NOOVERRIDE);
}
#else
/*!
* Das Verhalten dreht den Bot in die angegebene Richtung bis ein Hindernis
* im Sichtbereich erscheint, das eine Entfernung bis max. zur angegebenen
* Distanz zum Bot hat.
*/
void bot_measure_angle_behaviour(Behaviour_t *caller) {
/* Zustaende measure_angle_behaviour-Verhalten */
#define MEASURE_TURN 0
#define FOUND_OBSTACLE 1
#define TURN_COMPLETED 2
#define TURN_BACK 3
#define CORRECT_ANGLE 4
#define MEASUREMENT_DONE 5
static int8 measureState=MEASURE_TURN;
/* bereits gedrehte Strecke errechnen */
int16 turnedLeft=(measure_direction>0)?-(sensEncL-startEncL):(sensEncL-startEncL);
int16 turnedRight=(measure_direction>0)?(sensEncR-startEncR):-(sensEncR-startEncR);
int16 turnedSteps=(abs(turnedLeft)+abs(turnedRight))/2;
/* sensorwert abhaengig von der Drehrichtung abnehmen */
int16 sensor=(measure_direction==MEASURE_LEFT)?sensDistL:sensDistR;
/* solange drehen, bis Hindernis innerhalb Messstrecke oder 360<36> komplett */
switch(measureState){
case MEASURE_TURN:
/* nicht mehr als eine komplette Drehung machen! */
if (turnedSteps>=ANGLE_CONSTANT) {
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
measureState=TURN_COMPLETED;
measured_angle=0; /* kein Hindernis gefunden */
break;
}
/* Ist ein Objekt in Reichweite? */
if (sensor<=measure_distance) {
measure_distance=sensor;
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
measureState=FOUND_OBSTACLE;
break;
}
/* Beginnen, zurueckzudrehen */
speedWishLeft = (measure_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
speedWishRight = (measure_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
break;
case FOUND_OBSTACLE:
/* Hindernis gefunden, nun Bot wieder in Ausgangsstellung drehen */
measure_direction=-measure_direction;
measured_angle=(int16)((long)(turnedSteps*360)/ANGLE_CONSTANT);
measureState=TURN_BACK;
speedWishLeft = (measure_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
speedWishRight = (measure_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
break;
case TURN_COMPLETED:
/* bot steht wieder in Ausgangsrichtung, Verhalten beenden */
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
measureState=CORRECT_ANGLE;
break;
case TURN_BACK:
/* Bot in Ausgangsposition drehen */
if ((turnedLeft+turnedRight)/2>=0) {
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
measureState=TURN_COMPLETED;
break;
}
speedWishLeft = (measure_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
speedWishRight = (measure_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
break;
case CORRECT_ANGLE:
/* Evtl. etwas zuruecksetzen, falls wir zu weit gefahren sind */
if (turnedRight>0) {
/* rechts zu weit gefahren..langsam zurueck */
speedWishRight = (measure_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
} else if (turnedRight<0) {
/* rechts noch nicht weit genug...langsam vor */
speedWishRight = (measure_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
} else {
/* Endposition erreicht, rechtes Rad anhalten */
speedWishRight = BOT_SPEED_STOP;
}
if (turnedLeft<0) {
/* links zu weit gefahren..langsam zurueck */
speedWishLeft = (measure_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
} else if (turnedLeft>0) {
/* links noch nicht weit genug...langsam vor */
speedWishLeft = (measure_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
} else {
/* Endposition erreicht, linkes Rad anhalten */
speedWishLeft = BOT_SPEED_STOP;
}
if (speedWishLeft == BOT_SPEED_STOP && speedWishRight == BOT_SPEED_STOP) {
/* beide Raeder haben nun wirklich die Endposition erreicht, daher anhalten */
measureState=MEASUREMENT_DONE;
}
break;
case MEASUREMENT_DONE:
measureState=MEASURE_TURN;
return_from_behaviour(caller);
break;
}
}
/*!
* Das Verhalten dreht den Bot in die angegebene Richtung bis ein Hindernis
* im Sichtbereich erscheint, das eine Entfernung bis max. zur angegebenen
* Distanz zum Bot hat.
*/
void bot_measure_angle(Behaviour_t *caller, int8 direction, int16 distance) {
/* maximale Messentfernung und Richtung setzen */
measure_direction=direction;
measure_distance=distance;
/* Encoderwerte zu Anfang des Verhaltens merken */
startEncL=sensEncL;
startEncR=sensEncR;
switch_to_behaviour(caller, bot_measure_angle_behaviour,NOOVERRIDE);
}
#endif
/*!
* Das Verhalten findet seinen Weg durch ein Labyrinth, das nach gewissen Grundregeln gebaut ist
* in nicht immer optimaler Weise aber in jedem Fall. Es arbeitet nach dem Hoehlenforscher-Algorithmus.
* Einschraenkung: Objekte im Labyrinth, die Endlossschleifen verursachen koennen, z.b. ein einzeln
* stehender Pfeiler im Labyrinth um den der Bot dann immer wieder herum fahren wuerde.
*/
void bot_solve_maze_behaviour(Behaviour_t *data){
/* Zustaende fuer das bot_solve_maze_behaviour-Verhalten */
#define CHECK_FOR_STARTPAD 0
#define CHECK_FOR_WALL_RIGHT 1
#define CHECK_FOR_WALL_LEFT 2
#define CHECK_WALL_PRESENT 3
#define SOLVE_MAZE_LOOP 4
#define SOLVE_TURN_WALL 5
#define CHECK_CONDITION 6
#define TURN_TO_BRANCH 7
#define DETECTED_CROSS_BRANCH 8
#define APPROACH_CORNER 9
#define AVOID_ABYSS 10
#define REACHED_GOAL 11
static int8 mazeState=CHECK_FOR_STARTPAD;
static int8 followWall=-1;
static int8 checkedWalls=0;
int16 distance;
double x;
switch(mazeState) {
case CHECK_FOR_STARTPAD:
/* Wo beginnen wir, nach einer Wand zu suchen?
* Abgrund- und Kollisions-Verhalten ausschalten */
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
deactivateBehaviour(bot_avoid_col_behaviour);
#endif
#ifdef BEHAVIOUR_AVOID_BORDER_AVAILABLE
deactivateBehaviour(bot_avoid_border_behaviour);
#endif
/* sieht nach, ob der Bot auf einem definierten Startpad steht und
* beginnt dann mit der Suche gleich an der richtigen Wand */
/* Zuserst bei nach Startpad1 gucken */
checkedWalls=0;
if ((sensLineL>=STARTPAD1-10 && sensLineL<=STARTPAD1+10) ||
(sensLineR>=STARTPAD1-10 && sensLineR<=STARTPAD1+10)) {
mazeState=CHECK_FOR_WALL_LEFT;
break;
}
mazeState=CHECK_FOR_WALL_RIGHT;
break;
case CHECK_FOR_WALL_RIGHT:
mazeState=CHECK_WALL_PRESENT;
followWall=CHECK_WALL_RIGHT;
bot_check_wall(data,followWall);
break;
case CHECK_FOR_WALL_LEFT:
followWall=CHECK_WALL_LEFT;
bot_check_wall(data,followWall);
mazeState=CHECK_WALL_PRESENT;
break;
case CHECK_WALL_PRESENT:
/* wenn keine Wand gefunden aber links noch nicht nachgesehen, andere
* Richtung checken, sonst vorfahren */
checkedWalls++;
if (wall_detected==False){
/* Wand noch nicht entdeckt...haben wir schon beide gecheckt? */
if (checkedWalls<2) {
if (followWall==CHECK_WALL_RIGHT) {
mazeState=CHECK_FOR_WALL_LEFT;
break;
} else {
mazeState=CHECK_FOR_WALL_RIGHT;
break;
}
} else {
/* keine wand? dann vorfahren und selbes prozedere nochmal */
bot_drive_distance(data,0,BOT_SPEED_NORMAL,BOT_DIAMETER);
mazeState=CHECK_FOR_WALL_RIGHT;
checkedWalls=0;
break;
}
}
/* ok, wir haben unsere richtung im labyrinth gefunden jetzt dieser
* nur noch folgen bis Ziel, Abzweig oder Abgrund */
mazeState=SOLVE_MAZE_LOOP;
break;
case SOLVE_MAZE_LOOP:
/* Einen Schritt (=halbe BOT-Groesse) vorwaerts */
mazeState=SOLVE_TURN_WALL;
bot_drive_distance(data,0,BOT_SPEED_NORMAL,BOT_DIAMETER);
break;
case SOLVE_TURN_WALL:
/* Ziel erreicht? */
if ((sensLineL>GROUND_GOAL-20 && sensLineL<GROUND_GOAL+20) ||
(sensLineR>GROUND_GOAL-20 && sensLineR<GROUND_GOAL+20)) {
/* Bot hat Ziel erreicht...aus Freude einmal um die Achse drehen */
bot_turn(data,360);
mazeState=REACHED_GOAL;
break;
}
/* checken, ob wand vor uns (Abstand 2.5*Bot-Durchmesser in mm) */
distance=(sensDistL+sensDistR)/2;
if (distance<=25*BOT_DIAMETER) { // umrechnen 10*BOT_DIAMETER, da letzteres in cm angegeben wird
/* berechnete Entfernung zur Wand abzueglich optimale Distanz fahren */
mazeState=DETECTED_CROSS_BRANCH;
bot_drive_distance(data,0,BOT_SPEED_NORMAL,(distance-OPTIMAL_DISTANCE)/10);
break;
}
/* Zur Wand drehen....ist die Wand noch da? */
mazeState=CHECK_CONDITION;
bot_check_wall(data,followWall);
break;
case CHECK_CONDITION:
/* Solange weiter, wie die Wand zu sehen ist */
if (wall_detected==True) {
mazeState=SOLVE_MAZE_LOOP;
break;
}
/* messen, wo genau die Ecke ist */
mazeState=APPROACH_CORNER;
if (followWall==CHECK_WALL_LEFT){
bot_measure_angle(data,MEASURE_LEFT,300);
} else {
bot_measure_angle(data,MEASURE_RIGHT,300);
}
break;
case TURN_TO_BRANCH:
/* nun in Richtung Abzweig drehen , dann mit Hauptschleife weiter*/
mazeState=SOLVE_MAZE_LOOP;
if (followWall==CHECK_WALL_RIGHT) {
bot_turn(data,-90);
} else {
bot_turn(data,90);
}
break;
case DETECTED_CROSS_BRANCH:
/* Bot faehrt auf eine Ecke zu, in Richtung Gang drehen */
if (followWall==CHECK_WALL_LEFT) {
mazeState=SOLVE_MAZE_LOOP;
bot_turn(data,-90);
} else {
mazeState=SOLVE_MAZE_LOOP;
bot_turn(data,90);
}
break;
case APPROACH_CORNER:
/* ok, nun strecke bis zur Kante berechnen */
x=measure_distance*cos(measured_angle*M_PI/180)/10+BOT_DIAMETER*1.5;
mazeState=TURN_TO_BRANCH;
bot_drive_distance(data,0,BOT_SPEED_NORMAL,(int16)x);
break;
case REACHED_GOAL:
mazeState=CHECK_WALL_RIGHT;
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
return_from_behaviour(data);
break;
}
}
/*!
* Das Verhalten findet seinen Weg durch ein Labyrinth, das nach gewissen Grundregeln gebaut ist
* in nicht immer optimaler Weise aber in jedem Fall. Es arbeitet nach dem Hoehlenforscher-Algorithmus.
* Einschraenkung: Objekte im Labyrinth, die Endlossschleifen verursachen koennen, z.b. ein einzeln
* stehender Pfeiler im Labyrinth um den der Bot dann immer wieder herum fahren wuerde.
*/
void bot_solve_maze(Behaviour_t *caller){
LOG_DEBUG(("bot_solve_maze()"));
switch_to_behaviour(caller, bot_solve_maze_behaviour,NOOVERRIDE);
}
/*!
* Initialisiert den Hoelenforscher
* @param prio_main Prioritaet des Hoehlenforschers (typ. 100)
* @param prio_helper Prioritaet der Hilfsfunktionen (typ. 42)
* @param active ACTIVE wenn der hoehlenforcher sofort starten soll, sonst INACTIVE
*/
void bot_solve_maze_init(int8 prio_main,int8 prio_helper, int8 active){
// Verhalten, um ein Labyrinth nach der Hoehlenforscher-Methode loesen
insert_behaviour_to_list(&behaviour, new_behaviour(prio_main, bot_solve_maze_behaviour,active));
insert_behaviour_to_list(&behaviour, new_behaviour(prio_helper--, bot_measure_angle_behaviour,INACTIVE));
insert_behaviour_to_list(&behaviour, new_behaviour(prio_helper, bot_check_wall_behaviour,INACTIVE));
}
#endif

View file

@ -0,0 +1,361 @@
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file behaviour_turn.c
* @brief Drehe den Bot
*
* @author Benjamin Benz (bbe@heise.de)
* @date 03.11.06
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_TURN_AVAILABLE
#ifdef MCU
#include <avr/eeprom.h>
#endif
#include <stdlib.h>
#include <math.h>
/* Parameter fuer das bot_turn_behaviour() */
#ifndef MEASURE_MOUSE_AVAILABLE
int16 turn_targetR; /*!< Zu drehender Winkel bzw. angepeilter Stand des Radencoders sensEncR */
int16 turn_targetL; /*!< Zu drehender Winkel bzw. angepeilter Stand des Radencoders sensEncL */
#else
int8 angle_correct=0; /*!< Drehabschnitt 0=0-15Grad, 1=16-45 Grad, 2= >45 Grad */
int16 to_turn; /*!< Wieviel Grad sind noch zu drehen? */
#ifdef MCU
uint8 __attribute__ ((section (".eeprom"))) err15=1; /*!< Fehler bei Drehungen unter 15 Grad */
uint8 __attribute__ ((section (".eeprom"))) err45=2; /*!< Fehler bei Drehungen zwischen 15 und 45 Grad */
uint8 __attribute__ ((section (".eeprom"))) err_big=4; /*!< Fehler bei groesseren Drehungen */
#else
uint8 err15=0;
uint8 err45=0;
uint8 err_big=0;
#endif
#endif
int8 turn_direction; /*!< Richtung der Drehung */
/* Hilfsfunktion zur Berechnung einer Winkeldifferenz */
inline int16 calc_turned_angle(int8 direction, int16 angle1, int16 angle2) {
int16 diff_angle=0;
if (direction>0){
// Drehung in mathematisch positivem Sinn
if (angle1>angle2) {
// Es gab einen Ueberlauf
diff_angle=360-angle1+angle2;
} else {
diff_angle=angle2-angle1;
}
} else {
// Drehung in mathematisch negativem Sinn
if (angle1<angle2) {
// Es gab einen Ueberlauf
diff_angle=angle1+360-angle2;
} else {
diff_angle=angle1-angle2;
}
}
return diff_angle;
}
#ifdef MEASURE_MOUSE_AVAILABLE
/*!
* Das Verhalten laesst den Bot eine Punktdrehung durchfuehren.
+ * Drehen findet in drei Schritten statt. Die Drehung wird dabei
+ * bei Winkeln > 15 Grad zunaechst mit hoeherer Geschwindigkeit ausgefuehrt. Bei kleineren
+ * Winkeln oder wenn nur noch 15 Grad zu drehen sind, nur noch mit geringer Geschwindigkeit
* @param *data der Verhaltensdatensatz
* @see bot_turn()
*/
void bot_turn_behaviour(Behaviour_t *data){
// Zustaende fuer das bot_turn_behaviour-Verhalten
#define NORMAL_TURN 0
#define STOP_TURN 1
#define FULL_STOP 2
static int8 turnState=NORMAL_TURN;
static int16 old_heading=-1;
static int16 head_count=0;
uint8 e15;
uint8 e45;
uint8 ebig;
// seit dem letzten mal gedrehte Grad
int16 turned=0;
// aktueller Winkel als int16
int16 akt_heading=(int16)heading_mou;
// erster Aufruf? -> alter Winkel==neuer Winkel
if (old_heading==-1) old_heading=akt_heading;
// berechnen, wieviel Grad seit dem letzten Aufruf gedreht wurden
turned=calc_turned_angle(turn_direction,old_heading,akt_heading);
if (turned > 300) turned -= 360; // hier ging etwas schief
// aktueller Winkel wird alter Winkel
old_heading=akt_heading;
// aktuelle Drehung von zu drehendem Winkel abziehen
to_turn-=turned;
switch(turnState) {
case NORMAL_TURN:
// Solange drehen, bis Drehwinkel erreicht ist
// oder gar zu weit gedreht wurde
if (to_turn<1) {
/* Nachlauf abwarten */
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
turnState=STOP_TURN;
break;
}
speedWishLeft = (turn_direction > 0) ? -BOT_SPEED_NORMAL : BOT_SPEED_NORMAL; speedWishLeft = (turn_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
speedWishRight = (turn_direction > 0) ? BOT_SPEED_NORMAL : -BOT_SPEED_NORMAL; speedWishRight = (turn_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
break;
case STOP_TURN:
// Abwarten, bis Nachlauf beendet
if (akt_heading!=old_heading){
head_count=0;
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
break;
}
if (head_count<10) {
head_count++;
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
break;
}
#ifdef MCU
e15=eeprom_read_byte(&err15);
e45=eeprom_read_byte(&err45);
ebig=eeprom_read_byte(&err_big);
#else
e15=err15;
e45=err45;
ebig=err_big;
#endif
// Neue Abweichung mit alter vergleichen und ggfs neu bestimmen
switch(angle_correct) {
case 0:
if (abs(to_turn)-e15>1) {
e15=(int8)(abs(to_turn)+e15)/2;
#ifdef MCU
eeprom_write_byte(&err15,e15);
#else
err15=e15;
#endif
}
break;
case 1:
if (abs(to_turn)-e45>1) {
e45=(int8)(abs(to_turn)+e45)/2;
#ifdef MCU
eeprom_write_byte(&err45,e45);
#else
err45=e45;
#endif
}
break;
case 2:
if (abs(to_turn)-ebig>1) {
ebig=(int8)(abs(to_turn)+ebig)/2;
#ifdef MCU
eeprom_write_byte(&err_big,ebig);
#else
err_big=ebig;
#endif
}
break;
}
// ok, verhalten beenden
speedWishLeft=BOT_SPEED_STOP;
speedWishRight=BOT_SPEED_STOP;
turnState=NORMAL_TURN;
old_heading=-1;
return_from_behaviour(data);
break;
}
}
void bot_turn(Behaviour_t *caller, int16 degrees)
{
// Richtungsgerechte Umrechnung in den Zielwinkel
if(degrees < 0) turn_direction = -1;
else turn_direction = 1;
to_turn=abs(degrees);
#ifdef MCU
if (eeprom_read_byte(&err15)==255 && eeprom_read_byte(&err45)==255 && eeprom_read_byte(&err_big)==255) {
eeprom_write_byte(&err15,1);
eeprom_write_byte(&err45,2);
eeprom_write_byte(&err_big,4);
}
if (to_turn>45) {
to_turn-=eeprom_read_byte(&err_big);
angle_correct=2;
} else if (to_turn<=45 && to_turn>15) {
to_turn-=eeprom_read_byte(&err45);
angle_correct=1;
} else {
to_turn-=eeprom_read_byte(&err15);
angle_correct=0;
}
#else
if (to_turn>45) {
to_turn-=err_big;
angle_correct=2;
} else if (to_turn<=45 && to_turn>15) {
to_turn-=err45;
angle_correct=1;
} else {
to_turn-=err15;
angle_correct=0;
}
#endif
switch_to_behaviour(caller, bot_turn_behaviour,NOOVERRIDE);
}
#else
/*!
* Das Verhalten laesst den Bot eine Punktdrehung durchfuehren.
* @see bot_turn()
* */
void bot_turn_behaviour(Behaviour_t* data){
/* Drehen findet in vier Schritten statt. Die Drehung wird dabei
* bei Winkeln > 90 Grad zunaechst mit maximaler Geschwindigkeit ausgefuehrt. Bei kleineren
* Winkeln oder wenn nur noch 90 Grad zu drehen sind, nur noch mit normaler Geschwindigkeit
*/
/* Zustaende fuer das bot_turn_behaviour-Verhalten */
#define NORMAL_TURN 0
#define SHORT_REVERSE 1
#define CORRECT_POSITION 2
#define FULL_STOP 3
static int8 turnState=NORMAL_TURN;
/* zu drehende Schritte in die korrekte Drehrichtung korrigieren */
int16 to_turnR = turn_direction*(turn_targetR - sensEncR);
int16 to_turnL = -turn_direction*(turn_targetL - sensEncL);
switch(turnState) {
case NORMAL_TURN:
/* Solange drehen, bis beide Encoder nur noch zwei oder weniger Schritte zu fahren haben */
if (to_turnL <= 2 && to_turnR<=2){
/* nur noch 2 Schritte oder weniger, abbremsen einleiten */
turnState=SHORT_REVERSE;
break;
}
/* Bis 90 Grad kann mit maximaler Geschwindigkeit gefahren werden, danach auf Normal reduzieren */
/* Geschwindigkeit fuer beide Raeder getrennt ermitteln */
if(abs(to_turnL) < ANGLE_CONSTANT*0.25) {
speedWishLeft = (turn_direction > 0) ? -BOT_SPEED_MEDIUM : BOT_SPEED_MEDIUM;
} else {
speedWishLeft = (turn_direction > 0) ? -BOT_SPEED_NORMAL : BOT_SPEED_NORMAL;
}
if(abs(to_turnR) < ANGLE_CONSTANT*0.25) {
speedWishRight = (turn_direction > 0) ? BOT_SPEED_MEDIUM : -BOT_SPEED_MEDIUM;
} else {
speedWishRight = (turn_direction > 0) ? BOT_SPEED_NORMAL : -BOT_SPEED_NORMAL;
}
break;
case SHORT_REVERSE:
/* Ganz kurz durch umpolen anbremsen */
speedWishLeft = (turn_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
speedWishRight = (turn_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
turnState=CORRECT_POSITION;
break;
case CORRECT_POSITION:
/* Evtl. etwas zuruecksetzen, falls wir zu weit gefahren sind */
if (to_turnR<0) {
/* rechts zu weit gefahren..langsam zurueck */
speedWishRight = (turn_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
} else if (to_turnR>0) {
/* rechts noch nicht weit genug...langsam vor */
speedWishRight = (turn_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
} else {
/* Endposition erreicht, rechtes Rad anhalten */
speedWishRight = BOT_SPEED_STOP;
}
if (to_turnL<0) {
/* links zu weit gefahren..langsam zurueck */
speedWishLeft = (turn_direction > 0) ? BOT_SPEED_SLOW : -BOT_SPEED_SLOW;
} else if (to_turnL>0) {
/* links noch nicht weit genug...langsam vor */
speedWishLeft = (turn_direction > 0) ? -BOT_SPEED_SLOW : BOT_SPEED_SLOW;
} else {
/* Endposition erreicht, linkes Rad anhalten */
speedWishLeft = BOT_SPEED_STOP;
}
if (speedWishLeft == BOT_SPEED_STOP && speedWishRight == BOT_SPEED_STOP) {
/* beide Raeder haben nun wirklich die Endposition erreicht, daher anhalten */
turnState=FULL_STOP;
}
break;
default:
/* ist gleichzeitig FULL_STOP, da gleiche Aktion
* Stoppen, State zuruecksetzen und Verhalten beenden */
speedWishLeft = BOT_SPEED_STOP;
speedWishRight = BOT_SPEED_STOP;
turnState=NORMAL_TURN;
return_from_behaviour(data);
break;
}
}
/*!
* Dreht den Bot im mathematisch positiven Sinn.
* @param degrees Grad, um die der Bot gedreht wird. Negative Zahlen drehen im (mathematisch negativen) Uhrzeigersinn.
* Die Aufloesung betraegt rund 3 Grad
*/
void bot_turn(Behaviour_t* caller,int16 degrees){
/* Umrechnung von Grad in Encoder-Markierungen.
* Hinweis: Eigentlich muessten der Umfang von Bot und Rad verwendet werden. Die Rechnung wird
* allerdings viel einfacher, wenn man Pi auskuerzt.
* Ist degrees negativ, ist die Drehung negativ und der rechte Encoder muss kleiner werden.
*/
if(degrees < 0) turn_direction = -1;
else turn_direction = 1;
/* Anzahl zu fahrender Encoderschritte berechnen */
turn_targetR=(degrees*ANGLE_CONSTANT)/360;
/* linkes Rad dreht entgegengesetzt, daher negativer Wert */
turn_targetL=-turn_targetR;
/* aktuellen Sensorwert zu zu drehenden Encoderschritten addieren */
turn_targetR+=sensEncR;
turn_targetL+=sensEncL;
switch_to_behaviour(caller, bot_turn_behaviour,OVERRIDE);
}
#endif
#endif

View file

@ -0,0 +1,500 @@
/*
* c't-Sim - Robotersimulator fuer den c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
/*! @file bot-logik.c
* @brief High-Level Routinen fuer die Steuerung des c't-Bots.
* Diese Datei sollte der Einstiegspunkt fuer eigene Experimente sein,
* den Roboter zu steuern.
*
* bot_behave() arbeitet eine Liste von Verhalten ab.
* Jedes Verhalten kann entweder absolute Werte setzen, dann kommen niedrigerpriorisierte nicht mehr dran.
* Alternativ dazu kann es Modifikatoren aufstellen, die bei niedriger priorisierten angewendet werden.
* bot_behave_init() baut diese Liste auf.
* Jede Verhaltensfunktion bekommt einen Verhaltensdatensatz uebergeben, in den Sie ihre Daten eintraegt
*
* @author Benjamin Benz (bbe@heise.de)
* @author Christoph Grimmer (c.grimmer@futurio.de)
* @date 01.12.05
*/
#include "bot-logic/bot-logik.h"
#ifdef BEHAVIOUR_AVAILABLE
#include "display.h"
#include "rc5.h"
#include <stdlib.h>
int16 speedWishLeft; /*!< Puffervariablen fuer die Verhaltensfunktionen absolut Geschwindigkeit links*/
int16 speedWishRight; /*!< Puffervariablen fuer die Verhaltensfunktionen absolut Geschwindigkeit rechts*/
float faktorWishLeft; /*!< Puffervariablen fuer die Verhaltensfunktionen Modifikationsfaktor links*/
float faktorWishRight; /*!< Puffervariablen fuer die Verhaltensfunktionen Modifikationsfaktor rechts */
int16 target_speed_l=BOT_SPEED_STOP; /*!< Sollgeschwindigkeit linker Motor - darum kuemmert sich bot_base()*/
int16 target_speed_r=BOT_SPEED_STOP; /*!< Sollgeschwindigkeit rechter Motor - darum kuemmert sich bot_base() */
/*! Liste mit allen Verhalten */
Behaviour_t *behaviour = NULL;
/*!
* Das einfachste Grundverhalten
* @param *data der Verhaltensdatensatz
*/
void bot_base_behaviour(Behaviour_t *data){
speedWishLeft=target_speed_l;
speedWishRight=target_speed_r;
}
/*!
* Initialisert das ganze Verhalten
*/
void bot_behave_init(void){
#ifdef BEHAVIOUR_REMOTECALL_AVAILABLE
// Dieses Verhalten kann andere Starten
insert_behaviour_to_list(&behaviour, new_behaviour(254, bot_remotecall_behaviour,INACTIVE));
#endif
#ifdef BEHAVIOUR_SERVO_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(253, bot_servo_behaviour,INACTIVE));
#endif
// Demo-Verhalten, ganz einfach, inaktiv
// Achtung, im Moment hat es eine hoehere Prioritaet als die Gefahrenerkenner!!!
#ifdef BEHAVIOUR_SIMPLE_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(252, bot_simple_behaviour,INACTIVE));
insert_behaviour_to_list(&behaviour, new_behaviour(251, bot_simple2_behaviour,INACTIVE));
#endif
// Hoechste Prioritate haben die Notfall Verhalten
// Verhalten zum Schutz des Bots, hohe Prioritaet, Aktiv
#ifdef BEHAVIOUR_AVOID_BORDER_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(250, bot_avoid_border_behaviour,ACTIVE));
#endif
#ifdef BEHAVIOUR_AVOID_COL_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(249, bot_avoid_col_behaviour,ACTIVE));
#endif
#ifdef BEHAVIOUR_SCAN_AVAILABLE
// Verhalten, das die Umgebung des Bots on-the fly beim fahren scannt
insert_behaviour_to_list(&behaviour, new_behaviour(155, bot_scan_onthefly_behaviour,ACTIVE));
// Verhalten, das einmal die Umgebung des Bots scannt
insert_behaviour_to_list(&behaviour, new_behaviour(152, bot_scan_behaviour,INACTIVE));
#endif
// Alle Hilfsroutinen sind relativ wichtig, da sie auch von den Notverhalten her genutzt werden
// Hilfsverhalten, die Befehle von Boten-Funktionen ausfuehren, erst inaktiv, werden von Boten aktiviert
#ifdef BEHAVIOUR_TURN_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(150, bot_turn_behaviour,INACTIVE));
#endif
#ifdef BEHAVIOUR_DRIVE_DISTANCE_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(149, bot_drive_distance_behaviour,INACTIVE));
#endif
#ifdef BEHAVIOUR_GOTO_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(148, bot_goto_behaviour,INACTIVE));
#endif
// Hilfsverhalten zum Anfahren von Positionen
#ifdef BEHAVIOUR_GOTOXY_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(147, bot_gotoxy_behaviour,INACTIVE));
#endif
#ifdef BEHAVIOUR_CATCH_PILLAR_AVAILABLE
insert_behaviour_to_list(&behaviour, new_behaviour(44, bot_catch_pillar_behaviour,INACTIVE));
#endif
#ifdef BEHAVIOUR_OLYMPIC_AVAILABLE
bot_olympic_init(52,100,INACTIVE);
#endif
#ifdef BEHAVIOUR_FOLLOW_LINE_AVAILABLE
// Verhalten um einer Linie zu folgen
insert_behaviour_to_list(&behaviour, new_behaviour(70, bot_follow_line_behaviour, ACTIVE));
#endif
#ifdef BEHAVIOUR_SOLVE_MAZE_AVAILABLE
bot_solve_maze_init(100,43,INACTIVE);
#endif
#ifdef BEHAVIOUR_DRIVE_SQUARE_AVAILABLE
// Demo-Verhalten, etwas komplexer, inaktiv
insert_behaviour_to_list(&behaviour, new_behaviour(51, bot_drive_square_behaviour,INACTIVE));
#endif
// Grundverhalten, setzt aeltere FB-Befehle um, aktiv
insert_behaviour_to_list(&behaviour, new_behaviour(2, bot_base_behaviour, ACTIVE));
// Um das Simple-Behaviour zu nutzen, die Kommentarzeichen vor der folgenden Zeile entfernen!!!
// activateBehaviour(bot_simple_behaviour);
// activateBehaviour(bot_simple2_behaviour);
#ifdef PC
#ifdef DISPLAY_AVAILABLE
/* Anzeigen der geladenen Verhalten */
Behaviour_t *ptr = behaviour;
display_cursor(5,1);
display_printf("Verhaltensstack:\n");
while(ptr != NULL) {
display_printf("Prioritaet: %d.\n", ptr->priority);
ptr = ptr->next;
}
#endif
#endif
}
/*!
* Aktiviert eine Regel mit gegebener Funktion
* @param function Die Funktion, die das Verhalten realisiert.
*/
void activateBehaviour(BehaviourFunc function){
Behaviour_t *job; // Zeiger auf ein Verhalten
// Einmal durch die Liste gehen, bis wir den gewuenschten Eintrag haben
for (job = behaviour; job; job = job->next) {
if (job->work == function) {
job->active = ACTIVE;
break;
}
}
}
/*!
* Deaktiviert eine Regel mit gegebener Funktion
* @param function Die Funktion, die das Verhalten realisiert.
*/
void deactivateBehaviour(BehaviourFunc function){
Behaviour_t *job; // Zeiger auf ein Verhalten
// Einmal durch die Liste gehen, bis wir den gewuenschten Eintrag haben
for (job = behaviour; job; job = job->next) {
if (job->work == function) {
job->active = INACTIVE;
break;
}
}
}
/*!
* Ruft ein anderes Verhalten auf und merkt sich den Ruecksprung
* return_from_behaviour() kehrt dann spaeter wieder zum aufrufenden Verhalten zurueck
* @param from aufrufendes Verhalten
* @param to aufgerufenes Verhalten
* @param override Hier sind zwei Werte Moeglich:
* 1. OVERRIDE : Das Zielverhalten to wird aktiviert, auch wenn es noch aktiv ist.
* Das Verhalten, das es zuletzt aufgerufen hat wird dadurch automatisch
* wieder aktiv und muss selbst sein eigenes Feld subResult auswerten, um zu pruefen, ob das
* gewuenschte Ziel erreicht wurde, oder vorher ein Abbruch stattgefunden hat.
* 2. NOOVERRIDE : Das Zielverhalten wird nur aktiviert, wenn es gerade nichts zu tun hat.
* In diesem Fall kann der Aufrufer aus seinem eigenen subResult auslesen,
* ob seibem Wunsch Folge geleistet wurde.
*/
void switch_to_behaviour(Behaviour_t * from, void *to, uint8 override ){
Behaviour_t *job; // Zeiger auf ein Verhalten
// Einmal durch die Liste gehen, bis wir den gewuenschten Eintrag haben
for (job = behaviour; job; job = job->next) {
if (job->work == to) {
break; // Abbruch der Schleife, job zeigt nun auf die Datenstruktur des Zielverhaltens
}
}
if (job->caller){ // Ist das auzurufende Verhalten noch beschaeftigt?
if (override==NOOVERRIDE){ // nicht ueberschreiben, sofortige Rueckkehr
if (from)
from->subResult=SUBFAIL;
return;
}
// Wir wollen also ueberschreiben, aber nett zum alten Aufrufer sein und ihn darueber benachrichtigen
job->caller->active=ACTIVE; // alten Aufrufer reaktivieren
job->caller->subResult=SUBFAIL; // er bekam aber nicht das gewuenschte Resultat
}
if (from) {
// laufendes Verhalten abschalten
from->active=INACTIVE;
from->subResult=SUBRUNNING;
}
// neues Verhalten aktivieren
job->active=ACTIVE;
// Aufrufer sichern
job->caller = from;
}
/*!
* Kehrt zum aufrufenden Verhalten zurueck
* @param running laufendes Verhalten
*/
void return_from_behaviour(Behaviour_t * data){
data->active=INACTIVE; // Unterverhalten deaktivieren
if (data->caller){
data->caller->active=ACTIVE; // aufrufendes Verhalten aktivieren
data->caller->subResult=SUBSUCCESS; // Unterverhalten war erfolgreich
}
data->caller=NULL; // Job erledigt, Verweis loeschen
}
/*!
* Deaktiviert alle Verhalten bis auf Grundverhalten. Bei Verhaltensauswahl werden die Aktivitaeten vorher
* in die Verhaltens-Auswahlvariable gesichert.
*/
void deactivateAllBehaviours(void){
Behaviour_t *job; // Zeiger auf ein Verhalten
#ifdef DISPLAY_BEHAVIOUR_AVAILABLE
// bei Verhaltensanzeige in Aktivitaets-Auswahl-Variable sichern
#ifndef DISPLAY_DYNAMIC_BEHAVIOUR_AVAILABLE
// bei Verhaltensanzeige in Aktivitaets-Auswahl-Variable sichern
// nicht bei dynamischer Anzeige und Selektion
set_behaviours_equal();
#endif
#endif
// Einmal durch die Liste gehen und (fast) alle deaktivieren, Grundverhalten nicht
for (job = behaviour; job; job = job->next) {
if ((job->priority >= PRIO_VISIBLE_MIN) &&(job->priority <= PRIO_VISIBLE_MAX)) {
// Verhalten deaktivieren
job->active = INACTIVE;
}
}
}
/*!
* Zentrale Verhaltens-Routine, wird regelmaessig aufgerufen.
* Dies ist der richtige Platz fuer eigene Routinen, um den Bot zu steuern.
*/
void bot_behave(void){
Behaviour_t *job; // Zeiger auf ein Verhalten
float faktorLeft = 1.0; // Puffer fuer Modifkatoren
float faktorRight = 1.0; // Puffer fuer Modifkatoren
#ifdef RC5_AVAILABLE
rc5_control(); // Abfrage der IR-Fernbedienung
#endif
/* Solange noch Verhalten in der Liste sind...
(Achtung: Wir werten die Jobs sortiert nach Prioritaet aus. Wichtige zuerst einsortieren!!!) */
for (job = behaviour; job; job = job->next) {
if (job->active) {
/* WunschVariablen initialisieren */
speedWishLeft = BOT_SPEED_IGNORE;
speedWishRight = BOT_SPEED_IGNORE;
faktorWishLeft = 1.0;
faktorWishRight = 1.0;
job->work(job); /* Verhalten ausfuehren */
/* Modifikatoren sammeln */
faktorLeft *= faktorWishLeft;
faktorRight *= faktorWishRight;
/* Geschwindigkeit aendern? */
if ((speedWishLeft != BOT_SPEED_IGNORE) || (speedWishRight != BOT_SPEED_IGNORE)){
if (speedWishLeft != BOT_SPEED_IGNORE)
speedWishLeft *= faktorLeft;
if (speedWishRight != BOT_SPEED_IGNORE)
speedWishRight *= faktorRight;
motor_set(speedWishLeft, speedWishRight);
break; /* Wenn ein Verhalten Werte direkt setzen will, nicht weitermachen */
}
}
/* Dieser Punkt wird nur erreicht, wenn keine Regel im System die Motoren beeinflusen will */
if (job->next == NULL) {
motor_set(BOT_SPEED_IGNORE, BOT_SPEED_IGNORE);
}
}
}
/*!
* Erzeugt ein neues Verhalten
* @param priority Die Prioritaet
* @param *work Den Namen der Funktion, die sich drum kuemmert
*/
Behaviour_t *new_behaviour(uint8 priority, void (*work) (struct _Behaviour_t *data), int8 active){
Behaviour_t *newbehaviour = (Behaviour_t *) malloc(sizeof(Behaviour_t));
if (newbehaviour == NULL)
return NULL;
newbehaviour->priority = priority;
newbehaviour->active=active;
newbehaviour->next= NULL;
newbehaviour->work=work;
newbehaviour->caller=NULL;
newbehaviour->subResult=SUBSUCCESS;
return newbehaviour;
}
/*!
* Fuegt ein Verhalten der Verhaltenliste anhand der Prioritaet ein.
* @param list Die Speicherstelle an der die globale Verhaltensliste anfaengt
* @param behave Einzufuegendes Verhalten
*/
void insert_behaviour_to_list(Behaviour_t **list, Behaviour_t *behave){
Behaviour_t *ptr = *list;
Behaviour_t *temp = NULL;
/* Kein Eintrag dabei? */
if (behave == NULL)
return;
/* Erster Eintrag in der Liste? */
if (ptr == NULL){
ptr = behave;
*list = ptr;
} else {
/* Gleich mit erstem Eintrag tauschen? */
if (ptr->priority < behave->priority) {
behave->next = ptr;
ptr = behave;
*list = ptr;
} else {
/* Mit dem naechsten Eintrag vergleichen */
while(NULL != ptr->next) {
if (ptr->next->priority < behave->priority)
break;
/* Naechster Eintrag */
ptr = ptr->next;
}
temp = ptr->next;
ptr->next = behave;
behave->next = temp;
}
}
}
#ifdef DISPLAY_BEHAVIOUR_AVAILABLE
/*!
* ermittelt ob noch eine weitere Verhaltensseite existiert
*/
int8 another_behaviour_page(void) {
int16 max_behaviours ;
Behaviour_t *ptr ;
/* dazu muss ich auch gueltige Screenseite sein */
#ifdef DISPLAY_SCREENS_AVAILABLE
if (display_screen != 2)
return 0;
#endif
ptr = behaviour;
max_behaviours = 0;
// zuerst alle Verhalten ermitteln ausser Grundverhalten
while(ptr != NULL) {
if ((ptr->priority >= PRIO_VISIBLE_MIN) &&(ptr->priority <= PRIO_VISIBLE_MAX))
max_behaviours++;
ptr = ptr->next;
}
return (behaviour_page * 6) < max_behaviours;
}
/*!
* toggled ein Verhalten der Verhaltensliste an Position pos,
* die Aenderung erfolgt nur auf die Puffervariable
* @param pos Listenposition, entspricht der Taste 1-6 der gewaehlten Verhaltensseite
*/
void toggleNewBehaviourPos(int8 pos){
Behaviour_t *job; // Zeiger auf ein Verhalten
int8 i;
// nur aendern, wenn ich richtige Screenseite bin
if (display_screen != 2)
return ;
// richtigen Index je nach Seite ermitteln
pos = (behaviour_page - 1) * 6 + pos;
i = 0;
// durch die Liste gehen, bis wir den gewuenschten Index erreicht haben
for (job = behaviour; job; job = job->next) {
if ((job->priority >= PRIO_VISIBLE_MIN) &&(job->priority <= PRIO_VISIBLE_MAX)) {
i++;
if (i == pos) {
// bei dynamischer Wahl wird direkt die Zustandsvariable geaendert
#ifdef DISPLAY_DYNAMIC_BEHAVIOUR_AVAILABLE
job->active = !job->active;
#else
job->active_new = !job->active_new;
#endif
break;
}
}
}
}
#ifndef DISPLAY_DYNAMIC_BEHAVIOUR_AVAILABLE
/*!
* Startschuss, die gewaehlten neuen Verhaltensaktivitaeten werden in die
* Verhaltensliste geschrieben und die Verhalten damit scharf geschaltet
*/
void set_behaviours_active_to_new(void) {
Behaviour_t *job;
for (job = behaviour; job; job = job->next) {
if ((job->priority >= PRIO_VISIBLE_MIN) &&(job->priority <= PRIO_VISIBLE_MAX))
job->active = job->active_new;
}
}
/*!
* Die Aktivitaeten der Verhalten werden in die Puffervariable geschrieben,
* welche zur Anzeige und Auswahl verwendet wird
*/
void set_behaviours_equal(void) {
Behaviour_t *job;
for (job = behaviour; job; job = job->next) {
if ((job->priority >= PRIO_VISIBLE_MIN) &&(job->priority <= PRIO_VISIBLE_MAX))
job->active_new = job->active;
}
}
#endif
#endif
#endif