c't

c't-Projekte - Mailinglisten


[Voriger (Datum)] [Nächster (Datum)] [Voriger (Thread)] [Nächster (Thread)]
[Nach Datum][Nach Thread]

[ct-bot] main vereinfacht

Absender: Simon Siemens
Datum: Do, 12.05.2011 19:02:47


Hallo Timo,

ich schlage in den folgenden drei Emails jeweils drei Patches vor (sogar
mit Changelog-Eintrag :-)). Alle drei hÃngen irgendwo zusammen, kÃnnen
aber auch getrennt betrachtet werden. Die zwei Ersten sind die
Ãnderungen, die wir schon seit Langem verwenden. Wir dachten uns nun,
sie wÃren vielleicht auch von allgemeinem Interesse.

Der Patch in dieser Email vereinfacht das Schreiben einer main-Funktion
auf das typische generische GrundgerÃst

int main(int argc, char * argv[]) {
        ctbot_init(argc, argv);

        for (;;) {
                pre_behaviour();

                // Hier kommt der Verhaltenscode

                post_behaviour();
        }
}

Dieses GrundgerÃst passt zu Robotersoftware ebenso wie zu GUI-Software.
Es hat drei wesentliche Vorteile

      * Updates an der ct-Bot-Infrastruktur haben keine Auswirkungen auf
        die main-Funktion. Wenn also jemand sein eigenes Verhalten mit
        seiner eigene main-Funktion geschrieben hat (also komplett
        eigene ct-Bot.c), dann funktioniert das mit Release 20 ebenso
        wie mit Release 30 des ct-Bot-Codes â solange beide Releases die
        drei Funktionen ctbot_init, pre_behaviour und post_behaviour
        verwenden. Einfach ein neuer make-Aufruf und fertig.
      * Es ist sehr einfach, selbst eine main-Funktion / ct-Bot.c zu
        schreiben. Fehler kÃnnen einem dabei kaum unterlaufen.
      * Auch AnfÃnger verstehen diesen Aufbau und damit das Konzept
        (nicht die Details) hinter dem ct-Bot-Code.
      * Ein vierter Vorteil erschlieÃt sich, wenn man meinen Vorschlag
        einer Bibliothek der Hardware-Abstraktionsschicht denkt. (Wir
        liefern eine solche Bibliothek an unsere Studenten aus.)
        Bibliotheken enthalten Ãblicherweise keine main-Funktion,
        sollten es dem Nutzer aber einfach machen, eine zu schreiben.
        Das klappt mit diesem Patch ganz gut.

Was hÃltst du davon?

GruÃ, Simon

PS: Die main in ct-Bot.c ist Ãbrigens etwas komplizierter, weil dort ja
bereits ein Verhalten (das Testprogramm) implementiert ist.
Index: ct-Bot.c
===================================================================
--- ct-Bot.c	(Revision 1786)
+++ ct-Bot.c	(Arbeitskopie)
@@ -25,69 +25,27 @@
  */
 
 #include "ct-Bot.h"
+#include "global.h"
 #include "init.h"
-#include "display.h"
-#include "log.h"
-#include "sp03.h"
-#include "bot-2-sim.h"
-#include "sensor-low.h"
-#include "trace.h"
 #include "motor.h"
 #include "bot-logic/bot-logic.h"
