Ejemplo n.º 1
0
int main(void) {
    di();
    OSCCON = 0x78;
    led_init();
    //sound_init();
    radio_init();
    motors_init();
    adc_init();
    ei();

    while (1) {
        /* Listen for incoming radio packet */
        if (radio_rx()) {
            /* If a radio packet is pending
             * send it immediately
             */
            if (radio_len != 0) {
                /* Send a packet */
                unsigned char c;
                LATB |= 0x01;
                radio_tx_start();
                radio_tx_data(radio_len);
                for (c = 0; c < radio_len; c++)
                    radio_tx_data(radio_data[c]);
                radio_tx_finish();
                LATB &= ~0x01;
            }
        }

        /* Read ADC values sequentally */
        {
            static char adc_ptr = 0;
            const char adc_addr[6] = {4, 15, 11, 9, 30, 13};
            /* Reading value */
            char adc_id = adc_addr[adc_ptr];
            adc_measure(adc_id);
            adc_data[adc_ptr << 1] = ADRESH;
            adc_data[(adc_ptr << 1) | 1] = ADRESL;
            /* Incrementing address */
            adc_ptr++;
            if (adc_ptr >= 6)
                adc_ptr = 0;
#ifdef FALSE_DEF
            /* Checking battery voltage */
            if (adc_id == 13) {
                /* Voltage less then 3.0V */
                if (ADRESH == 0 && ADRESL < 144) {
                    /* Power off */
                    LATA = 0;
                    LATB = 0;
                    LATC = 0;
                    di();
                    SLEEP();
                }
            }
#endif
        }
    }
}
Ejemplo n.º 2
0
int main()
{

   motors_init();
   movman_init();
   contacts_init();
   event_q_init();
   adc_init();
   leds_init();

   sei();

   adc_start();

   movman_schedule_move(
      WAIT_5_SECONDS_THEN_FULL_FORWARD_FOR_A_LONG_TIME,
      TO_MEET_STARTUP_REQUIREMENT,
      IMMEDIATELY);

   while(1){

      // Testing in the lab showed this runs every ~95us

      event_t e = event_q_get_next_event();

      switch(e){

         case LINE_DETECTED:
            handle_line_detected();
            break;
         case CONTACT_DETECTED_BOTH:
         case CONTACT_DETECTED_FRONT:
            handle_front_contact();
            break;
         case CONTACT_DETECTED_REAR:
            handle_rear_contact();
            break;
         case MOVEMENT_COMPLETE:
            handle_movement_complete();
            break;
         case NEW_PROXIMITY_READINGS:
            handle_new_prox_readings();
            break;
         default:
            break;


      }

   }

   return 0;
}
Ejemplo n.º 3
0
int main(void)
{
	/*init all the things*/
	motors_init(PHASE_CORRECT, PRESCALE_8);
	uart_init(BAUD_CALC(9600));
	sei();
	adc_init();
	wdt_init(WDTO_500MS);
	/********************/
	go(0, 0);
	uart_putc(ACK);
	over_current_a = 0;
	over_current_b = 0;
	while (1)
	{
		current_a = analog_read(C_SENS_A);
		current_b = analog_read(C_SENS_B);

		req_t = get_request_type();
		if (req_t == CURRENT_REQ)
		{	
			write_current(current_a, current_b);
		}
		else if (req_t == MOTORS_SET)
		{
			read_motors(&speed_a, &speed_b);
			wdt_reset();
		}
		
		//manage current sens
		#ifdef CURRENT_LIMIT
		if ((current_a < CURRENT_LIMIT) && (current_b < CURRENT_LIMIT))
		{
			go(speed_a, speed_b);
			over_current_a = over_current_b = 0;
		}
		else
		{
			//overcurrent
			go(0, 0);
			uart_putc('!');
			over_current_a = current_a - CURRENT_LIMIT;
			over_current_b = current_b - CURRENT_LIMIT;
		}
		#endif
	}
	return (0);
}
Ejemplo n.º 4
0
void main(void)
//-----------------------------------------------------------------------------------------------------
//  Purpose:	The MCU will come here after reset. 
//  
//
//  Rev:    1.5a     TEMPLATE RELEASE
//  
//  Notes:          None    
//-----------------------------------------------------------------------------------------------------
{
	
	//Initialization function calls 
	init_ports();
	motors_init();
	system_clock_init();
	InitDisplay("FHBTEST    "); //Start-up splash changed to unity ID
	InitUART();
	ADInit();	
	ENABLE_SWITCHES;	
	/* LED initialization - macro defined in qsk_bsp.h */
 	ENABLE_LEDS	


	//Polling for switch presses 
	while(TRUE) 
	{
		if(S1 == PRESSED)
		{
			BNSPrintf(LCD,"\tTEST          \n        ");
			project2ADemo(); 		
		}
		else if (S2 == PRESSED)
		{
			BNSPrintf(LCD,"\tOff            \n        ");
		}
		else if (S3 == PRESSED)
		{
			BNSPrintf(LCD,"\tFigure 8              \n        ");
			DoFigureEight();
		}
		else
		{
       		BNSPrintf(LCD,"\tTeam 2                 \n        ");
        }
		
	}
}
void fc_init() {
  pids_init();
  motors_init();
}
void navigation_update_state()
{
    int32_t distance_values[N_ULTRASONIC_SENSORS];
    int32_t smallest = 0;
    int32_t left_s = 0;
    int32_t right_s = 0;
    int32_t front1_s = 0;
    int32_t front2_s = 0;

    ultrasonic_get_distance(distance_values);
    smallest = ultrasonic_get_smallest(distance_values, N_ULTRASONIC_SENSORS);
    left_s = distance_values[US_LEFT];
    right_s = distance_values[US_RIGHT];
    front1_s = distance_values[US_FRONT_1];
    front2_s = distance_values[US_FRONT_2];

    if(navigation_status.current_state == BYPASS){
		//motor command is done directly in CLI
    }
    else if(navigation_status.current_state == AVOID_OBSTACLE){

        if (smallest > navigation_status.max_dist_obs){
        	navigation_status.current_state = GO_TO_TARGET;
        	GPIO_write(Board_OBS_A_EN, 0);
        }else if ((left_s < BACKWARD_THRESHOLD/2) || (right_s < BACKWARD_THRESHOLD/2)){
        	navigation_status.current_state = SPACE_NEEDED;
        }else if (front1_s < BACKWARD_THRESHOLD && front2_s < BACKWARD_THRESHOLD){
        	serial_printf(cli_stdout, "Wall ahead!\n");
        	navigation_status.current_state = AVOID_WALL;
        }

    }
    else if (navigation_status.current_state == AVOID_WALL){
		//We check if we're not facing the wall anymore
			if ((left_s < BACKWARD_THRESHOLD/2) || (right_s < BACKWARD_THRESHOLD/2)){
				navigation_status.current_state = SPACE_NEEDED;
			}
			if (!((front1_s < BACKWARD_THRESHOLD) && (front2_s < BACKWARD_THRESHOLD))){
				if (smallest > navigation_status.max_dist_obs){
					navigation_status.current_state = GO_TO_TARGET;
					GPIO_write(Board_OBS_A_EN, 0);
				}else{
					navigation_status.current_state = AVOID_OBSTACLE;
				}
			}
    }
    else if (navigation_status.current_state == SPACE_NEEDED){
		if (!((left_s < BACKWARD_THRESHOLD/2) || (right_s < BACKWARD_THRESHOLD/2))){
			//Check if we face another type of obstacle or if path is free
			if (smallest < navigation_status.max_dist_obs){
				//We use a different strategy depending on the type of obstacle
				if (front1_s < BACKWARD_THRESHOLD && front2_s < BACKWARD_THRESHOLD){
					serial_printf(cli_stdout, "Wall ahead!\n");
					navigation_status.current_state = AVOID_WALL;
				}else
					navigation_status.current_state = AVOID_OBSTACLE;
			}else{
				navigation_status.current_state = GO_TO_TARGET;
				GPIO_write(Board_OBS_A_EN, 0);
			}
		}
    }
    else
    {
        //normal operation: continue on mission items
		if(mission_items.item[mission_items.current_index].current)
		{
			// Only go to target if mb is armed and rover must go to home OR sbc is armed and ready to record
#ifdef CONTINUE_WAYPOINTS_IMMEDIATELY
			if(comm_mainboard_armed() == 1){
#else
			if(comm_mainboard_armed() == 1 && (mission_items.current_index == 0 || comm_sbc_armed() == 1)){
#endif
				navigation_status.current_state = GO_TO_TARGET;
			}
			else
			{
				navigation_status.current_state = STOP;
			}
		}

		if(navigation_status.current_state == GO_TO_TARGET)
		{
			ultrasonic_get_distance(distance_values);
			if(navigation_status.distance_to_target < TARGET_REACHED_DISTANCE)
			{
				navigation_mission_item_reached();
			}
			else if (smallest < navigation_status.max_dist_obs)
			{
				GPIO_write(Board_OBS_A_EN, 1);

				//We use a different strategy depending on the type of obstacle
				if (front1_s < BACKWARD_THRESHOLD && front2_s < BACKWARD_THRESHOLD)
				{
					serial_printf(cli_stdout, "Wall ahead!\n");
					navigation_status.current_state = AVOID_WALL;
				}
				else if ((left_s < BACKWARD_THRESHOLD/2) || (right_s < BACKWARD_THRESHOLD/2))
				{
					navigation_status.current_state = SPACE_NEEDED;
				}
				else
					navigation_status.current_state = AVOID_OBSTACLE;
			}
		}
    }
}



#if defined (NAVIGATION_TEST)
void navigation_move();
#else
void navigation_move()
{
	static int32_t lspeed, rspeed;
	double angular = 0;

	//only move if not on halt AND state = go_to_target
	if(navigation_status.halt == 0)
	{
		if(navigation_status.current_state == GO_TO_TARGET)
		{
			angular = pid_update(&pid_a, navigation_status.angle_to_target) * PID_SCALING_FACTOR;

			if (angular > 0){
				lspeed = PWM_SPEED_100;
				rspeed = PWM_SPEED_100 - (int32_t)(angular);
				if (rspeed < PWM_MIN_CURVE_SPEED)
					rspeed = PWM_MIN_CURVE_SPEED;
			}else if (angular <= 0){
				rspeed = PWM_SPEED_100;
				lspeed = PWM_SPEED_100 + (int32_t)(angular);
				if (lspeed < PWM_MIN_CURVE_SPEED)
					lspeed = PWM_MIN_CURVE_SPEED;

			}
			motors_wheels_move((int32_t)lspeed, (int32_t)rspeed, (int32_t)lspeed, (int32_t)rspeed);
			navigation_status.motor_values[0] = lspeed; //backup
			navigation_status.motor_values[1] = rspeed;
		}
		else if(navigation_status.current_state == STOP)
		{
			motors_wheels_stop();
			navigation_status.motor_values[0] = 0;
			navigation_status.motor_values[1] = 0;
		}
//		else if(navigation_status.current_state == AVOID_OBSTACLE)
//		{
//			int32_t distance_values[N_ULTRASONIC_SENSORS];
//			ultrasonic_get_distance(distance_values);
//			ultrasonic_check_distance(distance_values, navigation_status.motor_values, PWM_SPEED_80); //80% of speed to move slower than in normal mode
//
//			motors_wheels_move(navigation_status.motor_values[0], navigation_status.motor_values[1],
//					navigation_status.motor_values[0], navigation_status.motor_values[1]);

//		}else if (navigation_status.current_state == AVOID_WALL){
//			// move backwards in opposite curving direction (TODO: to be tested)
//			lspeed = -navigation_status.motor_values[1];
//			rspeed = -navigation_status.motor_values[0];
//			motors_wheels_move((int32_t)lspeed, (int32_t)rspeed, (int32_t)lspeed, (int32_t)rspeed);
//		}else if (navigation_status.current_state == SPACE_NEEDED){
//			navigation_status.motor_values[0] = -PWM_SPEED_100;
//			navigation_status.motor_values[1] = -PWM_SPEED_100;
//			motors_wheels_move(navigation_status.motor_values[0], navigation_status.motor_values[1],
//					navigation_status.motor_values[0], navigation_status.motor_values[1]);
//		}
	}
	else
	{
		navigation_status.motor_values[0] = 0;
		navigation_status.motor_values[1] = 0;
		motors_wheels_stop();
	}

		//		serial_printf(cli_stdout, "speed l=%d, r=%d \n", motor_values[0], motor_values[1]);

}
#endif

void navigation_change_gain(char pid, char type, float gain)
{
	if (pid == 'a'){
		if(type == 'p')
			pid_a.pGain = gain;
		else if (type == 'i')
			pid_a.iGain = gain;
		else if (type == 'd')
			pid_a.dGain = gain;
	}
}

#if defined (NAVIGATION_TEST)
void navigation_init();
#else
void navigation_init()
{
	cli_init();
	motors_init();
	ultrasonic_init();
	pid_init(&pid_a, PGAIN_A, IGAIN_A, DGAIN_A, MOTOR_IMAX, MOTOR_IMIN);
	navigation_status.lat_rover = INIT_LAT;
	navigation_status.lon_rover = INIT_LON;
	navigation_status.heading_rover = 0.0;
	navigation_status.lat_target = TARGET_LAT;
	navigation_status.lon_target = TARGET_LON;
	navigation_status.distance_to_target = 0.0;
	navigation_status.angle_to_target = 0.0;
	navigation_status.current_state = STOP;
	navigation_status.max_dist_obs = OBSTACLE_MAX_DIST;
	navigation_status.halt = 0;
	navigation_status.position_valid = false;
	GPIO_write(Board_OBS_A_EN, 1);

	mission_items.count = 0;
}
Ejemplo n.º 7
0
void _main(int argc, char *argv[])
{
   (void)argc;
   (void)argv;
   syslog(LOG_INFO, "initializing core");
   
   /* init SCL subsystem: */
   syslog(LOG_INFO, "initializing signaling and communication link (SCL)");
   if (scl_init("core") != 0)
   {
      syslog(LOG_CRIT, "could not init scl module");
      exit(EXIT_FAILURE);
   }
   
   /* init params subsystem: */
   syslog(LOG_INFO, "initializing opcd interface");
   opcd_params_init("core.", 1);
   
   /* initialize logger: */
   syslog(LOG_INFO, "opening logger");
   if (logger_open() != 0)
   {
      syslog(LOG_CRIT, "could not open logger");
      exit(EXIT_FAILURE);
   }
   syslog(LOG_CRIT, "logger opened");
   sleep(1); /* give scl some time to establish
                a link between publisher and subscriber */

   LOG(LL_INFO, "+------------------+");
   LOG(LL_INFO, "|   core startup   |");
   LOG(LL_INFO, "+------------------+");

   LOG(LL_INFO, "initializing system");

   /* set-up real-time scheduling: */
   struct sched_param sp;
   sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
   sched_setscheduler(getpid(), SCHED_FIFO, &sp);
   if (mlockall(MCL_CURRENT | MCL_FUTURE))
   {
      LOG(LL_ERROR, "mlockall() failed");
      exit(EXIT_FAILURE);
   }

   /* initialize hardware/drivers: */
   omap_i2c_bus_init();
   baro_altimeter_init();
   ultra_altimeter_init();
   ahrs_init();
   motors_init();
   voltage_reader_start();
   //gps_init();
   
   LOG(LL_INFO, "initializing model/controller");
   model_init();
   ctrl_init();
   
   /* initialize command interface */
   LOG(LL_INFO, "initializing cmd interface");
   cmd_init();
   
   /* prepare main loop: */
   for (int i = 0; i < NUM_AVG; i++)
   {
      output_avg[i] = sliding_avg_create(OUTPUT_RATIO, 0.0f);
   }

   LOG(LL_INFO, "system up and running");
   struct timespec ts_curr;
   struct timespec ts_prev;
   struct timespec ts_diff;
   clock_gettime(CLOCK_REALTIME, &ts_curr);
 
   /* run model and controller: */
   while (1)
   {
      /* calculate dt: */
      ts_prev = ts_curr;
      clock_gettime(CLOCK_REALTIME, &ts_curr);
      TIMESPEC_SUB(ts_diff, ts_curr, ts_prev);
      float dt = (float)ts_diff.tv_sec + (float)ts_diff.tv_nsec / (float)NSEC_PER_SEC;

      /* read sensor values into model input structure: */
      model_input_t model_input;
      model_input.dt = dt;
      ahrs_read(&model_input.ahrs_data);
      gps_read(&model_input.gps_data);
      model_input.ultra_z = ultra_altimeter_read();
      model_input.baro_z = baro_altimeter_read();

      /* execute model step: */
      model_state_t model_state;
      model_step(&model_state, &model_input);

      /* execute controller step: */
      mixer_in_t mixer_in;
      ctrl_step(&mixer_in, dt, &model_state);
 
      /* set up mixer input: */
      mixer_in.pitch = sliding_avg_calc(output_avg[AVG_PITCH], mixer_in.pitch);
      mixer_in.roll = sliding_avg_calc(output_avg[AVG_ROLL], mixer_in.roll);
      mixer_in.yaw = sliding_avg_calc(output_avg[AVG_YAW], mixer_in.yaw);
      mixer_in.gas = sliding_avg_calc(output_avg[AVG_GAS], mixer_in.gas);

      /* write data to motor mixer: */
      EVERY_N_TIMES(OUTPUT_RATIO, motors_write(&mixer_in));
   }
}
Ejemplo n.º 8
0
int main (void) {
    uint8_t bu, bd;      // buttons up, buttons down (read-in buffers)
    uint8_t i;           // iterator
    uint8_t adcchan = 0;

    uint8_t ramp;
    uint16_t cycle;
    
    motor_t motor[NMOTORS];

    for (i = 0; i < NMOTORS; i++) {
	motor[i].isrunning = false;
	motor[i].position = 0;
	motor[i].bu = false;
	motor[i].bd = false;
	motor[i].pot = 0;
	motor[i].trgspeed = SPEEDMIN;
	motor[i].curspeed = SPEEDMIN;
	motor[i].counter = 0;
    }
    
    led_init();
    spi_init();
    adc_init();
    motors_init();

    /* // debug */
    /* uart_init(); */
    /* stdout = &uart_output; */

    adc_set_chan(adcchan);
    adc_start();

    while (1) {
	led_off();
	
	// keep the ADC running "in background"
	if ( !( adc_is_running() )) {
	    motor[adcchan].pot = adc_get();

	    if (motor[adcchan].bu != motor[adcchan].bd) {
		motor[adcchan].trgspeed =
		    motor_scale_speed(motor[adcchan].pot);
	    } else {
		motor[adcchan].trgspeed = SPEEDMIN;
	    }

	    adcchan++;
	    if (adcchan >= 5) adcchan = 0;

	    // HACK: lame jumpers
	    if (adcchan == 0) adc_set_chan(6);
	    if (adcchan == 1) adc_set_chan(1);
	    if (adcchan == 2) adc_set_chan(2);
	    if (adcchan == 3) adc_set_chan(3);
	    if (adcchan == 4) adc_set_chan(7);

	    adc_start();
	}

	// read in buttons
	shiftreg_load();
	bu = spi_transmit(SPI_TRANSMIT_DUMMY);
	bd = spi_transmit(SPI_TRANSMIT_DUMMY);
	for (i = 0; i < NMOTORS; i++) {
	    motor[i].bu = bit_is_set(bu, i) ? true : false;
	    motor[i].bd = bit_is_set(bd, i) ? true : false;

	    // both buttons pressed
	    if (motor[i].bu && motor[i].bd) {
		led_on();
		motor[i].trgspeed = SPEEDMIN;
	    }
	    
	    if (motor[i].bu != motor[i].bd) {
		motor[i].isrunning = true;
		
		// set dir
		if (motor[i].bu) {
		    motor_set_dir(i, DIR_UP);
		} else if (motor[i].bd) {
		    motor_set_dir(i, DIR_DOWN);
		}
	    }
	    // allow ramp-down
	    else if (motor[i].curspeed != motor[i].trgspeed) {
		motor[i].isrunning = true;
	    }
	    // mark as ok-to-stop
	    else if (motor[i].curspeed == SPEEDMIN) {
		motor[i].isrunning = false;
	    }
	}
       

	for (ramp = 0; ramp < RAMPCYCLES; ramp++) {
	    // push current speed towards target
	    for (i = 0; i < NMOTORS; i++) {
		if (motor[i].curspeed < motor[i].trgspeed) {
		    motor[i].curspeed += 1;
		}
		if (motor[i].curspeed > motor[i].trgspeed) {
		    motor[i].curspeed -= 1;
		}
	    }

	    // run at current speed
	    for (cycle = 0; cycle < RUNCYCLES; cycle++) {
		for (i = 0; i < NMOTORS; i++) {		
		    // either button pressed or ramp-down
		    if (motor[i].isrunning) {
			if (motor[i].counter > 0) {
			    motor[i].counter -= 1;
			} else {
			    // reset counter
			    motor[i].counter = motor[i].curspeed;
			    motor_step(i);
			}
		    }
		}
	    }
	}
    }
    return 0;
}
Ejemplo n.º 9
0
int main( void ){


	DDRC = 0xDB;
	//PORTC = 0x7E;;
	PORTC = 0xE7;


	uint8_t error;
	Packet packet;
	Queue* packets;
	packets = Packets_getQueue();

	// initialize globals 
	globals_init();

	// initialize Time
	time_init();
	TimeResult tr;
	uint32_t previous = 0;
	uint32_t watchdog = 0;

	// initialize usart
	usart_init();

	// initialize motors
	motors_init();
	motors_set(MOTORS_LEFT, 0);
	motors_set(MOTORS_RIGHT, 0);

	// initialize analog input
	analoginput_init();

	// enable interrupts
	sei();

	// loop forever
	while(1){
		error = Packets_getError();
		if (error){
			Packets_sendError(ERROR_PACKETS, error);
			continue;
		}
		if (packets->count > 0){
			error = 0x00;
			packet = Packets_getNext();
			error = Queue_getError(packets);
			if (error){
				Packets_sendError(ERROR_QUEUE, error);
				continue;
			}

			handle_packet(packet);
			watchdog = time_get_time();
			
		}
		tr = time_get_time_delta(previous);
		
		// every 20ms, calculate rpm
		if (get_time_in_ms(tr.delta) > 20){
			previous = tr.previous;
			motors_tick();
			send_status();

		}	

		tr = time_get_time_delta(watchdog);
		if (get_time_in_ms(tr.delta) > 500){
			motors_set(MOTORS_LEFT, 0);
			motors_set(MOTORS_RIGHT, 0);
		}	
	}
	
}
Ejemplo n.º 10
0
int main(int argc, char *argv[]) {
  ros::init(argc, argv, "motors");
  ros::NodeHandle n;

  timerclear(&last_motion);
  reset_valid_counts();

  /* Node setup */
  ros::ServiceServer srv = n.advertiseService("/scout/motion", motion_srv);
  ros::Subscriber sub = n.subscribe("/scout/motion", 1, motion_msg);
  ros::Publisher pub = n.advertise<scout_msgs::ScoutMotorsMsg>("/scout/motors", 1000);

  /* Read parameters */
  ros::NodeHandle tmp("~");
  if ( !tmp.getParam("accel", accel) )
    accel = DEFAULT_ACCEL;
  if ( !tmp.getParam("port0", p[0].name) )
    p[0].name = DEFAULT_PORT0;
  if ( !tmp.getParam("port1", p[1].name) )
    p[1].name = DEFAULT_PORT1;

  motors_init();
  signal(SIGINT, shutdown);

  ROS_INFO("Motors node launched (accel=%d)", accel);
  while (ros::ok()) {
    /* prepare select() */
    struct timeval timeout = {0, TIMEOUT_USECS};
    fd_set rfds;
    FD_ZERO(&rfds);
    int maxfd = -1;
    for (int i=0 ; i<NP ; i++) {
      int fd = p[i].fd;
      if (fd>maxfd) maxfd=fd;
      FD_SET(fd, &rfds);
    }

    /* perform select() */
    int ret = select(maxfd+1, &rfds, NULL, NULL, &timeout);
    if (ret>0) {
      /* processing serial port data */
      for (int i=0 ; i<NP ; i++) {
        int fd = p[i].fd;
        if (FD_ISSET(fd, &rfds))
          port_process(i);
      }
    } else {
      /* timeout */
      ROS_WARN("No response from any motor");
      reset_valid_counts();
      ask_encoders();
    }
    
    /* check of all encoder position reports have arrived */
    if (all_valid_counts()) {
      /* send ROS message */
      motors_msg.header.stamp = ros::Time::now();
      motors_msg.count_left  = count[0];
      motors_msg.count_right = count[1];
      /* printf("Sending data %d %d\n", motors_msg.count_left, motors_msg.count_right); */
      pub.publish(motors_msg);
      reset_valid_counts();
      ask_encoders();
    }

    /* check motor command timeout */
    if (timerisset(&last_motion)) {
      struct timeval now, diff;
      if (-1==gettimeofday(&now, NULL)) {
        perror("main:gettimeofday()");
        exit(1);
      } else {
        timersub(&now, &last_motion, &diff);
        /* printf("diff: %d %d\n", diff.tv_sec, diff.tv_usec); */
        if (diff.tv_sec >= MOTION_TIMEOUT) {
          ROS_WARN("No velocity commands for %d seconds -- STOPPING", MOTION_TIMEOUT);
          send_vel(0, 0);
          timerclear(&last_motion);
        }
      }
    }

    /* handle ROS callbacks */
    ros::spinOnce();
  }

  return 0;
}