Project Summary

Executive Summary

Overview

By: Andrew Le – Project Manager

The objective of the Rover Project is to improve on RObot SCOut (ROSCO), a rover created by Arxterra.  It is controlled remotely by using Arxterra’s Interface in conjunction with an Android OS phone running version 3.2 or newer.  The brain is the Arduino Uno and each track is powered by a DC motor.  The mount for the Android phone is able to scan and tilt using DC motors. The team will incorporate solar power charging to provide continuous charge during operation. An LED illuminator array will be built using an existing PCB to allow night camera operation.

Project Showcase Video:

Please watch in HD 1080P fullscreen for the best viewing experience.

Read more

Final DC Motor Code

By Eduardo Contreras – Computer, Power, and Powertrain

Here is the final code needed to run the rover with Arxterra. The highlighted lines are the new changes I made in order for it to work with the updated version of the Adafruit Motor Shield, as well as for the motors replacing the servos.

Personal Note: I strongly believe that this way of running the rover over Arxterra is inefficient. The amount of code needed so that the motors act like servos is a bit excessive. Each chunk of code can be replaced by two lines that will do the exact thing. Also, the servos can hold position more efficient than a motor can, since it can’t hold to begin with. The added code used so that the motor can stay still work, but jittering causes problems. The tilting works very well, but it’s better to stick with servos.

#include <SPI.h>

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();

#define FALSE 0
#define TRUE  1

// Commands to Numeric Value Mapping
//               Data[0] =   CMD TYPE | Qual
//                        bit  7654321   0      
#define MOVE         0x01   // 0000000   1        
#define CAMERA_MOVE  0x02   // 0000001   0                  
#define CAMERA_HOME  0x04   // 0000010   0

const int panHome        =   90;  // degrees 
const int tiltHome       =   10;

Adafruit_DCMotor *motorL = AFMS.getMotor(1);
Adafruit_DCMotor *motorR = AFMS.getMotor(2);
Adafruit_DCMotor *TiltMotor = AFMS.getMotor(3);

int cur_pot_scan = 0;              //Initialize starting values for potentiometer readings
int cur_pot_tilt = 0;
//int new_pot_scan = 600;            //These starting values may change, depending on potentiometer used
int new_pot_tilt = 135;
int pot_move = 0;
int pot_diff = 0;
int pot_move2 = 0;
int pot_diff2 = 0;
int time_delay = 0;
int old_panAngle = 0;
int i = 0;

const int deg_error = 15;          //Needed to reduce jittering, may change value

int inputPin = A0;

boolean collisionDetection = FALSE;

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(9600); // Use 57600?

  AFMS.begin(); // Use 64KHZ?

  init_servos();
}

void loop() { 
  if( Serial.available() ) {
    commandHandler();
  }
  while(cur_pot_tilt >= new_pot_tilt + deg_error || cur_pot_tilt <= new_pot_tilt - deg_error) {
    if( cur_pot_tilt > new_pot_tilt) {
      TiltMotor->run(FORWARD);
    }
    else if( cur_pot_tilt < new_pot_tilt) {
      TiltMotor->run(BACKWARD);
    }
    cur_pot_tilt = analogRead(inputPin);
  }

  TiltMotor->run(RELEASE);

  cur_pot_tilt = analogRead(inputPin);
}

// Event handler for the shell connection. 
void commandHandler() {  // declared void in version 1.00

  byte data[5];
  int i = 0;

  boolean cameraHome = false;

  if( Serial.peek() == CAMERA_HOME ) cameraHome = true;
  while(!cameraHome && Serial.available() < 5) {}

  while(Serial.available()) {
    data[i] = Serial.read();
    i++;
    if( cameraHome ) break;
  }
  byte cmd = data[0];

  if (cmd == MOVE) {
    /***********************************
     * motion command
     * motordata[1]    left run    (FORWARD, BACKWARD, BRAKE, RELEASE)
     * motordata[2]    left speed  0 - 255
     * motordata[3];   right run   (FORWARD, BACKWARD, BRAKE, RELEASE) 
     * motordata[4];   right speed 0 - 255
     ***********************************/
     move(data);
  }
  else if (cmd == CAMERA_MOVE){
    /***********************************
     * pan and tilt command 
     * data[1]    0
     * data[2]    pan degrees (0 to 180)
     * data[3]    0
     * data[4]    tilt degrees (0 to 180)
     ***********************************/
     move_camera(data[2],data[4]);
  }
  else if (cmd == CAMERA_HOME){
    /***********************************
     * camera home command 
     * pan position = 90 (default), tilt position = 90 (default)
     ***********************************/ 
     home_camera();
  }
}

