From 56d9bdd39ed36c36e9a61411b86c76d5228b2133 Mon Sep 17 00:00:00 2001 From: sicarius Date: Sun, 11 Feb 2007 18:32:03 +0000 Subject: Added lot's of code-files used during work --- source/ct-Bot/bot-logic/behaviour_turn.c | 361 +++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 source/ct-Bot/bot-logic/behaviour_turn.c (limited to 'source/ct-Bot/bot-logic/behaviour_turn.c') diff --git a/source/ct-Bot/bot-logic/behaviour_turn.c b/source/ct-Bot/bot-logic/behaviour_turn.c new file mode 100644 index 0000000..5b53c89 --- /dev/null +++ b/source/ct-Bot/bot-logic/behaviour_turn.c @@ -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 +#endif +#include +#include + +/* 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 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 + -- cgit v1.2.3