+++ /dev/null
-/*
- * Copyright Droids Corporation (2009)
- *
- * 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
- *
- * Revision : $Id: state.c,v 1.5 2009-11-08 17:25:00 zer0 Exp $
- *
- */
-
-#include <math.h>
-#include <string.h>
-
-#include <aversive.h>
-#include <aversive/wait.h>
-#include <aversive/error.h>
-
-#include <ax12.h>
-#include <uart.h>
-#include <spi.h>
-#include <encoders_spi.h>
-#include <pwm_ng.h>
-#include <timer.h>
-#include <scheduler.h>
-#include <time.h>
-
-#include <pid.h>
-#include <quadramp.h>
-#include <control_system_manager.h>
-#include <blocking_detection_manager.h>
-
-#include <rdline.h>
-#include <vt100.h>
-
-#include "../common/i2c_commands.h"
-#include "main.h"
-#include "cmdline.h"
-#include "sensor.h"
-#include "actuator.h"
-#include "arm_xy.h"
-#include "arm_highlevel.h"
-#include "state.h"
-
-#define STMCH_DEBUG(args...) DEBUG(E_USER_ST_MACH, args)
-#define STMCH_NOTICE(args...) NOTICE(E_USER_ST_MACH, args)
-#define STMCH_ERROR(args...) ERROR(E_USER_ST_MACH, args)
-
-/* shorter aliases for this file */
-#define MANUAL I2C_MECHBOARD_MODE_MANUAL
-#define HARVEST I2C_MECHBOARD_MODE_HARVEST
-#define PREPARE_PICKUP I2C_MECHBOARD_MODE_PREPARE_PICKUP
-#define PICKUP I2C_MECHBOARD_MODE_PICKUP
-#define PREPARE_BUILD I2C_MECHBOARD_MODE_PREPARE_BUILD
-#define AUTOBUILD I2C_MECHBOARD_MODE_AUTOBUILD
-#define WAIT I2C_MECHBOARD_MODE_WAIT
-#define INIT I2C_MECHBOARD_MODE_INIT
-#define PREPARE_GET_LINTEL I2C_MECHBOARD_MODE_PREPARE_GET_LINTEL
-#define GET_LINTEL I2C_MECHBOARD_MODE_GET_LINTEL
-#define PUT_LINTEL I2C_MECHBOARD_MODE_PUT_LINTEL
-#define PREPARE_EJECT I2C_MECHBOARD_MODE_PREPARE_EJECT
-#define EJECT I2C_MECHBOARD_MODE_EJECT
-#define CLEAR I2C_MECHBOARD_MODE_CLEAR
-#define LAZY_HARVEST I2C_MECHBOARD_MODE_LAZY_HARVEST
-#define LOADED I2C_MECHBOARD_MODE_LOADED
-#define PREPARE_INSIDE I2C_MECHBOARD_MODE_PREPARE_INSIDE
-#define STORE I2C_MECHBOARD_MODE_STORE
-#define LAZY_PICKUP I2C_MECHBOARD_MODE_LAZY_PICKUP
-#define MANIVELLE I2C_MECHBOARD_MODE_MANIVELLE
-#define PUSH_TEMPLE I2C_MECHBOARD_MODE_PUSH_TEMPLE
-#define PUSH_TEMPLE_DISC I2C_MECHBOARD_MODE_PUSH_TEMPLE_DISC
-#define EXIT I2C_MECHBOARD_MODE_EXIT
-
-static void state_do_eject(uint8_t arm_num, uint8_t pump_num, uint8_t old_mode);
-
-static struct i2c_cmd_mechboard_set_mode mainboard_command;
-static struct vt100 local_vt100;
-static volatile uint8_t prev_state;
-static uint8_t pickup_side;
-static volatile uint8_t changed = 0;
-
-uint8_t state_debug = 0;
-
-void state_dump_sensors(void)
-{
- uint16_t tmp = sensor_get_all();
- prog_char *front = PSTR("no_front");
- prog_char *left = PSTR("no_left");
- prog_char *right = PSTR("no_right");
-
- if (tmp & _BV(S_FRONT))
- front = PSTR("FRONT");
- if (tmp & _BV(S_LEFT)) {
- if (tmp & _BV(S_COL_LEFT))
- left = PSTR("LEFT(red)");
- else
- left = PSTR("LEFT(green)");
- }
- if (tmp & _BV(S_RIGHT)) {
- if (tmp & _BV(S_COL_RIGHT))
- right = PSTR("RIGHT(red)");
- else
- right = PSTR("RIGHT(green)");
- }
-
- STMCH_DEBUG("sensors = %S %S %S", front, left, right);
-}
-
-/* return 1 if column is there */
-uint8_t arm_get_sensor(uint8_t arm_num)
-{
- if (arm_num == ARM_LEFT_NUM) {
- return sensor_get(S_LEFT);
- }
- else if (arm_num == ARM_RIGHT_NUM) {
- return sensor_get(S_RIGHT);
- }
- return 0;
-}
-
-/* return 0 if color is correct, else return -1 */
-int8_t arm_get_color_sensor(uint8_t arm_num)
-{
- uint8_t col = 0;
- if (arm_num == ARM_LEFT_NUM) {
- col = sensor_get(S_COL_LEFT);
- }
- else if (arm_num == ARM_RIGHT_NUM) {
- col = sensor_get(S_COL_RIGHT);
- }
-
- /* if col != 0, column is red */
- if (col) {
- if (mechboard.our_color == I2C_COLOR_RED)
- return 0;
- return -1;
- }
- else {
- if (mechboard.our_color == I2C_COLOR_GREEN)
- return 0;
- return -1;
- }
-}
-
-void state_debug_wait_key_pressed(void)
-{
- if (!state_debug)
- return;
- printf_P(PSTR("press a key\r\n"));
- while(!cmdline_keypressed());
-}
-
-/* set a new state, return 0 on success */
-int8_t state_set_mode(struct i2c_cmd_mechboard_set_mode *cmd)
-{
- changed = 1;
- prev_state = mainboard_command.mode;
- memcpy(&mainboard_command, cmd, sizeof(mainboard_command));
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, mainboard_command.mode);
- return 0;
-}
-
-/* check that state is the one in parameter and that state did not
- * changed */
-uint8_t state_check(uint8_t mode)
-{
- int16_t c;
- if (mode != mainboard_command.mode)
- return 0;
-
- if (changed)
- return 0;
-
- /* force quit when CTRL-C is typed */
- c = cmdline_getchar();
- if (c == -1)
- return 1;
- if (vt100_parser(&local_vt100, c) == KEY_CTRL_C) {
- mainboard_command.mode = EXIT;
- return 0;
- }
- return 1;
-}
-
-uint8_t state_get_mode(void)
-{
- return mainboard_command.mode;
-}
-
-void pump_reset_all(void)
-{
- uint8_t i;
- for (i=0; i<4; i++) {
- pump_set(i, PUMP_OFF);
- pump_mark_free(i);
- }
-}
-
-void pump_check_all(void)
-{
- if (pump_is_busy(PUMP_LEFT1_NUM) &&
- mechboard.pump_left1_current < I2C_MECHBOARD_CURRENT_COLUMN) {
- STMCH_DEBUG("Mark l1 as free");
- pump_mark_free(PUMP_LEFT1_NUM);
- pump_set(PUMP_LEFT1_NUM, PUMP_OFF);
- }
-
- if (pump_is_busy(PUMP_LEFT2_NUM) &&
- mechboard.pump_left2_current < I2C_MECHBOARD_CURRENT_COLUMN) {
- STMCH_DEBUG("Mark l2 as free");
- pump_mark_free(PUMP_LEFT2_NUM);
- pump_set(PUMP_LEFT2_NUM, PUMP_OFF);
- }
-
- if (pump_is_busy(PUMP_RIGHT1_NUM) &&
- sensor_get_adc(ADC_CSENSE3) < I2C_MECHBOARD_CURRENT_COLUMN) {
- STMCH_DEBUG("Mark r1 as free");
- pump_mark_free(PUMP_RIGHT1_NUM);
- pump_set(PUMP_RIGHT1_NUM, PUMP_OFF);
- }
-
- if (pump_is_busy(PUMP_RIGHT2_NUM) &&
- sensor_get_adc(ADC_CSENSE4) < I2C_MECHBOARD_CURRENT_COLUMN) {
- STMCH_DEBUG("Mark r2 as free");
- pump_mark_free(PUMP_RIGHT2_NUM);
- pump_set(PUMP_RIGHT2_NUM, PUMP_OFF);
- }
-}
-
-uint8_t get_free_pump_count(void)
-{
- uint8_t i, free_pump_count = 0;
- for (i=0; i<4; i++) {
- if (pump_is_free(i))
- free_pump_count++;
- }
- return free_pump_count;
-}
-
-/* move finger if we are not in lazy harvest */
-void state_finger_goto(uint8_t mode, uint16_t position)
-{
- if (mode == LAZY_HARVEST)
- return;
- finger_goto(position);
-}
-
-void state_manivelle(int16_t step_deg)
-{
- double add_h = 0.;
- double add_d = 160.;
- double l = 70.;
- double step = RAD(step_deg);
- microseconds us;
- double al = RAD(0);
- double ar = RAD(180);
-
- time_wait_ms(500);
-
- us = time_get_us2();
- while (1) {
- al += step;
- ar += step;
- arm_do_xy(&left_arm, add_d+l*sin(al), add_h+l*cos(al), 10);
- arm_do_xy(&right_arm, add_d+l*sin(ar), add_h+l*cos(ar), 10);
- time_wait_ms(25);
- if (time_get_us2() - us > (4000L * 1000L))
- break;
- }
-}
-
-static void state_do_manivelle(void)
-{
- if (!state_check(MANIVELLE))
- return;
- state_manivelle(30);
- while (state_check(MANIVELLE));
-}
-
-/* common function for pickup/harvest */
-static void state_pickup_or_harvest(uint8_t mode)
-{
- int8_t arm_num, pump_num;
- int8_t other_arm_num, other_pump_num;
- struct arm *arm;
- microseconds us;
- uint8_t flags, bad_color = 0, have_2cols = 0;
-
- pump_check_all();
-
- /* get arm num */
- if (pickup_side == I2C_LEFT_SIDE) {
- arm_num = ARM_LEFT_NUM;
- other_arm_num = ARM_RIGHT_NUM;
- }
- else {
- arm_num = ARM_RIGHT_NUM;
- other_arm_num = ARM_LEFT_NUM;
- }
-
- pump_num = arm_get_free_pump(arm_num);
- other_pump_num = arm_get_free_pump(other_arm_num);
-
- /* pump is not free... skip to other arm */
- if (mode == HARVEST && pump_num == -1) {
- STMCH_DEBUG("%s no free pump", __FUNCTION__);
- if (arm_num == ARM_RIGHT_NUM) {
- state_finger_goto(mode, FINGER_CENTER_RIGHT);
- pickup_side = I2C_LEFT_SIDE;
- }
- else {
- state_finger_goto(mode, FINGER_CENTER_LEFT);
- pickup_side = I2C_RIGHT_SIDE;
- }
- return;
- }
- else if (mode == PICKUP && pump_num == -1) {
- /* or exit when we are in pickup mode */
- IRQ_LOCK(flags);
- if (mainboard_command.mode == mode)
- mainboard_command.mode = WAIT;
- IRQ_UNLOCK(flags);
- }
-
- us = time_get_us2();
- /* wait front sensor */
- if (mode == HARVEST || mode == LAZY_HARVEST) {
- STMCH_DEBUG("%s wait front", __FUNCTION__);
-
- while (1) {
- if (sensor_get(S_FRONT))
- break;
- if (state_check(mode) == 0)
- return;
- /* wait 500ms before reading other
- sensors */
- if (time_get_us2() - us < (500 * 1000L))
- continue;
- if (arm_get_sensor(arm_num))
- break;
- if (arm_get_sensor(other_arm_num)) {
- uint8_t tmp;
- tmp = arm_num;
- arm_num = other_arm_num;
- other_arm_num = tmp;
- pump_num = arm_get_free_pump(arm_num);
- other_pump_num = arm_get_free_pump(other_arm_num);
- if (other_pump_num == -1)
- return; // XXX
- break;
- }
- }
- }
-
-
- STMCH_DEBUG("%s arm_num=%d pump_num=%d",
- __FUNCTION__, arm_num, pump_num);
-
- /* when ready, move finger */
- if (arm_num == ARM_RIGHT_NUM)
- state_finger_goto(mode, FINGER_RIGHT);
- else
- state_finger_goto(mode, FINGER_LEFT);
-
- state_debug_wait_key_pressed();
-
-
- arm = arm_num2ptr(arm_num);
-
- /* prepare arm, should be already done */
- arm_goto_prepare_get(arm_num, pump_num);
- while (arm_test_traj_end(arm, ARM_TRAJ_ALL) &&
- state_check(mode));
-
- STMCH_DEBUG("%s arm pos ok", __FUNCTION__);
-
- state_debug_wait_key_pressed();
-
- /* wait to see the column on the sensor */
- us = time_get_us2();
- while (1) {
- if (arm_get_sensor(arm_num))
- break;
- if (state_check(mode) == 0)
- return;
- if (mode == PICKUP) /* no timeout in pickup */
- continue;
- /* 500ms timeout in harvest, go back */
- if (time_get_us2() - us > 500*1000L) {
- STMCH_DEBUG("%s timeout", __FUNCTION__);
-
- if (arm_num == ARM_RIGHT_NUM)
- state_finger_goto(mode, FINGER_LEFT);
- else
- state_finger_goto(mode, FINGER_RIGHT);
-
- if (sensor_get(S_FRONT))
- time_wait_ms(500);
-
- pump_set(pump_num, PUMP_OFF);
- return;
- }
- }
-
- state_dump_sensors();
-
- pump_set(pump_num, PUMP_ON);
- /* bad color */
- if (arm_get_color_sensor(arm_num) == -1) {
- bad_color = 1;
- STMCH_DEBUG("%s prepare eject", __FUNCTION__);
- mainboard_command.mode = PREPARE_EJECT;
- state_do_eject(arm_num, pump_num, mode);
- return;
- }
-
- STMCH_DEBUG("%s sensor ok", __FUNCTION__);
-
- /* by the way, prepare the other arm */
- if (other_pump_num != -1)
- arm_goto_prepare_get(other_arm_num, other_pump_num);
-
- /* get the column */
- arm_goto_get_column(arm_num, pump_num);
-
- us = time_get_us2();
- while (1) {
- /* wait 50 ms */
- if (time_get_us2() - us > 50*1000L)
- break;
- if (mode != HARVEST)
- continue;
- /* if we still see the front sensor, it's because
- * there are 2 columns instead of one or because there
- * is another column, so send the arm on other
- * side. */
- if (sensor_get(S_FRONT) && have_2cols == 0) {
- STMCH_DEBUG("%s 2 columns, release finger", __FUNCTION__);
- have_2cols = 1;
- if (finger_get_side() == I2C_LEFT_SIDE)
- state_finger_goto(mode, FINGER_RIGHT);
- else
- state_finger_goto(mode, FINGER_LEFT);
- }
- }
-
- if (mode == HARVEST && have_2cols == 0) {
- /* just release a bit of effort */
- if (finger_get_side() == I2C_LEFT_SIDE) {
- state_finger_goto(mode, FINGER_LEFT_RELAX);
- }
- else {
- state_finger_goto(mode, FINGER_RIGHT_RELAX);
- }
- }
- else if (mode == PICKUP) {
- /* no free pump on other arm */
- if (other_pump_num == -1) {
- if (finger_get_side() == I2C_LEFT_SIDE) {
- state_finger_goto(mode, FINGER_LEFT_RELAX);
- }
- else {
- state_finger_goto(mode, FINGER_RIGHT_RELAX);
- }
- }
- /* else send finger on the other side */
- else {
- if (finger_get_side() == I2C_LEFT_SIDE) {
- state_finger_goto(mode, FINGER_RIGHT);
- }
- else {
- state_finger_goto(mode, FINGER_LEFT);
- }
- }
- }
-
- us = time_get_us2();
- while (1) {
- /* wait 100 ms */
- if (time_get_us2() - us > 100*1000L)
- break;
- if (mode != HARVEST)
- continue;
- /* if we still see the front sensor, it's because
- * there are 2 columns instead of one or because there
- * is another column, so send the arm on other
- * side. */
- if (sensor_get(S_FRONT) && have_2cols == 0) {
- STMCH_DEBUG("%s 2 columns, release finger", __FUNCTION__);
- have_2cols = 1;
- if (finger_get_side() == I2C_LEFT_SIDE)
- state_finger_goto(mode, FINGER_RIGHT);
- else
- state_finger_goto(mode, FINGER_LEFT);
- }
- }
-
- /* consider the column as taken */
- pump_mark_busy(pump_num);
-
- state_debug_wait_key_pressed();
-
- arm_goto_intermediate_get(arm_num, pump_num);
- arm_wait_traj_end(arm, ARM_TRAJ_ALL_NEAR);
-
- /* prepare next */
- pump_num = arm_get_free_pump(arm_num);
- if (pump_num == -1)
- arm_goto_loaded(arm_num);
- else
- arm_goto_intermediate_get(arm_num, pump_num);
-
- state_debug_wait_key_pressed();
-
- /* switch to wait state */
- if (get_free_pump_count() == 0) {
- IRQ_LOCK(flags);
- if (mainboard_command.mode == mode)
- mainboard_command.mode = WAIT;
- IRQ_UNLOCK(flags);
- }
-
- /* next pickup/harvest will be on the other side */
- if (pickup_side == I2C_LEFT_SIDE)
- pickup_side = I2C_RIGHT_SIDE;
- else
- pickup_side = I2C_LEFT_SIDE;
-}
-
-
-/* manual mode, arm position is sent from mainboard */
-static void state_do_manual(void)
-{
- if (!state_check(MANUAL))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
- while (state_check(MANUAL));
-}
-
-/* wait mode */
-static void state_do_wait(void)
-{
- if (!state_check(WAIT))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
- while (state_check(WAIT));
-}
-
-/* init mode */
-static void state_do_init(void)
-{
- if (!state_check(INIT))
- return;
- state_init();
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
- while (state_check(INIT));
-}
-
-/* harvest columns elts from area */
-static void state_do_harvest(void)
-{
- if (!state_check(HARVEST))
- return;
-
- if (get_free_pump_count() == 0) {
- mainboard_command.mode = WAIT;
- return;
- }
-
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- state_pickup_or_harvest(HARVEST);
-}
-
-/* harvest columns elts from area without moving finger */
-static void state_do_lazy_harvest(void)
-{
- if (!state_check(LAZY_HARVEST))
- return;
-
- if (get_free_pump_count() == 0) {
- mainboard_command.mode = WAIT;
- return;
- }
-
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- state_pickup_or_harvest(LAZY_HARVEST);
-}
-
-/* eject a column. always called from pickup mode. */
-static void state_do_eject(uint8_t arm_num, uint8_t pump_num, uint8_t old_mode)
-{
- struct arm *arm;
- arm = arm_num2ptr(arm_num);
-
- if (finger_get_side() == I2C_LEFT_SIDE) {
- state_finger_goto(old_mode, FINGER_LEFT_RELAX);
- }
- else {
- state_finger_goto(old_mode, FINGER_RIGHT_RELAX);
- }
-
- /* wait mainboard to eject */
- while (state_check(PREPARE_EJECT));
-
- if (finger_get_side() == I2C_LEFT_SIDE) {
- state_finger_goto(old_mode, FINGER_CENTER_LEFT);
- }
- else {
- state_finger_goto(old_mode, FINGER_CENTER_RIGHT);
- }
-
- arm_goto_get_column(arm_num, pump_num);
- arm_wait_traj_end(arm, ARM_TRAJ_ALL);
- time_wait_ms(150);
-
- state_debug_wait_key_pressed();
-
- arm_goto_prepare_eject(arm_num, pump_num);
- arm_wait_traj_end(arm, ARM_TRAJ_ALL);
-
- state_debug_wait_key_pressed();
-
- if (finger_get_side() == I2C_LEFT_SIDE) {
- state_finger_goto(old_mode, FINGER_LEFT_RELAX);
- }
- else {
- state_finger_goto(old_mode, FINGER_RIGHT_RELAX);
- }
-
- state_debug_wait_key_pressed();
-
- time_wait_ms(300);
- arm_goto_eject(arm_num, pump_num);
- time_wait_ms(200);
- pump_set(pump_num, PUMP_REVERSE);
- arm_wait_traj_end(arm, ARM_TRAJ_ALL);
-
- arm_goto_intermediate_get(arm_num, pump_num);
- pump_set(pump_num, PUMP_OFF);
-}
-
-
-/* prepare pickup in a dispenser, or harvest */
-static void state_do_prepare_pickup(void)
-{
- uint8_t left_count = 0, right_count = 0;
- int8_t pump_l, pump_r;
-
- if (!state_check(PREPARE_PICKUP))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- pump_check_all();
-
- pump_l = arm_get_free_pump(ARM_LEFT_NUM);
- if (pump_l == -1) {
- arm_goto_loaded(ARM_LEFT_NUM);
- }
- else {
- arm_goto_intermediate_front_get(ARM_LEFT_NUM, pump_l);
- }
-
- pump_r = arm_get_free_pump(ARM_RIGHT_NUM);
- if (pump_r == -1) {
- arm_goto_loaded(ARM_RIGHT_NUM);
- }
- else {
- arm_goto_intermediate_front_get(ARM_RIGHT_NUM, pump_r);
- }
-
- arm_wait_both(ARM_TRAJ_ALL);
-
- if (pump_l != -1)
- arm_goto_prepare_get(ARM_LEFT_NUM, pump_l);
- if (pump_r != -1)
- arm_goto_prepare_get(ARM_RIGHT_NUM, pump_r);
-
- if (mainboard_command.prep_pickup.side == I2C_AUTO_SIDE) {
- left_count += pump_is_busy(PUMP_LEFT1_NUM);
- left_count += pump_is_busy(PUMP_LEFT2_NUM);
- right_count += pump_is_busy(PUMP_RIGHT1_NUM);
- right_count += pump_is_busy(PUMP_RIGHT2_NUM);
- if (left_count < right_count)
- finger_goto(FINGER_RIGHT);
- else
- finger_goto(FINGER_LEFT);
- }
- else if (mainboard_command.prep_pickup.side == I2C_LEFT_SIDE)
- finger_goto(FINGER_LEFT);
- else if (mainboard_command.prep_pickup.side == I2C_RIGHT_SIDE)
- finger_goto(FINGER_RIGHT);
- else if (mainboard_command.prep_pickup.side == I2C_CENTER_SIDE)
- finger_goto(FINGER_CENTER_LEFT);
-
- /* try to know on which side we have to pickup */
- if (finger_get_side() == I2C_RIGHT_SIDE) {
- pickup_side = I2C_LEFT_SIDE;
- }
- else {
- pickup_side = I2C_RIGHT_SIDE;
- }
-
- arm_prepare_free_pumps();
-
- mainboard_command.mode = mainboard_command.prep_pickup.next_mode;
-
- while (state_check(PREPARE_PICKUP));
-}
-
-/* clear pickup zone, will switch to harvest if needed */
-static void state_do_clear(void)
-{
- uint8_t flags, err;
-
- if (!state_check(CLEAR))
- return;
-
- if (get_free_pump_count() == 0) {
- mainboard_command.mode = WAIT;
- return;
- }
-
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- finger_goto(FINGER_LEFT);
- err = WAIT_COND_OR_TIMEOUT(sensor_get(S_LEFT), 500);
- if (err) {
- IRQ_LOCK(flags);
- if (mainboard_command.mode == CLEAR)
- mainboard_command.mode = I2C_MECHBOARD_MODE_HARVEST;
- IRQ_UNLOCK(flags);
- pickup_side = I2C_LEFT_SIDE;
- return;
- }
-
- finger_goto(FINGER_RIGHT);
- err = WAIT_COND_OR_TIMEOUT(sensor_get(S_RIGHT), 500);
- if (err) {
- IRQ_LOCK(flags);
- if (mainboard_command.mode == CLEAR)
- mainboard_command.mode = I2C_MECHBOARD_MODE_HARVEST;
- IRQ_UNLOCK(flags);
- pickup_side = I2C_RIGHT_SIDE;
- return;
- }
-
- IRQ_LOCK(flags);
- if (mainboard_command.mode == CLEAR)
- mainboard_command.mode = I2C_MECHBOARD_MODE_HARVEST;
- IRQ_UNLOCK(flags);
-}
-
-/* do a lazy pickup */
-static void state_do_lazy_pickup(void)
-{
- int8_t flags, arm_num, pump_num;
- uint32_t us;
-
- if (!state_check(LAZY_PICKUP))
- return;
-
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- if (arm_get_sensor(ARM_LEFT_NUM) &&
- arm_get_sensor(ARM_RIGHT_NUM)) {
- IRQ_LOCK(flags);
- if (mainboard_command.mode == LAZY_PICKUP) {
- mainboard_command.mode = WAIT;
- }
- IRQ_UNLOCK(flags);
- return;
- }
-
- if (finger_get_side() == I2C_RIGHT_SIDE) {
- finger_goto(FINGER_LEFT);
- arm_num = ARM_LEFT_NUM;
- }
- else {
- finger_goto(FINGER_RIGHT);
- arm_num = ARM_RIGHT_NUM;
- }
-
- us = time_get_us2();
- while(1) {
- if (state_check(LAZY_PICKUP) == 0)
- return;
- if (arm_get_sensor(arm_num))
- break;
- if (time_get_us2() - us > 500*1000L) {
- if (finger_get_side() == I2C_RIGHT_SIDE)
- finger_goto(FINGER_LEFT);
- else
- finger_goto(FINGER_RIGHT);
- return;
- }
- }
-
- if (arm_get_color_sensor(arm_num) == -1) {
- pump_num = arm_get_free_pump(arm_num);
- if (pump_num == -1)
- return; /* XXX */
- pump_set(pump_num, PUMP_ON);
- STMCH_DEBUG("%s prepare eject", __FUNCTION__);
- mainboard_command.mode = PREPARE_EJECT;
- state_do_eject(arm_num, pump_num, LAZY_PICKUP);
- }
-}
-
-/* pickup from a dispenser automatically */
-static void state_do_pickup(void)
-{
- if (!state_check(PICKUP))
- return;
-
- if (get_free_pump_count() == 0) {
- mainboard_command.mode = WAIT;
- return;
- }
-
- /* XXX check that finger is at correct place */
-
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- state_pickup_or_harvest(PICKUP);
-}
-
-/* store columns without using arms */
-static void state_do_store(void)
-{
- int8_t arm_num;
- int8_t other_arm_num;
- microseconds us;
-
- if (!state_check(STORE))
- return;
-
- if (get_free_pump_count() == 0) {
- mainboard_command.mode = WAIT;
- return;
- }
-
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- /* get arm num */
- if (pickup_side == I2C_LEFT_SIDE) {
- arm_num = ARM_LEFT_NUM;
- other_arm_num = ARM_RIGHT_NUM;
- }
- else {
- arm_num = ARM_RIGHT_NUM;
- other_arm_num = ARM_LEFT_NUM;
- }
-
- while (1) {
- if (sensor_get(S_FRONT))
- break;
- if (state_check(STORE) == 0)
- return;
- }
-
- /* when ready, move finger */
- if (arm_num == ARM_RIGHT_NUM)
- finger_goto(FINGER_RIGHT);
- else
- finger_goto(FINGER_LEFT);
-
- /* wait to see the column on the sensor */
- us = time_get_us2();
- while (1) {
- if (arm_get_sensor(arm_num))
- break;
- if (state_check(STORE) == 0)
- return;
- /* 500ms timeout in harvest, go back */
- if (time_get_us2() - us > 500*1000L) {
- STMCH_DEBUG("%s timeout", __FUNCTION__);
-
- if (arm_num == ARM_RIGHT_NUM)
- finger_goto(FINGER_LEFT);
- else
- finger_goto(FINGER_RIGHT);
- return;
- }
- }
-
- if (arm_get_sensor(arm_num) && arm_get_sensor(other_arm_num)) {
- STMCH_DEBUG("%s full", __FUNCTION__);
- while (state_check(STORE));
- return;
- }
-
- /* next store will be on the other side */
- if (pickup_side == I2C_LEFT_SIDE)
- pickup_side = I2C_RIGHT_SIDE;
- else
- pickup_side = I2C_LEFT_SIDE;
-}
-
-/* prepare the building of a temple */
-static void state_do_prepare_build(void)
-{
- int8_t pump_num, level;
- if (!state_check(PREPARE_BUILD))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- pump_check_all();
-
- if (finger_get_side() == I2C_LEFT_SIDE)
- finger_goto(FINGER_LEFT);
- else
- finger_goto(FINGER_RIGHT);
-
- pump_num = arm_get_busy_pump(ARM_LEFT_NUM);
- level = mainboard_command.prep_build.level_l;
- if (pump_num != -1 && level != -1)
- arm_goto_prepare_autobuild_outside(ARM_LEFT_NUM, pump_num,
- level, I2C_AUTOBUILD_DEFAULT_DIST);
-
- pump_num = arm_get_busy_pump(ARM_RIGHT_NUM);
- level = mainboard_command.prep_build.level_r;
- if (pump_num != -1 && level != -1)
- arm_goto_prepare_autobuild_outside(ARM_RIGHT_NUM, pump_num,
- level, I2C_AUTOBUILD_DEFAULT_DIST);
-
- while (state_check(PREPARE_BUILD));
-}
-
-/* prepare the building of a temple */
-static void state_do_push_temple(void)
-{
- uint8_t level;
-
- level = mainboard_command.push_temple.level;
-
- if (!state_check(PUSH_TEMPLE))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- if (finger_get_side() == I2C_LEFT_SIDE)
- finger_goto(FINGER_LEFT);
- else
- finger_goto(FINGER_RIGHT);
-
- arm_goto_prepare_push_temple(ARM_LEFT_NUM);
- arm_goto_prepare_push_temple(ARM_RIGHT_NUM);
- arm_wait_both(ARM_TRAJ_ALL);
-
- arm_goto_push_temple(ARM_LEFT_NUM, level);
- arm_goto_push_temple(ARM_RIGHT_NUM, level);
-
- while (state_check(PUSH_TEMPLE));
-}
-
-/* prepare the building of a temple */
-static void state_do_push_temple_disc(void)
-{
- uint8_t side;
- struct arm *arm;
-
- if (!state_check(PUSH_TEMPLE_DISC))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- side = mainboard_command.push_temple_disc.side;
-
- if (side == I2C_LEFT_SIDE) {
- arm = arm_num2ptr(ARM_LEFT_NUM);
- arm_goto_prepare_push_temple_disc(ARM_LEFT_NUM);
- arm_wait_traj_end(arm, ARM_TRAJ_ALL);
- arm_goto_push_temple_disc(ARM_LEFT_NUM);
- }
- else {
- arm = arm_num2ptr(ARM_RIGHT_NUM);
- arm_goto_prepare_push_temple_disc(ARM_RIGHT_NUM);
- arm_wait_traj_end(arm, ARM_TRAJ_ALL);
- arm_goto_push_temple_disc(ARM_RIGHT_NUM);
- }
-
- while (state_check(PUSH_TEMPLE_DISC));
-}
-
-/* prepare the building of a temple (mainly for columns) */
-static void state_do_prepare_inside(void)
-{
- int8_t pump_num, level_l, level_r;
- if (!state_check(PREPARE_INSIDE))
- return;
-
- level_l = mainboard_command.prep_inside.level_l;
- level_r = mainboard_command.prep_inside.level_r;
- STMCH_DEBUG("%s mode=%d level_l=%d, level_r=%d", __FUNCTION__,
- state_get_mode(), level_l, level_r);
-
- pump_check_all();
-
- if (finger_get_side() == I2C_LEFT_SIDE)
- finger_goto(FINGER_LEFT);
- else
- finger_goto(FINGER_RIGHT);
-
- pump_num = arm_get_busy_pump(ARM_LEFT_NUM);
- if (pump_num == -1)
- pump_num = PUMP_LEFT1_NUM;
- if (level_l != -1)
- arm_goto_prepare_build_inside(ARM_LEFT_NUM, pump_num,
- level_l);
-
- pump_num = arm_get_busy_pump(ARM_RIGHT_NUM);
- if (pump_num == -1)
- pump_num = PUMP_RIGHT1_NUM;
- if (level_r != -1)
- arm_goto_prepare_build_inside(ARM_RIGHT_NUM, pump_num,
- level_r);
-
- while (state_check(PREPARE_INSIDE));
-}
-
-/* moving position */
-static void state_do_loaded(void)
-{
- if (!state_check(LOADED))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- pump_check_all();
-
- if (finger_get_side() == I2C_LEFT_SIDE)
- finger_goto(FINGER_LEFT);
- else
- finger_goto(FINGER_RIGHT);
-
- arm_goto_loaded(ARM_LEFT_NUM);
- arm_goto_loaded(ARM_RIGHT_NUM);
-
- while (state_check(LOADED));
-}
-
-static void state_do_build_lintel(uint8_t level)
-{
- STMCH_DEBUG("%s() level=%d have_lintel=%d",
- __FUNCTION__, level, mechboard.lintel_count);
-
- servo_lintel_out();
-
- arm_goto_prepare_get_lintel_inside1();
- arm_wait_both(ARM_TRAJ_ALL);
- state_debug_wait_key_pressed();
-
- pump_set(PUMP_LEFT1_NUM, PUMP_REVERSE);
- pump_set(PUMP_RIGHT1_NUM, PUMP_REVERSE);
- arm_goto_prepare_get_lintel_inside2(mechboard.lintel_count);
- arm_wait_both(ARM_TRAJ_ALL);
- state_debug_wait_key_pressed();
-
- arm_goto_get_lintel_inside(mechboard.lintel_count);
- arm_wait_both(ARM_TRAJ_ALL);
- state_debug_wait_key_pressed();
-
- time_wait_ms(150);
- arm_goto_prepare_build_lintel1();
- arm_wait_both(ARM_TRAJ_ALL);
- state_debug_wait_key_pressed();
-
- arm_goto_prepare_build_lintel2(level);
- arm_wait_both(ARM_TRAJ_ALL);
- state_debug_wait_key_pressed();
-
- arm_goto_prepare_build_lintel3(level);
- arm_wait_both(ARM_TRAJ_ALL);
- state_debug_wait_key_pressed();
-
- if (mechboard.lintel_count == 1)
- servo_lintel_1lin();
- else
- servo_lintel_2lin();
-
- arm_goto_build_lintel(level);
- arm_wait_both(ARM_TRAJ_ALL);
- time_wait_ms(170);
- pump_set(PUMP_LEFT1_NUM, PUMP_ON);
- time_wait_ms(50); /* right arm a bit after */
- pump_set(PUMP_RIGHT1_NUM, PUMP_ON);
- time_wait_ms(130);
- pump_set(PUMP_LEFT1_NUM, PUMP_OFF);
- pump_set(PUMP_RIGHT1_NUM, PUMP_OFF);
-
- mechboard.lintel_count --;
-}
-
-/* Build one level of column. If pump_r or pump_l is -1, don't build
- * with this arm. */
-static void state_do_build_column(uint8_t level_l, int8_t pump_l,
- uint8_t dist_l,
- uint8_t level_r, int8_t pump_r,
- uint8_t dist_r)
-{
- STMCH_DEBUG("%s() level_l=%d pump_l=%d level_r=%d pump_r=%d",
- __FUNCTION__, level_l, pump_l, level_r, pump_r);
-
- /* nothing to do */
- if (pump_l == -1 && pump_r == -1)
- return;
-
- /* go above the selected level */
- if (pump_l != -1)
- arm_goto_prepare_autobuild_outside(ARM_LEFT_NUM, pump_l, level_l, dist_l);
- if (pump_r != -1)
- arm_goto_prepare_autobuild_outside(ARM_RIGHT_NUM, pump_r, level_r, dist_r);
- STMCH_DEBUG("l=%d r=%d", arm_test_traj_end(&left_arm, ARM_TRAJ_ALL),
- arm_test_traj_end(&right_arm, ARM_TRAJ_ALL));
- arm_wait_select(pump_l != -1, pump_r != -1, ARM_TRAJ_ALL);
- STMCH_DEBUG("l=%d r=%d", arm_test_traj_end(&left_arm, ARM_TRAJ_ALL),
- arm_test_traj_end(&right_arm, ARM_TRAJ_ALL));
-
- state_debug_wait_key_pressed();
-
- /* drop columns of P2 */
- if (pump_l != -1)
- arm_goto_autobuild(ARM_LEFT_NUM, pump_l, level_l, dist_l);
- if (pump_r != -1)
- arm_goto_autobuild(ARM_RIGHT_NUM, pump_r, level_r, dist_r);
- arm_wait_select(pump_l != -1, pump_r != -1, ARM_TRAJ_ALL);
-
- state_debug_wait_key_pressed();
-
- time_wait_ms(150);
- if (pump_l != -1)
- pump_set(pump_l, PUMP_REVERSE);
- if (pump_r != -1)
- pump_set(pump_r, PUMP_REVERSE);
- time_wait_ms(150);
- if (pump_l != -1) {
- pump_set(pump_l, PUMP_OFF);
- pump_mark_free(pump_l);
- }
- if (pump_r != -1) {
- pump_set(pump_r, PUMP_OFF);
- pump_mark_free(pump_r);
- }
-
- state_debug_wait_key_pressed();
-}
-
-/* autobuild columns elts from area */
-/* check level to avoid bad things ? */
-/* check if enough cols ? */
-static void state_do_autobuild(void)
-{
- int8_t pump_l, pump_r;
- /* copy command into local data */
- int8_t level_l = mainboard_command.autobuild.level_left;
- int8_t level_r = mainboard_command.autobuild.level_right;
- uint8_t count_l = mainboard_command.autobuild.count_left;
- uint8_t count_r = mainboard_command.autobuild.count_right;
- uint8_t dist_l = mainboard_command.autobuild.distance_left;
- uint8_t dist_r = mainboard_command.autobuild.distance_right;
- uint8_t do_lintel = mainboard_command.autobuild.do_lintel;
- int8_t max_level = level_l;
-
-
- if (!state_check(AUTOBUILD))
- return;
-
- STMCH_DEBUG("%s mode=%d do_lintel=%d", __FUNCTION__,
- state_get_mode(), do_lintel);
- STMCH_DEBUG(" left: level=%d count=%d", level_l, count_l);
- STMCH_DEBUG(" right: level=%d count=%d", level_r, count_r);
-
- /*
- * build the first level of column if needed
- */
-
- /* don't build with this arm if no pump or if we don't ask to */
- pump_l = arm_get_busy_pump(ARM_LEFT_NUM);
- if (count_l == 0)
- pump_l = -1;
- pump_r = arm_get_busy_pump(ARM_RIGHT_NUM);
- if (count_r == 0)
- pump_r = -1;
-
- if (pump_l == -1 && pump_r == -1)
- goto lintel_only;
-
- state_do_build_column(level_l, pump_l, dist_l,
- level_r, pump_r, dist_r);
-
- /* one level up */
- if (pump_l != -1) {
- count_l --;
- level_l ++;
- max_level = level_l;
- }
- if (pump_r != -1) {
- count_r --;
- level_r ++;
- if (level_r > max_level)
- max_level = level_r;
- }
-
- /*
- * build the second level of column if needed
- */
-
- /* don't build with this arm if no pump or if we don't ask to */
- pump_l = arm_get_busy_pump(ARM_LEFT_NUM);
- if (count_l == 0)
- pump_l = -1;
- pump_r = arm_get_busy_pump(ARM_RIGHT_NUM);
- if (count_r == 0)
- pump_r = -1;
-
- state_do_build_column(level_l, pump_l, dist_l,
- level_r, pump_r, dist_r);
-
- /* one level up */
- if (pump_l != -1) {
- count_l --;
- level_l ++;
- max_level = level_l;
- }
- if (pump_r != -1) {
- count_r --;
- level_r ++;
- if (level_r > max_level)
- max_level = level_r;
- }
-
- state_debug_wait_key_pressed();
-
- if (mechboard.lintel_count != 0 && do_lintel != 0) {
- arm_goto_prepare_autobuild_outside(ARM_LEFT_NUM,
- PUMP_LEFT1_NUM,
- max_level,
- I2C_AUTOBUILD_DEFAULT_DIST);
- arm_goto_prepare_autobuild_outside(ARM_RIGHT_NUM,
- PUMP_RIGHT1_NUM,
- max_level,
- I2C_AUTOBUILD_DEFAULT_DIST);
- arm_wait_both(ARM_TRAJ_ALL_NEAR);
- state_debug_wait_key_pressed();
-
- arm_goto_prepare_autobuild_inside(ARM_LEFT_NUM,
- PUMP_LEFT1_NUM,
- max_level);
- arm_goto_prepare_autobuild_inside(ARM_RIGHT_NUM,
- PUMP_RIGHT1_NUM,
- max_level);
- arm_wait_both(ARM_TRAJ_ALL_NEAR);
- state_debug_wait_key_pressed();
- }
-
- lintel_only:
- if (mechboard.lintel_count == 0 || do_lintel == 0) {
- mainboard_command.mode = WAIT;
- return;
- }
-
- state_do_build_lintel(max_level);
- mainboard_command.mode = WAIT;
-}
-
-/* prepare to get the lintel */
-static void state_do_prepare_get_lintel(void)
-{
- if (!state_check(PREPARE_GET_LINTEL))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- arm_goto_prepare_get_lintel_disp();
- arm_wait_both(ARM_TRAJ_ALL);
-
- pump_set(PUMP_LEFT1_NUM, PUMP_OFF);
- pump_set(PUMP_RIGHT1_NUM, PUMP_OFF);
-
- /* go fully left or right */
- if (finger_get_side() == I2C_LEFT_SIDE)
- finger_goto(FINGER_LEFT);
- else
- finger_goto(FINGER_RIGHT);
-
- while (state_check(PREPARE_GET_LINTEL));
-}
-
-/* get the lintel from the dispenser */
-static void state_do_get_lintel(void)
-{
- if (!state_check(GET_LINTEL))
- return;
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
-
- pump_set(PUMP_LEFT1_NUM, PUMP_REVERSE);
- pump_set(PUMP_RIGHT1_NUM, PUMP_REVERSE);
-
- arm_goto_get_lintel_disp();
- arm_wait_both(ARM_TRAJ_ALL_NEAR);
-
- time_wait_ms(200);
-
- STMCH_DEBUG("%s left1=%d left2=%d", __FUNCTION__,
- mechboard.pump_left1_current,
- sensor_get_adc(ADC_CSENSE3));
-
- while (state_check(GET_LINTEL));
-
- /* mainboard asked to release lintel, so release pump first */
- if (state_get_mode() == PREPARE_GET_LINTEL) {
- pump_set(PUMP_LEFT1_NUM, PUMP_ON);
- pump_set(PUMP_RIGHT1_NUM, PUMP_ON);
- time_wait_ms(200);
- pump_set(PUMP_LEFT1_NUM, PUMP_OFF);
- pump_set(PUMP_RIGHT1_NUM, PUMP_OFF);
- }
-}
-
-/* put the lintel inside the robot */
-static void state_do_put_lintel(void)
-{
- uint8_t prev_lin_count;
-
- if (!state_check(PUT_LINTEL))
- return;
-
- STMCH_DEBUG("%s mode=%d", __FUNCTION__, state_get_mode());
- prev_lin_count = mechboard.lintel_count;
- mechboard.lintel_count ++;
-
- arm_goto_prepare_get_lintel_disp();
- arm_wait_both(ARM_TRAJ_ALL);
-
- servo_lintel_out();
-
- arm_goto_prepare_put_lintel();
- arm_wait_both(ARM_TRAJ_ALL_NEAR);
-
- arm_goto_put_lintel(prev_lin_count);
- arm_wait_both(ARM_TRAJ_ALL);
-
- pump_set(PUMP_LEFT1_NUM, PUMP_ON);
- pump_set(PUMP_RIGHT1_NUM, PUMP_ON);
-
- if (mechboard.lintel_count == 1)
- servo_lintel_1lin();
- else
- servo_lintel_2lin();
-
- time_wait_ms(300);
-
- pump_set(PUMP_LEFT1_NUM, PUMP_OFF);
- pump_set(PUMP_RIGHT1_NUM, PUMP_OFF);
-
- arm_goto_prepare_put_lintel();
- arm_wait_both(ARM_TRAJ_ALL_NEAR);
-
- while (state_check(PUT_LINTEL));
-}
-
-/* main state machine */
-void state_machine(void)
-{
- while (state_get_mode() != EXIT) {
- changed = 0;
- state_do_init();
- state_do_manual();
- state_do_harvest();
- state_do_lazy_harvest();
- state_do_prepare_pickup();
- state_do_pickup();
- state_do_prepare_inside();
- state_do_prepare_build();
- state_do_autobuild();
- state_do_prepare_get_lintel();
- state_do_get_lintel();
- state_do_put_lintel();
- state_do_loaded();
- state_do_clear();
- state_do_lazy_pickup();
- state_do_wait();
- state_do_store();
- state_do_manivelle();
- state_do_push_temple();
- state_do_push_temple_disc();
- }
-}
-
-void state_init(void)
-{
- vt100_init(&local_vt100);
- mainboard_command.mode = WAIT;
- pump_reset_all();
- mechboard.lintel_count = 1;
- mechboard.column_flags = 0;
- servo_lintel_1lin();
- finger_goto(FINGER_LEFT);
-}