void move(uint8_t * motordata) {
   motorL->setSpeed(motordata[2]);  
   motorR->setSpeed(motordata[4]);
   motorL->run(motordata[1]);
   motorR->run(motordata[3]);
}

void move_camera(byte panAngle, byte tiltAngle) {
  motorL->setSpeed(150);
  motorR->setSpeed(150);
  if(old_panAngle != panAngle) {
  if(panAngle > 90) {
    pot_diff = panAngle - 90;
    time_delay = pot_diff * 20.55;
    motorR->run(FORWARD);
    motorL->run(BACKWARD);
    delay(time_delay);
    motorR->run(RELEASE);
    motorL->run(RELEASE);
  }
  else if(panAngle < 90) {
    pot_diff = 90 - panAngle;
    time_delay = pot_diff * 20.55;
    motorR->run(BACKWARD);
    motorL->run(FORWARD);
    delay(time_delay);
    motorR->run(RELEASE);
    motorL->run(RELEASE);
  }
  i = 1;
  }
  else {
    i = 0;
  }
  old_panAngle = panAngle;
  if(i == 0) {
  if(tiltAngle > 70) {
    tiltAngle = 70;
  }
  new_pot_tilt = tiltAngle * 4;
  }
}

void init_servos() {
  TiltMotor->setSpeed(100);                       //Starting speed of motor, could change it (0-255)  

  cur_pot_tilt = analogRead(inputPin);            //Start calibration by reading potentiometers

  while(cur_pot_tilt != 135) {                    //Calibrating the Tilting Motor
    if(cur_pot_tilt > 135) {
      TiltMotor->run(FORWARD);                   //Motor will move to position value 135 (Center)
    }
    else if(cur_pot_tilt < 135) {
      TiltMotor->run(BACKWARD);
    }
    cur_pot_tilt = analogRead(inputPin);
  }

    TiltMotor->run(RELEASE);                     //Finished calibrating Tilting Motor, stopping motor
}

void home_camera() {
  move_camera(panHome,tiltHome);
}

Speed

Post by Andrew Le

Testing conducted by Eduardo Contreras, Jimmy Fernandez, and Santiago Landazuri

After calibrating and tweaking the tracks’ tension, grip on surface, and hold on the wheels (wheelslip), test runs were conducted.

Speed Tests

To test typical speed of the Rover, a yardstick was used to measure distance. A stop watch was then used to find the time the rover takes to travel one yard. This information was then used to calculate the speed of the rover. This process was repeated five times to find the average speed over five trial runs. To simulate typical speed of the rover while traversing terrain in the field, a raised ruler and a 1/4 inch diameter stick were placed in the path.

We found that the average speed of the rover during typical operating conditions is .21m/s. 

This meets and exceeds our required speed to traverse our 50m course in 15 minutes, 0.0556 m/s.

Calculations:

Distance = 3ft = 1 yard = 0.9144m

Screen Shot 2013-12-10 at 7.44.55 AM

Weights were substituted while rover head was under modification.

The rover’s tracks and wheels now operate correctly with proper tension and traction, without wheelslip.

Battery Comparisons

NiCd vs NiMH vs. LiPo Battery Packs

By Jimmy Fernandez – Systems Engineer

Abstract

In this study, we are researching the best battery pack to use for our Tracked Rover project.  While each of the batteries have their pros and cons, the properties of our chosen battery must satisfy our project requirements.  The choice ultimately comes down to a NiMH battery pack.

Objective

The objective of this study is to determine the best battery pack type for a Tracked Rover.  The main criteria is safety, then capacity and discharge rate.  These packs are the most commonly used battery packs in RC cars and similar applications.  Note that this is a qualitative analysis rather quantitative, this will help narrow battery pack choices to a certain type so that capacity can be determined.

Theory

  • Lithium Polymer – LiPoT-RCB-1013-3__Lithium-Polymer-Battery
    • Pro – Very high capacity, lightweight, good discharge rate
    • Con – More likely to catch on fire if discharged too low or overcharged.  Expands with high levels of static charge.
  • Nickel-Metal Hyrdride – NiMHimage_18264
    • Pro – Higher capacity than NiCd, but lower than LiPo
    • Con – High rate of self-discharge.  Best to recharge before use.  Less environmental impact than NiCd
  • Nickel Cadmium – NiCdnicd
    • Pro – Good discharge rate. Can charge quickly.  Lower internal resistance.
    • Con – Lowest capacity of the three.  Cost more than NiMH

Conclusion

In an effort to be more cost effective while still maintaining the mission length and personnel safety, the best choice is NiMH.  In general, its capacity is large while still being cost-efficient.  LiPo has safety concerns that could be made readily apparent to those who have never worked the battery type.  NiCd in theory does not have the capacity needed while maintaining a cost-effective price-point.