-#include "sensor.h"
-#include "gui.h"
-#include "command.h"
-#include "os_thread.h"
-#include "timer.h"
 
 
-//#define DEBUG_TIMES	/*!< Gibt Debug-Infos zum Timing aus (PC) */
-
-
 /*!
  * Hauptprogramm des Bots. Diese Schleife kuemmert sich um seine Steuerung.
  */
 int main(int argc, char * argv[]) {
-	static uint16_t comm_ticks = 0;
-	static uint8_t uart_gui = 0;
-
 	/* Alles initialisieren */
 	ctbot_init(argc, argv);
 
-#ifdef WELCOME_AVAILABLE
-	display_cursor(1, 1);
-	display_puts("c't-Roboter");
-
-#ifdef LOG_AVAILABLE
-	LOG_INFO("Hallo Welt!");
-#endif
-#ifdef SP03_AVAILABLE
-	sp03_say("I am Robi %d", sensError);
-#endif
-#endif // WELCOME_AVAILABLE
-
 #ifdef  TEST_AVAILABLE_MOTOR
 	uint16_t calls = 0;	// Im Testfall zaehle die Durchlaeufe
 #endif
 
 	/* Hauptschleife des Bots */
 	for (;;) {
-#ifdef BOT_2_SIM_AVAILABLE
-		/* Daten vom Sim empfangen */
-		bot_2_sim_listen();
-#endif // BOT_2_SIM_AVAILABLE
+		pre_behaviour();
 
-		/* Sensordaten aktualisieren / auswerten */
-		bot_sens();
-
-#if defined PC && defined DEBUG_TIMES
-		/* Zum Debuggen der Zeiten */
-		struct timeval start, stop;
-		GETTIMEOFDAY(&start, NULL);
-		int t1 = (start.tv_sec - stop.tv_sec) * 1000000 + start.tv_usec - stop.tv_usec;
-		printf("Done-Token (%d) in nach %d usec\n", received_command.data_l, t1);
-#endif // PC && DEBUG_TIMES
-
 #ifdef TEST_AVAILABLE_MOTOR
 		/* Testprogramm, das den Bot erst links-, dann rechtsrum dreht */
 		if (calls < 1001) {
@@ -108,54 +66,6 @@
 #endif // BEHAVIOUR_AVAILABLE
 		}
 
-#ifdef CREATE_TRACEFILE_AVAILABLE
-		trace_add_sensors();
-#endif // CREATE_TRACEFILE_AVAILABLE
-
-		/* jeweils alle 100 ms kommunizieren Bot, User und Sim */
-		if (timer_ms_passed_16(&comm_ticks, 50)
-#ifdef RC5_AVAILABLE
-			|| RC5_Code != 0
-#endif
-		) {
-			if (uart_gui == 0
-#ifdef RC5_AVAILABLE
-				|| RC5_Code != 0
-#endif
-			) {
-#ifdef DISPLAY_AVAILABLE
-				/* GUI-Behandlung starten */
-				gui_display(display_screen);
-#endif // DISPLAY_AVAILABLE
-				uart_gui = 1; // bot-2-sim ist erst beim naechsten Mal dran
-			} else {
-#ifdef BOT_2_SIM_AVAILABLE
-				/* Den Sim ueber Sensoren und Aktuatoren informieren */
-				bot_2_sim_inform(); // NOP auf PC
-#endif // BOT_2_SIM_AVAILABLE
-				uart_gui = 0; // naechstes Mal wieder mit GUI anfangen
-			}
-		}
-
-#ifdef PC
-#ifdef CREATE_TRACEFILE_AVAILABLE
-		trace_add_actuators();
-#endif // CREATE_TRACEFILE_AVAILABLE
-
-		/* Sim ueber naechsten Schleifendurchlauf / Bot-Zyklus informieren */
-		command_write(CMD_DONE, SUB_CMD_NORM, simultime, 0, 0); // flusht auch den Sendepuffer
-
-#ifdef DEBUG_TIMES
-		/* Zum Debuggen der Zeiten */
-		GETTIMEOFDAY(&stop, NULL);
-		int t2 = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
-		printf("Done-Token (%d) out after %d usec\n", simultime, t2);
-#endif // DEBUG_TIMES
-#endif // PC
-
-#ifdef OS_AVAILABLE
-		/* Rest der Zeitscheibe (OS_TIME_SLICE ms) schlafen legen */
-		os_thread_yield();
-#endif // OS_AVAILABLE
+		post_behaviour();
 	}
 }
Index: init.c
===================================================================
--- init.c	(Revision 1786)
+++ init.c	(Arbeitskopie)
@@ -26,6 +26,7 @@
 
 #include "ct-Bot.h"
 
+#include "command.h"
 #include "init.h"
 #include "timer.h"
 #include "uart.h"
@@ -36,17 +37,24 @@
 #include "ena.h"
 #include "mmc.h"
 #include "botfs.h"
