Exemple #1
0
void drive_dump()//dumps the basket into the caldera by driving
{
	move_block_arm(BLA_MID);//get the arm out of the way
	servo_set(BASKET_ARM, BA_UP, 1);//raise the arm
	move_block_arm(BLA_UP);//driving position
	time_drive(-50, -50, 1000);//drive back into the caldera
	msleep(1000);//let stuff fall out
	time_drive(50, 50, 500);//one more attempted dump
	time_drive(-50, -50, 1000);//
	time_drive(50, 50, 500);//get off the caldera a bit (hopefully reducing catching)
	msleep(1000);//more time to fall out
	move_block_arm(BLA_MID);//get the arm out of the way
	servo_set(BASKET_ARM, BA_DOWN, 1);//bring the basket down
	move_block_arm(BLA_UP);//driving position
}
Exemple #2
0
void grab_blocks()//goes through the routine to pick up the blocks
{//starts once near to the pipe, with plowed tribbles; ends back from the pipe, with the tribbles in front, tribble arm down
	servo_set(BLOCK_CLAW, BC_CLOSE, .1);//drop the claw
	move_block_arm(BLA_DOWN);//
	servo_set(BLOCK_CLAW, BC_OPEN, .1);//
	time_drive(50,50,1700);//drive up to blocks
	servo_set(BLOCK_CLAW, BC_CLOSE,.75);//and pick them up
	msleep(250);
	move_block_arm(BLA_LIFT);//get off the ground
	thread hold=thread_create(hold_ba_lift);//this will hold the block arm at the lift location
	thread_start(hold);//
	back(6, 60);//back away from the pipe
	thread_destroy(hold);//don't want to hold it up any more
	servo_set(TRIBBLE_ARM, TA_JUMP, .5);//bring the ta up to keep the blocks in the basket
	servo_set(TRIBBLE_CLAW, TC_CLOSE, .5);//
	servo_set(TRIBBLE_ARM, TA_UP, .5);//
	move_block_arm(BLA_UP);//drop in the basket
	msleep(500);
	motor(BLOCK_ARM, -50);//stall it into the basket
	servo_set(BLOCK_CLAW, BC_OPEN,.75);//
	msleep(300);
	servo_set(BLOCK_CLAW, BC_START, .4);//shake the claw a bit to try to push the blocks in if they didn't go in the first time
	msleep(100);
	servo_set(BLOCK_CLAW, BC_OPEN, .75);//
	msleep(300);
	servo_set(BLOCK_CLAW, BC_START, .4);//
	off(BLOCK_ARM);//stop stalling the motor
	servo_set(TRIBBLE_CLAW, TC_PART_OPEN, .4);//put the claw back down
	servo_set(TRIBBLE_ARM, TA_START, .4);//
	msleep(200);
	servo_set(TRIBBLE_CLAW, TC_OPEN, .6);//
	servo_set(TRIBBLE_ARM, TA_DOWN, .1);//
}
Exemple #3
0
static float retime_drive(cdrom_drive *d, FILE *progress, FILE *log, int lba, int readahead, float oldmean){
  int sectors = 2000;
  int total;
  float newmean;
  if(sectors*oldmean > 5000) sectors=5000/oldmean;
  readahead*=10;
  readahead/=9;
  if(readahead>sectors)sectors=readahead;

  printC("\bo");
  logC("\n\tRetiming drive...                               ");
  
  total = time_drive(d,NULL,log,lba,sectors,1);
  newmean = total/(float)sectors;

  logC("\n\tOld mean=%.2fms/sec, New mean=%.2fms/sec\n",oldmean,newmean);
  printC("\b");

  if(newmean>oldmean)return newmean;
  return oldmean;
}
Exemple #4
0
int main()
{
	set_a_button_text("pipe jumping");
	set_b_button_text("center drive");
	set_c_button_text("testing");
	int strategy;
	WAIT(a_button()||b_button()||c_button());
	if(a_button())
	{
		strategy=PIPE_JUMP;
	}
	else if(b_button())
	{
		strategy=CENTER_DRIVE;
	}
	else//c
	{
		WAIT(side_button());
		msleep(1000);
		set_servo_position(TRIBBLE_ARM, TA_DOWN);
		set_servo_position(TRIBBLE_CLAW, TC_OPEN);
		set_servo_position(BLOCK_CLAW, BC_START);
		set_servo_position(BASKET_ARM, BA_DOWN);
		enable_servos();
		msleep(2000);
		forward(20, 60);
		return 0;
		//set_up_drive();//gets the servos and stuff in driving position
		//test_driving();
		reset_buttons();
		set_up_drive();
		printf("press black button to begin\n");
		WAIT(side_button());
		printf("starting in 2 seconds...\n");
		msleep(2000);
		back_line_follow_time(60, 5000);
		return 9001;
	}
	WAIT(!a_button()&&!b_button());
	set_a_button_text("light start");//only gets here if running one of the real code options
	set_b_button_text("no ls");
	set_c_button_text("-");
	boolean l_s=false;//whether or not is doing light start
	WAIT(a_button()||b_button());
	if(a_button())//if b, does nothing-->l_s already false
		l_s=true;
	reset_buttons();
	if(strategy==PIPE_JUMP)
		set_up_jump();
	else//drive
		set_up_drive();
	if(l_s)
	{
		light_start(LIGHT_SENSOR);
	}
	else//no light start
	{
		printf("press black button when ready\n");
		WAIT(side_button());
		printf("starting in 2 seconds...\n");
		msleep(2000);
	}
	shutdownin(239.5);
	start();//timing
	if(strategy==PIPE_JUMP)
	{
		ready_to_jump();
		time_drive(-90, -90, 1300);//jump!
		servo_set(TRIBBLE_ARM, TA_UP,.3);//move the claw up so it can square up
		time_drive(-50, -50, 1500);//get towards the pipe
		physical_squareup(false);//square up on the back
		time_drive(50, 50, 2500);//go back towards the other wall
		physical_squareup(true);//square up on the front
		time_drive(-50, -50, 1000);//get back to the center
		right(87, 0, 50);//turn towards the edge
		time_drive(-60, -60, 1500);//move towards edge
		physical_squareup(false);//square up on the outside of the field
		tribble_claw_drop();//drop the claw-->plow position
		time_drive(68, 60, 1100);//arc into the wall to wall follow to the blocks
		//forward(5.25, 60);//move to block position
		grab_blocks();//grab the blocks...
		forward(20, 60);//plow the tribbles!
		servo_set(TRIBBLE_CLAW, TC_CLOSE, .7);//close claw to catch tribbles
		servo_set(TRIBBLE_ARM, TA_UP, 1);//put the arm up to get across the center
		forward(20, 60);//get across the center
		servo_set(TRIBBLE_ARM, TA_START, .5);//push into the ground so the claw doesn't jump
		servo_set(TRIBBLE_CLAW, TC_OPEN, .8);//back into plow position
		servo_set(TRIBBLE_ARM, TA_DOWN, .1);//back to drive position
		msleep(250);
		forward(7, 60);//get to dumping location
		nowstr("first dump started at");
		drive_dump();//dump...
		forward(7, 60);//replow the tribbles (maybe get a few extra)
		back(2, 60);//get to optimal grab location
		tribble_claw_dump();//put the tribbles in the basket
		back(5, 60);//back to dump location
		tribble_claw_drop();//put the claw back down
		drive_dump();//dump again
		nowstr("first dump finished at");
		//forward(15, 60);//plow the second set of tribbles, get to block location
		time_drive(66, 60, 3000);//arc towards the right wall to make sure it follows the right wall
		grab_blocks();//grab the blocks...
		forward(8, 60);//plow the remaining tribbles
		servo_set(TRIBBLE_CLAW, TC_CLOSE, .4);//grab the tribbles
		servo_set(TRIBBLE_ARM, TA_DUMP, 1);//raise the arm (to allow it to square up)
		time_drive(60, 60, 1500);//get towards the wall
		physical_squareup(true);//and square up on it
		msleep(200);
		back_line_follow(35.8, 60);//back up to the dumping location
		servo_set(TRIBBLE_ARM, TA_DOWN, .5);//put the arm down to get it out of the way
		nowstr("second dump started at");
		drive_dump();//dump
		tribble_claw_dump();//put the tribbles in the basket
		tribble_claw_drop();//
		drive_dump();//dump again
		nowstr("second dump finished at");
		servo_set(TRIBBLE_CLAW, TC_PART_OPEN, .3);//get the claw up and out of the way
		servo_set(TRIBBLE_ARM, TA_UP, .3);
		back(6, 60);//back up to get the caught tribbles
		servo_set(TRIBBLE_ARM, TA_START, .3);//put the claw back down
		servo_set(TRIBBLE_CLAW, TC_OPEN, .5);//
		servo_set(TRIBBLE_ARM, TA_DOWN, .1);//
		forward(38, 60);//push the tribbles (get any that went way down the field)
		back(2, 60);//tribbles near edge of claw
		tribble_claw_dump();
		servo_set(TRIBBLE_CLAW, TC_CLOSE, .3);//close the claw, just for good measure
		back_line_follow(30, 60);//get back to the dumping location
		servo_set(TRIBBLE_ARM, TA_DOWN, .5);//get the arm out of the way
		nowstr("third dump started at");
		drive_dump();
		nowstr("third dump finished at");
		back_line_follow(17, 60);//get back across the center
		right(180, 0, 50);//turn around
		tribble_claw_drop();//put the claw down...
		forward(25, 60);//and plow!
		back(2, 60);//optimal grab location
		tribble_claw_dump();//well duh...
		servo_set(TRIBBLE_CLAW, TC_CLOSE, .3);//close the claw for good measure
		time_drive(60, 60, 1500);//move towards the wall
		physical_squareup(true);//and square up on it
		back_line_follow(35.8, 60);//back up to the dumping location
		servo_set(TRIBBLE_ARM, TA_DOWN, .5);//get the claw out of the way
		nowstr("fourth dump started at");
		drive_dump();//dump stuff
		move_block_arm(BLA_MID);//get the block arm back out of the way
		servo_set(BASKET_ARM, BA_UP, 1);//put the basket back up
		time_drive(-50, -50, 1500);//one last chance to dump (stay there just cause...you never know)
	}
	else//drive strategy
	{
		forward(38, 90);//get towards the center
		right(90, 0, 70);//turn towards the middle of the gap
		forward(17, 90);//get through the gap and to the black tape
		left(85, 0, 70);//turn parallel to the black tape
		servo_set(TRIBBLE_ARM, TA_JUMP, .4);//get the claw into plow position
		servo_set(TRIBBLE_CLAW, TC_PART_OPEN, .4);//
		servo_set(TRIBBLE_ARM, TA_DOWN, .4);//
		servo_set(TRIBBLE_CLAW, TC_OPEN, .4);//
	}
	nowstr("finished at");
	return 42;
}
Exemple #5
0
int analyze_cache(cdrom_drive *d, FILE *progress, FILE *log, int speed){

  /* Some assumptions about timing: 

     We can't perform cache determination timing based on looking at
     average transfer times; on slow setups, the speed of a drive
     reading sectors via PIO will not be reliably distinguishable from
     the same drive returning data from the cache via pio.  We need
     something even more noticable and reliable: the seek time. It is
     unlikely we'd ever see a seek latency of under ~10ms given the
     synchronization requirements of a CD and the maximum possible
     rotational velocity. A cache hit would always be faster, even
     with PIO.

     Further complicating things, we have to watch the data collection
     carefully as we're not always going to be on an unloaded system,
     and we even have to guard against other apps accessing the drive
     (something that should never happen on purpose, but could happen
     by accident).  As we know in our testing when seeks should never
     occur, a sudden seek-sized latency popping up in the middle of a
     collection is an indication that collection is possibly invalid.

     A second cause of 'spurious latency' would be media damage; if
     we're consistently hitting latency on the same sector during
     initial collection, may need to move past it. */

  int i,j,ret=0,x;
  int firstsector=-1;
  int lastsector=-1;
  int firsttest=-1;
  int lasttest=-1;
  int offset;
  int warn=0;
  int current=1000;
  int hi=15000;
  int cachesize=0;
  int readahead=0;
  int rollbehind=0;
  int cachegran=0;
  float mspersector=0;
  if(speed<=0)speed=-1;

  reportC("\n=================== Checking drive cache/timing behavior ===================\n");
  d->error_retry=0;

  /* verify the lib and cache analysis match */
  if(strcmp(VERSIONNUM,paranoia_version())){
    reportC("\nWARNING: cdparanoia application (and thus the cache tests) does not match the"
	    "\ninstalled (or in use) libcdda_paranoia.so library.  The final verdict of this"
	    "\ntesting may or may not be accurate for the actual version of the paranoia"
	    "library.  Continuing anyway...\n\n");
  }

  /* find the longest stretch of available audio data */

  for(i=0;i<d->tracks;i++){
    if(cdda_track_audiop(d,i+1)==1){
      if(firsttest == -1)
	firsttest=cdda_track_firstsector(d,i+1);
      lasttest=cdda_track_lastsector(d,i+1);
      if(lasttest-firsttest > lastsector-firstsector){
	firstsector=firsttest;
	lastsector=lasttest;
      }
    }else{
      firsttest=-1;
      lasttest=-1;
    }
  }

  if(firstsector==-1){
    reportC("\n\tNo audio on disc; Cannot determine timing behavior...");
    return -1;
  }

  /* Dump some initial timing data to give a little context for human
     eyes.  Take readings ten minutes apart (45000 sectors) and at end of disk. */
  {
    int best=0;
    int bestcount=0;
    int iterating=0;

    offset = lastsector-firstsector-current-1;

    reportC("\nSeek/read timing:\n");

    while(offset>=firstsector){
      int m = offset/4500;
      int s = (offset-m*4500)/75;
      int f = offset-m*4500-s*75;
      int sofar;

      if(iterating){
	reportC("\n");
      }else{
	printC("\r");
	logC("\n");
      }
      reportC("\t[%02d:%02d.%02d]: ",m,s,f);

      /* initial seek to put at at a small offset past end of upcoming reads */
      if((ret=cdda_read(d,NULL,offset+current+1,1))<0){
	/* media error! grr!  retry elsewhere */
	if(ret==-404)return -1;
	reportC("\n\tWARNING: media error during read; continuing at next offset...");
	offset = (offset-firstsector+44999)/45000*45000+firstsector;
	offset-=45000;
	continue;
      }
  
      sofar=time_drive(d,progress, log, offset, current, 1);
      if(offset==firstsector)mspersector = sofar/(float)current;
      if(sofar==-404)
	return -1;
      else if(sofar<0){
	reportC("\n\tWARNING: media error during read; continuing at next offset...");
	offset = (offset-firstsector+44999)/45000*45000+firstsector;
	offset-=45000;
	continue;
      }else{
	if(!iterating){
	  if(best==0 || sofar*1.01<best){
	    best= sofar;
	    bestcount=0;
	  }else{
	    bestcount+=sofar;
	    if(bestcount>sofar && bestcount>4000)
	      iterating=1;
	  }
	}
      }

      if(iterating){
	offset = (offset-firstsector+44999)/45000*45000+firstsector;
	offset-=45000;
	printC("                 ");
      }else{
	offset--;
	printC(" spinning up...  ");
      }
    }
  }

  reportC("\n\nAnalyzing cache behavior...\n");
  
  /* search on cache size; cache hits are fast, seeks are not, so a
     linear search through cache hits up to a miss are faster than a
     bisection */
  {
    int under=1;
    int onex=0;
    current=0;
    offset = firstsector+10;
    
    while(current <= hi && under){
      int i,j;
      under=0;
      current++;
      
      if(onex){
	if(speed==-1){
	  logC("\tAttempting to reset read speed to full... ");
	}else{
	  logC("\tAttempting to reset read speed to %dx... ",speed);
	}
	if(cdda_speed_set(d,speed)){
	  logC("failed.\n");
	}else{
	  logC("drive said OK\n");
	}
	onex=0;
      }

      printC("\r");
      reportC("\tFast search for approximate cache size... %d sectors            ",current-1);
      logC("\n");
      
      for(i=0;i<25 && !under;i++){
	for(j=0;;j++){
	  int ret1=0,ret2=0;
	  if(i>=15){
	    int sofar=0;
	    
	    if(i==15){
	      printC("\r");
	      reportC("\tSlow verify for approximate cache size... %d sectors",current-1);
	      logC("\n");
	      
	      logC("\tAttempting to reduce read speed to 1x... ");
	      if(cdda_speed_set(d,1)){
		logC("failed.\n");
	      }else{
		logC("drive said OK\n");
	      }
	      onex=1;
	    }
	    printC(".");
	    logC("\t\t>>> ");
	    
	    while(sofar<current){
	      ret1 = cdda_read_timed(d,NULL,offset+sofar,current-sofar,&x);
	      logC("slow_read=%d:%d:%d ",offset+sofar,ret1,x);
	      if(ret1<=0)break;
	      sofar+=ret1;
	    }
	  }else{
	    ret1 = cdda_read_timed(d,NULL,offset+current-1,1,&x);
	    logC("\t\t>>> fast_read=%d:%d:%d ",offset+current-1,ret1,x);

	    /* Some drives are 'easily distracted' when readahead is
	       running ahead of the read cursor, causing accesses of
	       the earliest sectors in the cache to show bursty
	       latency. If there's no seek here after a borderline
	       long read of the earliest sector in the cache, then the
	       cache must not have been dumped yet. */

	    if(ret==1 && i && x<MIN_SEEK_MS){ 
	      under=1;
	      logC("\n");
	      break;
	    }
	  }
	  ret2 = cdda_read_timed(d,NULL,offset,1,&x);
	  logC("seek_read=%d:%d:%d\n",offset,ret2,x);
	  
	  if(ret1<=0 || ret2<=0){
	    offset+=current+100;
	    if(j==10 || offset+current>lastsector){
	      reportC("\n\tToo many read errors while performing drive cache checks;"
		      "\n\t  aborting test.\n\n");
	      return(-1);
	    }
	    reportC("\n\tRead error while performing drive cache checks;"
		    "\n\t  choosing new offset and trying again.\n");
	  }else{
	    if(x==-1){
	      reportC("\n\tTiming error while performing drive cache checks; aborting test.\n");
	      return(-1);
	    }else{
	      if(x<MIN_SEEK_MS){
		under=1;
	      }
	      break;
	    }
	  }
	}
      }
    } 
  }
  cachesize=current-1;

  printC("\r");
  if(cachesize==hi){
    reportC("\tWARNING: Cannot determine drive cache size or behavior!          \n");
    return 1;
  }else if(cachesize){
    reportC("\tApproximate random access cache size: %d sector(s)               \n",cachesize);
  }else{
    reportC("\tDrive does not cache nonlinear access                            \n");
    return 0;
  }
  
  /* does the readahead cache exceed the maximum Paranoia currently expects? */
  {
    cdrom_paranoia *p=paranoia_init(d);
    if(cachesize > paranoia_cachemodel_size(p,-1)){
      reportC("\nWARNING: This drive appears to be caching more sectors of\n"
	      "           readahead than Paranoia can currently handle!\n");
      warn=1;
      
    }
    paranoia_free(p);
  }
  if(speed==-1){
    logC("\tAttempting to reset read speed to full... ");
  }else{
    logC("\tAttempting to reset read speed to %d... ",speed);
  }
  if(cdda_speed_set(d,speed)){
    logC("failed.\n");
  }else{
    logC("drive said OK\n");
  }

  /* This is similar to the Fast search above, but just in case the
     cache is being tracked as multiple areas that are treated
     differently if non-contiguous.... */
  {
    int seekoff = cachesize*3;
    int under=0;
    reportC("\tVerifying that cache is contiguous...");
  
    for(i=0;i<20 && !under;i++){
      printC(".");
      for(j=0;;j++){
	int ret1,ret2;

	if(offset+seekoff>lastsector){
	  reportC("\n\tOut of readable space on CDROM while performing drive checks;"
		  "\n\t  aborting test.\n\n");
	  return(-1);
	}
	

	ret1 = cdda_read_timed(d,NULL,offset+seekoff,1,&x);
	logC("\t\t>>> %d:%d:%d ",offset+seekoff,ret1,x);
	ret2 = cdda_read_timed(d,NULL,offset,1,&x);
	logC("seek_read:%d:%d:%d\n",offset,ret2,x);
	
	if(ret1<=0 || ret2<=0){
	  offset+=cachesize+100;
	  if(j==10){
	    reportC("\n\tToo many read errors while performing drive cache checks;"
		    "\n\t  aborting test.\n\n");
	    return(-1);
	  }
	  reportC("\n\tRead error while performing drive cache checks;"
		  "\n\t  choosing new offset and trying again.\n");
	}else{
	  if(x==-1){
	    reportC("\n\tTiming error while performing drive cache checks; aborting test.\n");
	    return(-1);
	  }else{
	    if(x<MIN_SEEK_MS)under=1;
	    break;
	  }
	}
      }
    }
    printC("\r");
    if(under){
      reportC("\nWARNING: Drive cache does not appear to be contiguous!\n");
      warn=1;
    }else{
      reportC("\tDrive cache tests as contiguous                           \n");
    }
  }

  /* The readahead cache size ascertained above is likely qualified by
     background 'rollahead'; that is, the drive's readahead process is
     often working ahead of our actual linear reads, and if reads stop
     or are interrupted, readahead continues and overflows the cache.
     It is also the case that the cache size we determined above is
     slightly too low because readahead is probably always working
     ahead of reads. 

     Determine the rollahead size a few ways (which may disagree:
     1) Read number of sectors equal to cache size; pause; read backward until seek
     2) Read sectors equal to cache-rollahead; verify reading back to beginning does not seek 
     3) Read sectors equal to cache; pause; read ahead until seek delay
  */

  {
    int lower=0;
    int gran=64;
    int it=3;
    int tests=0;
    int under=1;
    readahead=0;
    
    while(gran>1 || under){
      tests++;
      if(tests>8 && gran<64){
	gran<<=3;
	tests=0;
	it=3;
      }
      if(gran && !under){
	gran>>=3;
	tests=0;
	if(gran==1)it=10;
      }

      under=0;
      readahead=lower+gran;

      printC("\r");
      logC("\n");
      reportC("\tTesting background readahead past read cursor... %d",readahead);
      printC("           \b\b\b\b\b\b\b\b\b\b\b");
      for(i=0;i<it;i++){
	int sofar=0,ret;
	logC("\n\t\t%d >>> ",i);

	while(sofar<cachesize){
	  ret = cdda_read_timed(d,NULL,offset+sofar,cachesize-sofar,&x);
	  if(ret<=0)goto error;
	  logC("%d:%d:%d ",offset+sofar,ret,x);

	  /* some drives can lose sync and perform an internal resync,
	     which can also cause readahead to restart.  If we see
	     seek-like delays during the initial cahe load, retry the
	     preload */

	  sofar+=ret;
	}
	
	printC(".");

	/* what we'd predict is needed to let the readahead process work. */
	{
	  int usec=mspersector*(readahead)*(6+i)*200;
	  int max= 13000*2*readahead; /* corresponds to .5x */
	  if(usec>max)usec=max;
	  logC("sleep=%dus ",usec);
	  usleep(usec);
	}
	
	/* seek to offset+cachesize+readahead */
	ret = cdda_read_timed(d,NULL,offset+cachesize+readahead-1,1,&x);
	if(ret<=0)break;
	logC("seek=%d:%d:%d",offset+cachesize+readahead-1,ret,x);
	if(x<MIN_SEEK_MS){
	  under=1;
	  break;
	}else if(i%3==1){
	  /* retime the drive just to be conservative */
	  mspersector=retime_drive(d, progress, log, offset, readahead, mspersector);
	}
      }
      
      if(under)
	lower=readahead;

    }
    readahead=lower;
  }