Sources

http://daringrey.com/lipo_nimh_nicd_battery_maintenance.htm

http://www.servocity.com/html/nicad_vs__nimh_batteries.html

http://www.faa.gov/about/office_org/headquarters_offices/ash/ash_programs/hazmat/aircarrier_info/media/Battery_incident_chart.pdf

DC Motor to Servo Conversion Beta Code

By Eduardo Contreras – Computer, Power, and Powertrain

The following code is a beta version of converting a dc motor into a servo:

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"

Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 

Adafruit_DCMotor *myMotor = AFMS.getMotor(1);

const int deg_error = 15;

int cur_pot = 0;
int new_pot = 160;

int inputPin = A0;

void setup()
{
  // initialize serial communication with computer:
  Serial.begin(9600);       

  AFMS.begin();
  myMotor->setSpeed(50);         

    cur_pot = analogRead(inputPin);

    while(cur_pot != 160) {
     if(cur_pot > 160) {
    myMotor->run(BACKWARD);
     }
     else if(cur_pot < 160) {
       myMotor->run(FORWARD);
     }
   cur_pot = analogRead(inputPin);  
    }
    myMotor->run(RELEASE);
    Serial.println("Calibration Done!");
    delay(1000);
}

void loop() {
  check_input();

  Serial.println(cur_pot);   

  while(cur_pot >= new_pot + deg_error || cur_pot <= new_pot - deg_error) {
    if( cur_pot > new_pot) {
      myMotor->run(BACKWARD);
    }
    else if( cur_pot < new_pot) {
      myMotor->run(FORWARD);
    }
    cur_pot = analogRead(inputPin);
  }
  myMotor->run(RELEASE);
  cur_pot = analogRead(inputPin) 
}

void check_input() {
  if ( Serial.available()) {
    char ch = Serial.read();

    switch(ch) {       
      case 'r':
        Serial.println("Move Right");
        new_pot = cur_pot + 115;
        break;
      case 'l':
        Serial.println("Move Left");
        new_pot = cur_pot - 115;
        break;
    }
  }
}

For connections, see Figure 1 below:

Figure 1: Connections for the Arduino Motor Shield, with the motor and analog potentiometer connected. The potentiometer will be used to detect the position of the motor.

Figure 1: Connections for the Arduino Motor Shield, with the motor and analog potentiometer connected. The potentiometer will be used to detect the position of the motor.

Note: The idea for this is for both shafts from the motor and potentiometer to be connected together so that the potentiometer will turn whenever the motor moves in any direction and will keep that position saved in a variable, here called cur_pot.

Before letting the user command the motor to move, it will need to reset its position to a predetermined position. In this case, it will move until the Arduino reads the potentiometer at a certain value, here being 160. After it is in position, the user will be able to tell the Arduino to move the motor.

When the user wants to turn the motor, the user will either type ‘r’, which will turn right, or ‘l’, which will turn left. This is done by incrementing, to turn right, or decrementing, to turn left, a second variable, new_pot, and have the Arduino compare this value to the current reading from the potentiometer. Depending on the value, the motor will either run forward or backwards, trying to reach the second variable number. After it reaches the value, the motor will stop. If the position changes from an outside force, the code will try to go back to the previous value. Afterwards, the user can type another instruction to turn either left or right.

The following video demonstrates how the code works:

Tread Development

Tread Development Progress

By Julian Sanz – Manufacturing, 3D Printing

The original tank tread for the Rover is a single continuous printed piece. It is actually a reconstruction of a 3D printed bracelet. It had undulations that would allow it to stretch slightly due to nylon’s flexibility. This allowed the tread to snap on around the gears that would move the tread and thus the Rover. The reconstruction included having divots for the teeth of the gear to move the tread. This system was ingenious in that it created a single track with no extra parts needed to keep it together, like metal pins, secured between the individual pieces of the track. There was also the added benefit that it would move as one cohesive piece and not as multiple pieces pulling each other and coming loose.

The single continuous track design has many flaws, though they mostly lie more in the 3D printer than the design of the tread itself. The printing process could take 6-8 hours, and the longer a print takes, the higher the probability for a problem to occur in the printing process. Inherent problems with the printing process include, but are not limited to the following: the printer running out of filament to print, the printer gets off its axis, the printer makes a mistake while printing (either too much or not enough filament, there is a miscommunication between the printer and the computer resulting in skipping a section, etc). A flaw with the design of one single piece is that if there is a small imperfection due to printing or from damage, the whole thing must be reprinted. This is solved by having multiple smaller pieces.

1

