summaryrefslogtreecommitdiff
path: root/2004/n/asserv/src
diff options
context:
space:
mode:
Diffstat (limited to '2004/n/asserv/src')
-rw-r--r--2004/n/asserv/src/README3
-rw-r--r--2004/n/asserv/src/main.c115
-rw-r--r--2004/n/asserv/src/motor.c402
-rw-r--r--2004/n/asserv/src/motor.h91
-rw-r--r--2004/n/asserv/src/serial.c149
-rw-r--r--2004/n/asserv/src/serial.h86
6 files changed, 846 insertions, 0 deletions
diff --git a/2004/n/asserv/src/README b/2004/n/asserv/src/README
new file mode 100644
index 0000000..6b8b31d
--- /dev/null
+++ b/2004/n/asserv/src/README
@@ -0,0 +1,3 @@
+APBTasserv - asservissement Robot 2004
+
+Merci à l'ANCR et Fribotte pour la doc et les exemples.
diff --git a/2004/n/asserv/src/main.c b/2004/n/asserv/src/main.c
new file mode 100644
index 0000000..1dd817e
--- /dev/null
+++ b/2004/n/asserv/src/main.c
@@ -0,0 +1,115 @@
+/* main.c */
+/* APBTasserv - asservissement Robot 2004 {{{
+ *
+ * Copyright (C) 2003 Nicolas Schodet
+ *
+ * Robot APB Team/Efrei 2004.
+ * Web: http://assos.efrei.fr/robot/
+ * Mail: robot AT efrei DOT fr
+ *
+ * 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.
+ *
+ * }}} */
+#include <18f442.h> // Définition des registres du PIC18
+#include <stdlib.h> // Définition de la librairie standard
+
+// Pattes libres.
+/*
+40 rb7 (coupee)
+39 rb6 : D3
+38 rb5 : D2
+37 rb4 : D1
+36 rb3 : D0
+35 rb2 : Clk busp
+30 rd7
+29 rd6 : Capteur sharp
+28 rd5 : Capteur doigts
+27 rd4 : Capteur couleur
+24 rc5
+23 rc4
+22 rd3 : Jack
+21 rd2
+18 rc3
+10 re2
+9 re1
+8 re0
+7 ra5
+5 ra3
+4 ra2
+3 ra1
+
+A1-5 B2-7 C4-5 D2-6 E0-2
+*/
+
+// General configuration
+#fuses HS,WDT,WDT128,PUT,NOBROWNOUT,NOLVP
+#use delay(clock=20000000)
+#use rs232(baud=115200,xmit=PIN_C6,parity=N,rcv=PIN_C7,bits=8)
+#priority EXT,EXT1,RDA,TIMER2
+
+#include "motor.c"
+#include "serial.c"
+
+/* Initialise le PIC. */
+void
+main_init (void)
+{
+ /* Configuration de la liaison série. */
+ setup_psp (PSP_DISABLED);
+ /* Configuration de l'interface SPI : non utilisée. */
+ setup_spi (FALSE);
+ // Configuration du chien de garde
+ //setup_wdt (WDT_OFF);
+ // Configuration du TIMER 0 pour lire le nombre de pas faits en reculant
+ setup_timer_0 (RTCC_EXT_L_TO_H | RTCC_8_BIT | RTCC_DIV_1);
+ // Confguration du TIMER 1 pour lire le nombre de pas faits en avançant
+ setup_timer_1 (T1_DISABLED);
+ // Configuration du TIMER 2.
+ // Tpwm = (PR2 + 1) * 4 * Tosc * TMR2_prescale
+ // Fpwm = 20kHz
+ // Tint2 = TMR2_postscale * Tpwm
+ // Tint2 = 0,5ms
+ setup_timer_2 (T2_DIV_BY_1, 249, 10);
+ // Configuration du TIMER 3 : non utilisé
+ setup_timer_3 (T3_EXTERNAL | T3_DIV_BY_1);
+ // Configuration de l'ADC
+ setup_adc_ports (NO_ANALOGS);
+ setup_adc (ADC_CLOCK_DIV_2);
+ // Configuration des registres pour un fonctionnement en PWM
+ setup_ccp1 (CCP_PWM);
+ setup_ccp2 (CCP_PWM);
+ set_pwm1_duty (0);
+ set_pwm2_duty (0);
+ // Configuration pour l'autorisation des interruptions.
+ enable_interrupts (INT_EXT);
+ enable_interrupts (INT_EXT1);
+ enable_interrupts (INT_TIMER2);
+ enable_interrupts (INT_RDA);
+ enable_interrupts (GLOBAL);
+ // Heu, on s'en servait pour le bus...
+ //output_low (PIN_B2);
+}
+
+void
+main (void)
+{
+ delay_ms (20);
+ motor_init ();
+ serial_init ();
+ main_init ();
+ while (1)
+ {
+ }
+}
diff --git a/2004/n/asserv/src/motor.c b/2004/n/asserv/src/motor.c
new file mode 100644
index 0000000..94954f2
--- /dev/null
+++ b/2004/n/asserv/src/motor.c
@@ -0,0 +1,402 @@
+/* motor.c */
+/* APBTasserv - asservissement Robot 2004 {{{
+ *
+ * Copyright (C) 2003 Nicolas Schodet
+ *
+ * Robot APB Team/Efrei 2004.
+ * Web: http://assos.efrei.fr/robot/
+ * Mail: robot AT efrei DOT fr
+ *
+ * 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.
+ *
+ * }}} */
+#include "motor.h"
+#include "serial.h"
+
+/* Variables globales. */
+signed long motor_ttl; /* Time to live : arrète le robot au bout de
+ ce nombre de pas. */
+short motor_asservi; /* Asservissement activé ? */
+unsigned int motor_kp, motor_ki, motor_kd; /* Coefficients du PID. */
+unsigned int motor_a; /* Acceleration. */
+signed long motor_int_max; /* Terme intégral maximum. */
+unsigned int motor_pid_int; /* Compteur d'interruptions 2 entre deux
+ calculs de PID. */
+
+/* Statistiques, etc... */
+short motor_stat; /* Report motor stats. */
+unsigned int motor_stat_delay; /* Delay between stats. */
+unsigned int motor_stat_delay_cpt; /* Delay counter. */
+
+/* Moteurs. */
+signed int motor_g_vdes, motor_g_vacc; /* Vitesse désirée, actuelle. */
+signed int motor_d_vdes, motor_d_vacc;
+unsigned int motor_g_cpt_av, motor_g_cpt_ar; /* Compteur pour les interruptions. */
+unsigned int motor_d_cpt_av, motor_d_cpt_ar;
+signed long motor_g_cpt, motor_d_cpt; /* Compteurs. */
+signed long motor_g_e_old, motor_d_e_old; /* Dernière erreur, pour le
+ calcul de la dérivée. */
+signed long motor_g_int, motor_d_int; /* Valeur integrale. */
+
+/* Initialise le modue moteur. */
+void
+motor_init (void)
+{
+ motor_ttl = 2000;
+ motor_asservi = 0;
+ motor_kp = 10; motor_ki = 5; motor_kd = 0;
+ motor_a = 2;
+ motor_int_max = 1000;
+ motor_pid_int = 0;
+ motor_stat = 0;
+ motor_stat_delay = 101;
+ motor_stat_delay_cpt = 0;
+ motor_g_vdes = 0; motor_g_vacc = 0;
+ motor_d_vdes = 0; motor_d_vacc = 0;
+ motor_g_cpt_av = 0; motor_g_cpt_ar = 0;
+ motor_d_cpt_av = 0; motor_d_cpt_ar = 0;
+ motor_g_cpt = 0; motor_d_cpt = 0;
+ motor_g_e_old = 0; motor_d_e_old = 0;
+ motor_g_int = 0; motor_d_int = 0;
+}
+
+/* Addition limitée à 32000. */
+signed long
+safe_add_long (signed long &a, signed long &b)
+{
+ signed long ret;
+ /* Additionne. */
+ ret = a + b;
+ /* Vérifie les débordements par cohérence des signes. */
+ if (a > 0 && b > 0 && ret <= 0)
+ return 32000;
+ else if (a < 0 && b < 0 && ret >= 0)
+ return -32000;
+ else
+ return ret;
+}
+
+/* Limite un entier entre -MAX et MAX. */
+signed long
+boundary (signed long &n, signed long &max)
+{
+ if (n > max)
+ return max;
+ if (n < -max)
+ return -max;
+ return n;
+}
+
+/* Multiplication par les coef. */
+signed long
+safe_mul_long (signed long &a, unsigned int &k)
+{
+ unsigned long ua;
+ short sa;
+ signed long temp;
+ /* Sépare le signe de la valeur absolue. */
+ if (a >= 0)
+ {
+ sa = 1;
+ ua = a;
+ }
+ else
+ {
+ sa = 0;
+ ua = -a;
+ }
+ /* Multiplie le poid fort. */
+ temp = make8 (ua, 1) * k;
+ /* Test un futur débordement. */
+ if (temp > 255)
+ {
+ if (sa) return 32760;
+ else return -32760;
+ }
+ else
+ {
+ temp = make8 (temp, 1);
+ temp += ((long) make8 (ua, 0)) * k ;
+ if (sa) return temp;
+ else return -temp;
+ }
+}
+
+/* Met à jour la vitesse du moteur gauche. */
+void
+motor_update_left_speed (void)
+{
+ if (motor_g_vacc != motor_g_vdes)
+ {
+ if (motor_g_vacc < motor_g_vdes)
+ {
+ /* Accélère. */
+ motor_g_vacc += motor_a;
+ if (motor_g_vacc > motor_g_vdes)
+ motor_g_vacc = motor_g_vdes;
+ }
+ else
+ {
+ /* Freine. */
+ motor_g_vacc -= motor_a;
+ if (motor_g_vacc < motor_g_vdes)
+ motor_g_vacc = motor_g_vdes;
+ }
+ }
+}
+
+/* Met à jour la vitesse du moteur droit. */
+void
+motor_update_right_speed (void)
+{
+ if (motor_d_vacc != motor_d_vdes)
+ {
+ if (motor_d_vacc < motor_d_vdes)
+ {
+ /* Accélère. */
+ motor_d_vacc += motor_a;
+ if (motor_d_vacc > motor_d_vdes)
+ motor_d_vacc = motor_d_vdes;
+ }
+ else
+ {
+ /* Freine. */
+ motor_d_vacc -= motor_a;
+ if (motor_d_vacc < motor_d_vdes)
+ motor_d_vacc = motor_d_vdes;
+ }
+ }
+}
+
+/* Calcule le PID associé au moteur gauche. */
+void
+motor_compute_left_pid (void)
+{
+ signed long e;
+ signed long diff;
+ signed long pwm;
+ signed long temp;
+ unsigned char av, ar;
+ /* Récupère les compteurs. */
+ disable_interrupts (INT_EXT);
+ av = motor_g_cpt_av;
+ motor_g_cpt_av = 0;
+ enable_interrupts (INT_EXT);
+ disable_interrupts (INT_EXT1);
+ ar = motor_g_cpt_ar;
+ motor_g_cpt_ar = 0;
+ enable_interrupts (INT_EXT1);
+ /* Calcule l'erreur. */
+ diff = av;
+ diff -= ar;
+ motor_g_cpt += diff;
+ e = motor_g_vacc - diff;
+ /* Calcul de l'integrale. */
+ motor_g_int = safe_add_long (motor_g_int, e);
+ motor_g_int = boundary (motor_g_int, motor_int_max);
+ /* Calcul du PID. */
+ pwm = safe_mul_long (e, motor_kp);
+ temp = safe_mul_long (motor_g_int, motor_ki);
+ pwm = safe_add_long (pwm, temp);
+ temp = 1000;
+ pwm = boundary (pwm, temp);
+ /* Envois la sauce. */
+ motor_g_pwm (pwm);
+ /* Information de PWM. */
+ if (motor_stat)
+ {
+ if (!motor_stat_delay_cpt--)
+ {
+ serial_send_motor_stat ('l', motor_g_vacc, e, pwm);
+ motor_stat_delay_cpt = motor_stat_delay;
+ }
+ }
+ /* Conserve l'ancienne erreur pour le terme dérivé. */
+ //motor_g_old_e = e;
+}
+
+/* Calcule le PID associé au moteur droit. */
+void
+motor_compute_right_pid (void)
+{
+ signed long e;
+ signed long diff;
+ signed long pwm;
+ signed long temp;
+ unsigned char av, ar;
+ /* Récupère les compteurs. */
+ av = get_timer0 ();
+ ar = get_timer3 ();
+ /* Calcule l'erreur. */
+ diff = av;
+ diff -= motor_d_cpt_av;
+ if (av < motor_d_cpt_av) diff += 256;
+ diff -= ar;
+ diff += motor_d_cpt_ar;
+ if (ar < motor_d_cpt_ar) diff -= 256;
+ motor_d_cpt += diff;
+ e = motor_d_vacc - diff;
+ /* Sauvegarde les compteurs. */
+ motor_d_cpt_av = av;
+ motor_d_cpt_ar = ar;
+ /* Calcul de l'integrale. */
+ motor_d_int = safe_add_long (motor_d_int, e);
+ motor_d_int = boundary (motor_d_int, motor_int_max);
+ /* Calcul du PID. */
+ pwm = safe_mul_long (e, motor_kp);
+ temp = safe_mul_long (motor_d_int, motor_ki);
+ pwm = safe_add_long (pwm, temp);
+ temp = 1000;
+ pwm = boundary (pwm, temp);
+ /* Envois la sauce. */
+ motor_d_pwm (pwm);
+ /* Information de PWM. */
+ if (motor_stat)
+ {
+ if (!motor_stat_delay_cpt--)
+ {
+ serial_send_motor_stat ('r', motor_d_vacc, e, pwm);
+ motor_stat_delay_cpt = motor_stat_delay;
+ }
+ }
+ /* Conserve l'ancienne erreur pour le terme dérivé. */
+ //motor_d_old_e = e;
+}
+
+/* Paramètre la PWM pour le moteur gauche. */
+void
+motor_g_pwm (signed long &pwm)
+{
+ if (!motor_asservi) pwm = 0;
+ if (pwm >= 0)
+ {
+ output_high (PIN_D1);
+ set_pwm2_duty(pwm);
+ }
+ else
+ {
+ output_low (PIN_D1);
+ set_pwm2_duty (-pwm);
+ }
+}
+
+/* Paramètre la PWM pour le moteur droit. */
+void
+motor_d_pwm (signed long &pwm)
+{
+ if (!motor_asservi) pwm = 0;
+ if (pwm >= 0)
+ {
+ output_high (PIN_D0);
+ set_pwm1_duty(pwm);
+ }
+ else
+ {
+ output_low (PIN_D0);
+ set_pwm1_duty (-pwm);
+ }
+}
+
+/* Interruptions de comptage moteur. */
+#int_EXT
+EXT_isr()
+{
+ motor_g_cpt_av++;
+}
+
+#int_EXT1
+EXT1_isr()
+{
+ motor_g_cpt_ar++;
+}
+
+/* Interruption de PID. */
+#int_TIMER2
+TIMER2_isr ()
+{
+ if ((motor_pid_int & 7) == 0)
+ {
+ motor_compute_left_pid ();
+ motor_compute_right_pid ();
+ }
+ if ((motor_pid_int & 63) == 0)
+ {
+ motor_update_left_speed ();
+ motor_update_right_speed ();
+ serial_parse ();
+ }
+ motor_pid_int++;
+}
+
+/* Traite une entrée série. */
+short
+motor_parse (void)
+{
+ switch (serial_recv_com ())
+ {
+ case 'v':
+ serial_recv_int (motor_g_vdes);
+ serial_recv_int1 (motor_d_vdes);
+ serial_send_ok ('v');
+ return 1;
+ case 's':
+ motor_g_vdes = 0;
+ motor_d_vdes = 0;
+ serial_send_ok ('s');
+ return 1;
+ case 'a':
+ serial_recv_int (motor_a);
+ serial_send_ok ('a');
+ return 1;
+ case 'p':
+ serial_recv_int (motor_kp);
+ serial_send_ok ('p');
+ return 1;
+ case 'i':
+ serial_recv_int (motor_ki);
+ serial_send_ok ('i');
+ return 1;
+ case 'm':
+ serial_recv_bool (motor_stat);
+ serial_send_ok ('m');
+ return 1;
+ case 'g':
+ serial_recv_bool (motor_asservi);
+ motor_toggle_asservi ();
+ serial_send_ok ('g');
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Démarre l'asservissement. */
+void
+motor_toggle_asservi (void)
+{
+ if (motor_asservi)
+ {
+ motor_g_cpt_av = 0;
+ motor_g_cpt_ar = 0;
+ motor_d_cpt_av = get_timer0 ();
+ motor_d_cpt_ar = get_timer3 ();
+ motor_g_vacc = 0;
+ motor_d_vdes = 0;
+ motor_g_vdes = 0;
+ motor_d_vdes = 0;
+ motor_g_int = 0;
+ motor_d_int = 0;
+ }
+}
diff --git a/2004/n/asserv/src/motor.h b/2004/n/asserv/src/motor.h
new file mode 100644
index 0000000..92b1680
--- /dev/null
+++ b/2004/n/asserv/src/motor.h
@@ -0,0 +1,91 @@
+#ifndef motor_h
+#define motor_h
+/* motor.h */
+/* APBTasserv - asservissement Robot 2004 {{{
+ *
+ * Copyright (C) 2003 Nicolas Schodet
+ *
+ * Robot APB Team/Efrei 2004.
+ * Web: http://assos.efrei.fr/robot/
+ * Mail: robot AT efrei DOT fr
+ *
+ * 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.
+ *
+ * }}} */
+
+/* +AutoDec */
+
+/* Initialise le modue moteur. */
+void
+motor_init (void);
+
+/* Addition limitée à 32000. */
+signed long
+safe_add_long (signed long &a, signed long &b);
+
+/* Limite un entier entre -MAX et MAX. */
+signed long
+boundary (signed long &n, signed long &max);
+
+/* Multiplication par les coef. */
+signed long
+safe_mul_long (signed long &a, unsigned int &k);
+
+/* Met à jour la vitesse du moteur gauche. */
+void
+motor_update_left_speed (void);
+
+/* Met à jour la vitesse du moteur droit. */
+void
+motor_update_right_speed (void);
+
+/* Calcule le PID associé au moteur gauche. */
+void
+motor_compute_left_pid (void);
+
+/* Calcule le PID associé au moteur droit. */
+void
+motor_compute_right_pid (void);
+
+/* Paramètre la PWM pour le moteur gauche. */
+void
+motor_g_pwm (signed long &pwm);
+
+/* Paramètre la PWM pour le moteur droit. */
+void
+motor_d_pwm (signed long &pwm);
+
+/* Interruptions de comptage moteur. */
+#int_EXT
+EXT_isr();
+
+#int_EXT1
+EXT1_isr();
+
+/* Interruption de PID. */
+#int_TIMER2
+TIMER2_isr ();
+
+/* Traite une entrée série. */
+short
+motor_parse (void);
+
+/* Démarre l'asservissement. */
+void
+motor_toggle_asservi (short fl);
+
+/* -AutoDec */
+
+#endif /* motor_h */
diff --git a/2004/n/asserv/src/serial.c b/2004/n/asserv/src/serial.c
new file mode 100644
index 0000000..a72f7db
--- /dev/null
+++ b/2004/n/asserv/src/serial.c
@@ -0,0 +1,149 @@
+/* serial.c */
+/* APBTasserv - asservissement Robot 2004 {{{
+ *
+ * Copyright (C) 2003 Nicolas Schodet
+ *
+ * Robot APB Team/Efrei 2004.
+ * Web: http://assos.efrei.fr/robot/
+ * Mail: robot AT efrei DOT fr
+ *
+ * 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.
+ *
+ * }}} */
+#include "serial.h"
+#include "motor.h"
+
+/* Macros de lecture du tampon. */
+#define HEXDIGIT(a) ((a) <= 9 ? (a) + '0' : (a) + ('a' - 10))
+#define SERIAL2INT(a, b) (HEX (a) << 4 | HEX (b))
+
+#define CRLF "\r"
+
+/* Tampon de reception. */
+char serial_recv_buf[SERIAL_RECV_BUF_LEN];
+int serial_recv_buf_n;
+short serial_recv_full, serial_recv_working;
+
+/* Tampon d'emmission. */
+#define SERIAL_SEND_BUF_LEN 20
+char serial_send_buf[SERIAL_SEND_BUF_LEN];
+int serial_send_buf_n;
+short serial_send_full, serial_send_working;
+
+/* Initialise la reception serie. */
+void
+serial_init (void)
+{
+ serial_recv_buf_n = 0;
+ serial_recv_full = 0;
+ serial_recv_working = 0;
+ serial_send_buf_n = 0;
+ serial_send_full = 0;
+ serial_send_working = 0;
+ printf ("!z" CRLF);
+}
+
+/* Recois des caractères. */
+#int_RDA
+serial_recv ()
+{
+ char c;
+ if (serial_recv_full) return;
+ c = getc ();
+ if (c == '\n' || c == '\r')
+ {
+ if (serial_recv_buf_n)
+ serial_recv_full = 1;
+ }
+ else if (c == '!' || serial_recv_buf_n >= SERIAL_RECV_BUF_LEN)
+ serial_recv_buf_n = 0;
+ else
+ serial_recv_buf[serial_recv_buf_n++] = c;
+}
+
+/* Traite la commande recue. */
+void
+serial_parse (void)
+{
+ restart_wdt ();
+ /* Si le tampon n'est pas plein, bye, bye. */
+ if (!serial_recv_full || serial_recv_working) return;
+ serial_recv_working = 1;
+ /* Vérifie la taille du tampon. */
+ if (serial_recv_buf_n)
+ {
+ /* Est-ce une commande moteur. */
+ if (!motor_parse ())
+ {
+ switch (serial_recv_com ())
+ {
+ case 'z':
+ reset_cpu ();
+ break;
+ default:
+ serial_send_error ('?');
+ break;
+ }
+ }
+ }
+ serial_recv_buf_n = 0;
+ serial_recv_working = 0;
+ serial_recv_full = 0;
+}
+
+/* Envoie un code d'erreur. */
+void
+serial_send_error (char c)
+{
+ printf ("!e%c" CRLF, c);
+}
+
+/* Envoie un code ok. */
+void
+serial_send_ok (char c)
+{
+ printf ("!o%c" CRLF, c);
+}
+
+/* Envoie un rapport d'un moteur. */
+void
+serial_send_motor_stat (char side, unsigned int vacc, unsigned long &e, unsigned long &pwm)
+{
+ printf ("!m%c", side);
+ serial_send_int (vacc);
+ putc (',');
+ serial_send_long (e);
+ putc (',');
+ serial_send_long (pwm);
+ puts (CRLF);
+}
+
+/* Envoie un long. */
+void
+serial_send_long (unsigned long &value)
+{
+ putc (HEXDIGIT ((make8 (value, 1) >> 4) & 0xf));
+ putc (HEXDIGIT (make8 (value, 1) & 0xf));
+ putc (HEXDIGIT ((make8 (value, 0) >> 4) & 0xf));
+ putc (HEXDIGIT (make8 (value, 0) & 0xf));
+}
+
+/* Envoie un int. */
+void
+serial_send_int (unsigned int &value)
+{
+ putc (HEXDIGIT ((value >> 4) & 0xf));
+ putc (HEXDIGIT (value & 0xf));
+}
diff --git a/2004/n/asserv/src/serial.h b/2004/n/asserv/src/serial.h
new file mode 100644
index 0000000..e06c1f0
--- /dev/null
+++ b/2004/n/asserv/src/serial.h
@@ -0,0 +1,86 @@
+#ifndef serial_h
+#define serial_h
+/* serial.h */
+/* APBTasserv - asservissement Robot 2004 {{{
+ *
+ * Copyright (C) 2003 Nicolas Schodet
+ *
+ * Robot APB Team/Efrei 2004.
+ * Web: http://assos.efrei.fr/robot/
+ * Mail: robot AT efrei DOT fr
+ *
+ * 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.
+ *
+ * }}} */
+
+/* Tampon de reception. */
+#define SERIAL_RECV_BUF_LEN 20
+extern char serial_recv_buf[SERIAL_RECV_BUF_LEN];
+extern int serial_recv_buf_n;
+
+/* Macros de récupération de la commande recu. */
+#define HEXBIN(a) (((a) >= '0' && (a) <= '9') ? (a) - '0' : (a) - ('a' + 10))
+#define serial_recv_com() \
+ (serial_recv_buf[0])
+#define serial_recv_int(v) \
+ ((v) = HEXBIN (serial_recv_buf[1]) << 4 | HEXBIN (serial_recv_buf[2]))
+#define serial_recv_int1(v) \
+ ((v) = HEXBIN (serial_recv_buf[3]) << 4 | HEXBIN (serial_recv_buf[4]))
+#define serial_recv_long(v) \
+ ((v) = make16 (HEXBIN (serial_recv_buf[0]) << 4 | HEXBIN \
+ (serial_recv_buf[1]), \
+ HEXBIN (serial_recv_buf[2]) << 4 | HEXBIN \
+ (serial_recv_buf[3])))
+#define serial_recv_bool(v) \
+ ((v) = serial_recv_buf[1] == '1')
+
+
+/* +AutoDec */
+
+/* Initialise la reception serie. */
+void
+serial_init (void);
+
+/* Recois des caractères. */
+#int_RDA
+serial_recv ();
+
+/* Traite la commande recue. */
+void
+serial_parse (void);
+
+/* Envoie un code d'erreur. */
+void
+serial_send_error (char c);
+
+/* Envoie un code ok. */
+void
+serial_send_ok (char c);
+
+/* Envoie un rapport d'un moteur. */
+void
+serial_send_motor_stat (char side, unsigned int vacc, unsigned long &e, unsigned long &pwm);
+
+/* Envoie un long. */
+void
+serial_send_long (unsigned long &value);
+
+/* Envoie un int. */
+void
+serial_send_int (unsigned int &value);
+
+/* -AutoDec */
+
+#endif /* serial_h */