+#include "sensor.h"
 #include "sensor-low.h"
 #include "ir-rc5.h"
 #include "mouse.h"
 #include "map.h"
+#include "os_thread.h"
 #include "log.h"
 #include "i2c.h"
+#include "timer.h"
 #include "twi.h"
 #include "gui.h"
 
 mmc_buffers_t mmc_buffers; /*!< Puffer fuer alle MMC-Transfers */
 
+#if defined PC && defined DEBUG_TIMES
+struct timeval init_start, init_stop; /*!< Zeit von Beginn und Ende des Verhaltensdurchlaufs */
+#endif // PC && DEBUG_TIMES
+
 /*!
  * Initialisierung
  */
@@ -123,9 +131,104 @@
 #endif
 
 	ctbot_init_low_last();
+
+#ifdef WELCOME_AVAILABLE
+	display_cursor(1, 1);
+	display_puts("c't-Roboter");
+
+#ifdef LOG_AVAILABLE
+	LOG_INFO("Hallo Welt!");
+#endif
+#ifdef SP03_AVAILABLE
+	sp03_say("I am Robi %d", sensError);
+#endif
+#endif // WELCOME_AVAILABLE
 }
 
 /*!
+ * Fuehrt die Verarbeitung in der Hauptschlaufe vor dem 
+ * Verhaltenscode durch. Dazu gehoert beispielsweise, die Sensoren 
+ * abzufragen und auf Pakete des Simulators zu reagieren.
+ */
+void pre_behaviour(void) {
+#ifdef BOT_2_SIM_AVAILABLE
+	/* Daten vom Sim empfangen */
+	bot_2_sim_listen();
+#endif // BOT_2_SIM_AVAILABLE
+
+	/* Sensordaten aktualisieren / auswerten */
+	bot_sens();
+
+#if defined PC && defined DEBUG_TIMES
+	/* Zum Debuggen der Zeiten */
+	GETTIMEOFDAY(&init_start, NULL);
+	int t1 = (init_start.tv_sec - init_stop.tv_sec) * 1000000 + init_start.tv_usec - init_stop.tv_usec;
+	printf("Done-Token (%d) in nach %d usec\n", received_command.data_l, t1);
+#endif // PC && DEBUG_TIMES
+}
+
+/*!
+ * Fuehrt die Verarbeitung in der Hauptschleife nach dem 
+ * Verhaltenscode durch. Dazu gehoert beispielsweise, die 
+ * Bildschirmanzeige zu steuern und den Simulator Ãber den aktuellen 
+ * Zustand zu informieren.
+ */
+void post_behaviour(void) {
+	static uint16_t comm_ticks = 0;
+	static uint8_t uart_gui = 0;
+
+#ifdef CREATE_TRACEFILE_AVAILABLE
+	trace_add_sensors();
+#endif // CREATE_TRACEFILE_AVAILABLE
+
+	/* jeweils alle 100 ms kommunizieren Bot, User und Sim */
+	if (timer_ms_passed_16(&comm_ticks, 50)
+#ifdef RC5_AVAILABLE
+		|| RC5_Code != 0
+#endif
+	) {
+		if (uart_gui == 0
+#ifdef RC5_AVAILABLE
+			|| RC5_Code != 0
+#endif
+		) {
+#ifdef DISPLAY_AVAILABLE
+			/* GUI-Behandlung starten */
+			gui_display(display_screen);
+#endif // DISPLAY_AVAILABLE
+			uart_gui = 1; // bot-2-sim ist erst beim naechsten Mal dran
+		} else {
+#ifdef BOT_2_SIM_AVAILABLE
+			/* Den Sim ueber Sensoren und Aktuatoren informieren */
+			bot_2_sim_inform(); // NOP auf PC
+#endif // BOT_2_SIM_AVAILABLE
+			uart_gui = 0; // naechstes Mal wieder mit GUI anfangen
+		}
+	}
+
+#ifdef PC
+#ifdef CREATE_TRACEFILE_AVAILABLE
+	trace_add_actuators();
+#endif // CREATE_TRACEFILE_AVAILABLE
+
+	/* Sim ueber naechsten Schleifendurchlauf / Bot-Zyklus informieren */
+	command_write(CMD_DONE, SUB_CMD_NORM, simultime, 0, 0); // flusht auch den Sendepuffer
+
+#ifdef DEBUG_TIMES
+	/* Zum Debuggen der Zeiten */
+	GETTIMEOFDAY(&init_stop, NULL);
+	int t2 = (init_stop.tv_sec - init_start.tv_sec) * 1000000 + init_stop.tv_usec - init_start.tv_usec;
+	printf("Done-Token (%d) out after %d usec\n", simultime, t2);
+#endif // DEBUG_TIMES
+#endif // PC
+
+#ifdef OS_AVAILABLE
+	/* Rest der Zeitscheibe (OS_TIME_SLICE ms) schlafen legen */
+	os_thread_yield();
+#endif // OS_AVAILABLE
+}
+
+/*!
  * Faehrt den Bot sauber herunter
  */
 void ctbot_shutdown(void) {
Index: ct-Bot.h
===================================================================
--- ct-Bot.h	(Revision 1786)
+++ ct-Bot.h	(Arbeitskopie)
@@ -97,6 +97,8 @@
 
 //#define BOOTLOADER_AVAILABLE	/*!< Aktiviert den Bootloadercode - das ist nur noetig fuer die einmalige "Installation" des Bootloaders. Siehe auch Documentation/Bootloader.html */
 
+//#define DEBUG_TIMES	/*!< Gibt Debug-Infos zum Timing aus (PC) */
+
 /************************************************************
  * Some Dependencies!!!
  ************************************************************/
Index: include/init.h
===================================================================
--- include/init.h	(Revision 1786)
+++ include/init.h	(Arbeitskopie)
@@ -94,6 +94,21 @@
 void ctbot_init_low_last(void);
 
 /*!
+ * Fuehrt die Verarbeitung in der Hauptschlaufe vor dem 
+ * Verhaltenscode durch. Dazu gehoert beispielsweise, die Sensoren 
+ * abzufragen und auf Pakete des Simulators zu reagieren.
+ */
+void pre_behaviour(void);
+
+/*!
+ * Fuehrt die Verarbeitung in der Hauptschleife nach dem 
+ * Verhaltenscode durch. Dazu gehoert beispielsweise, die 
+ * Bildschirmanzeige zu steuern und den Simulator Ãber den aktuellen 
+ * Zustand zu informieren.
+ */
+void post_behaviour(void);
+
+/*!
  * Faehrt den Bot sauber herunter
  */
 void ctbot_shutdown(void);
Index: Changelog.txt
===================================================================
--- Changelog.txt	(Revision 1786)
+++ Changelog.txt	(Arbeitskopie)
@@ -1,5 +1,7 @@
 CHANGELOG fuer c't-Bot
 ======================
+2011-05-12 Simon Siemens [simon.siemens@xxxxxxxx]: Vereinfachung der main-Funktion. VerhaltensunabhÃngigen Code dazu in init.c ausgelagert. In main verbleibt nur ein generisches GrundgerÃst. Damit sind keine Ãnderungen an main bei Updates mehr nÃtig und jeder kann sich sehr einfach eine eigene main-Funktion schreiben.
+
 2011-05-06 Timo Sandmann [mail@xxxxxxxxxxxxxxx]: Bugfix falls RC5_AVAILABLE aus ist
 
 2011-05-04 Timo Sandmann [mail@xxxxxxxxxxxxxxx]: Bugfix fuer #include-Abhaengigkeiten
@@ -1132,4 +1134,4 @@
 
 2006-01-25	Benjamin Benz (bbe@xxxxxxxx) Status der LEDs wird nun an den Simulator uebertragen
 
-2006-01-24	Benjamin Benz (bbe@xxxxxxxx) Schreibweise des Changelogs nochmal veraendert
\ No newline at end of file
+2006-01-24	Benjamin Benz (bbe@xxxxxxxx) Schreibweise des Changelogs nochmal veraendert