Figure 1: Hook and Bar method

Tread_3

Hook Model

The challenge proposed by Professor Hill was to have interlocking pieces that do not require external pieces to keep them together. It was also suggested that they come together one way, but, due to their usage, do not come apart during regular operation. Originally, my design involved a hook method of keeping the treads together (see Fig. 1). The problem with this method was that it as the tank tread would be pulled upwards, there was a possibility of slipping out. Even if it was reversed with the hook facing downwards, the tread would have had to be perfectly taut to not come apart when upside down passing from the front gear to the rear gear. The design for the tread evolved to something more along the lines of the added suggestion of the pieces fitting together one way and not coming apart during normal operation.

2

Figure 2: C-bar and L-bar

There are two main designs in figure 2, starting with the right: L-bar and C-bar. The third drawing in figure 2 (lower) on the left shows the attempt to adapt the L-bar since the design of the L-bar would have been impossible to put together do to the angle of entrance for the L-bar. The C-bar design took the L-bar and curved the design as to allow it to enter the area of operation. The problem with the C-bar was that it allowed too much movement within the area of rotation and due to the curvature of the bar, allowed no secure method of pulling the tank treads. The C-bar design eventually became the Sheath method, where instead of allowing a point of rotation for the upward tilt of the front tank tread, as in the L and C-bar designs, it had more gap in the rotational direction of the C bar, allowing it to delve deeper when the front tread rotates upward. See Figure 3 for visualization.

Figure 3: Sheath Method

Figure 3: Sheath Method

Left: the treads are moving linearly. Right: the forward tread is being pulled up by the gear.

The issues raised by the Sheath method were mostly theoretical. Being very similar to the previous methods, it was speculated that similar problems would arise. We weren’t sure how well the two treads would pull on one another, though the second situation (where the front tread is pulled up by the gear) seemed promising. Fitting the pieces together seemed problematic due to the angle of the entrance. The way they would be fitted together would be to put the two pieces at the opposite angle of the second situation, making a peak (^) instead of a valley (V) between the two pieces. In the end, a different design was brought to my attention for interlocking pieces and it solved the problem of putting the parts together.

The new design is called the T-turn (T-lock) method. This is radically different from all of the previous designs. It’s based on the design that was initially found in interlocking scissors to allow for quick and easy separation for cleaning. With a little readjustment, I turned it into a design that can, when adjusted correctly, only rotates vertically and not horizontally. Two tank treads would be pieced together by rotating the back tread perpendicular to the front tread, inserting the T into the hole, rotating the back tread back so it’s inline with the front tread, and then pulled back to secure it into the divot. A fourth figure will be presented soon.

After deciding what locking mechanism to use, I took to Solidworks. Since I had never worked with Solidworks before, the progress was slow, but steady thanks to the Solidworks tutorials by Shawn. I had a number of setbacks and problems due to a lack of foresight and unfamiliarity with Solidworks. Initially I had made my design with the unit of meters, rather than millimeters, which is obviously a giant blunder due to the fact that the rover won’t be anywhere close to a meter in any direction. The next problem was that I hadn’t connected the measurements of the part to be in proportion to the body of the continuous track. When changing the proportion of the body, this caused a lot of problems with changing the distances for the inner components. Eventually, I finished the design for the continuous track and was ready to start on the gear. Initially, the original gear was going to be used, but due a revolved and angled structure, it was abandoned for complexity of application of design to the continuous track. Not only for its complexity to a new solidworks user, but more importantly, it worked with the old design of the continuous track, not with the new form I had created. What I did then was copy all of the components of the gear into a new program, with a couple alterations for my continuous track. One of the changes was to decrease the number of teeth on the gear to 15 so there wouldn’t be too much of a difference to the dimensions to the continuous track.

Final_Tread_1

Figure 4: Final Tread Model

Final_Tread_3

Figure 5: Final Tread Underside

 

 

Detailed Cost

Bill of Materials

By Andrew Le – Project Manager

See list below for detailed bill of materials with description and vendor sources:

Read more

Resource Report

Resource Report – Power/Mass

By Jimmy Fernandez – Systems Engineer

Power consumption and mass resource reports for the Rover Project are provided below:

Read more

Interface Definitions

Interface Definitions

By Jimmy Fernandez – Systems Engineer

A schematic for the interface definition and a system resource table was generated for the Rover Project.

Read more

System and Subsystem Requirements

Level 2 and Level 3 Requirements

By Jimmy Fernandez – Systems Engineer

System Requirements

System requirements for the Rover Project were derived from our on-field testing results and planned course route. Specific system requirements were formed by these field surveying tests. These requirements are necessary to fulfill our top level mission requirements.

Read more