gopher tortoise scope redesign

59
Gopher Tortoise Scope Redesign Xiangzhen Sun 1 Itiel Agramonte 2 Submitted On: December 11, 2015 EML5930 – Mechatronics II Dr. Clark Fall 2015 1

Upload: xiangzhen-sun

Post on 15-Feb-2017

104 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Gopher Tortoise Scope Redesign

Gopher Tortoise Scope Redesign

Xiangzhen Sun1

Itiel Agramonte2

Submitted On:December 11, 2015

EML5930 – Mechatronics IIDr. ClarkFall 2015

1

Page 2: Gopher Tortoise Scope Redesign

Table of Contents

Title and Group Member Information……………………………………………………1

I. Project Overview………………………………………………………………………3 1. Research Background………………………………………………………………3 2. Design Requirements……………………………………………………………….3 3. Design Objectives…………………………………………………………………..4 4. Design Constraints………………………………………………………………….4

II. Exploration, Analysis, and Design…………………………………………………....5 1. Functional Analysis…………………………………………………………………5 2. Overall Circuitry……………………………………………………………………7 3. Electrical Design…………………………………………………………………....9 3.1 Circuitry of Microprocessor…………………………………………………….9 3.1.1 Gamepad Control…………………………………………………………..9 3.1.2 Video Streaming & Image Capture………………………….....................11 3.2 Circuitry of Microcontroller………………………………………………..…13 3.2.1 Temperature/Humidity Sensor……………………………………………13 3.2.2 Encoder…………………………………………………………………...14 3.2.3 Control Algorithm………………………………………………………..16 3.3 Data Communication and Power plan………………………….......................18

4. Mechanical Design………………………………………………………………...20 4.1 Design Consideration………………………………………………………….20 4.2 Motor Torque Calculation……………………………………………………..21 4.3 Chamber Design……………………………………………………………….21 4.4 Transmission Design…………………………………………………………..22 4.5 Camera Design…………………………………………………… …………..23 4.6 Manufacturing and Assembly …………………………………………………23

III. Challenges………………………………………………………………………….25

IV. Conclusion and Future Work………………………………………………………25

V. Appendix……………………………………………………………………………26.

2

Page 3: Gopher Tortoise Scope Redesign

I. Project OverviewInitial background with respect to gopher tortoise along with currently commercial scopes will be introduced in this section. The necessity as well as major constraints of proposed project design will be introduced.

1. Research BackgroundTortoise has a large effect on its surrounding ecosystem mainly because of its burrow provides shelter for many species. This fact provides the study of the animal enough impetus, especially for a research station such as Tall Timbers which specializes in fire ecology studies. Gopher tortoises however are not the only burrowing animals that require a scope in order to be studied. Other animals like foxes and small mammals are also burrowing too. To meet this need for research equipment, Sandpiper Technologies, INC. introduced the Peeper 2000. Its system has the benefits of being lightweight as well as waterproof. However, given further insights into Sandpiper system, the major drawback of costing 6,000 dollars apiece becomes a concern. This is generally out of the budget of research centers such as Tall Timbers, leaving them still without a scope. In order to meet this need, Tall Timbers built their own scope for a total of about 500 dollars. It is however outdated and slightly crude in design, consisting of an infrared camera connected via long detachable wires to a portable DVD player. The wires are protected by thick rubber hosing. This hosing has proven to be heavy as well as not easily navigated through the burrow, and the DVD player is not waterproof.

The creation of a scope that is on the technological level of Sandpiper’s Peeper 2000 while also costing less than 1000 dollars would be pivotal for research centers such as Tall Timbers, and could do a great deal of good for the advancement of the study of many burrowing keystone species, not only the gopher tortoise.

Tall Timbers Research Station and Land Conservancy originally tasked the mechanical engineering senior design Team 21, from the fall of 2014 semester, to develop a system for entering the burrows of the Gopher Tortoise to monitor the population of the tortoises. Their requirements include remote control vehicle to drive into the burrows with an IR camera attached to it and they would also like the ability to read the temperature and humidity data from the burrows. The dimensions of the robot were to be a max of 4inx6inx10in with a max weight of 40 pounds.

Team 21 developed a robot that would be driven into the burrows with an IR camera and also monitor the temperature and humidity within the burrows. The initial design, though functional and water proof, was too large to enter the burrows and move over the angled environment within the burrows. It met the height, width, and weight constraints but was over a foot in length. The team, this year, has been tasked with optimizing the body of the robot itself and improving functionality.

2. Design RequirementsThe previous design is cumbersome for several reasons. In order to observe through scope, user have to control the motion of servo-camera with gamepad, which is redundant. This process can be replaced by adjusting the position of robot body. Original Design results in longer body length. Thus, the camera can easily dig into the ground and get blocked by dirt. It is difficult to

3

Page 4: Gopher Tortoise Scope Redesign

navigate the scope, as there is nothing to help it move forward, backwards or navigate turns. Because of this lack of maneuverability, many parts of the burrows are unreachable for observation. The scope plus rover, which involve many large components, are heavy and bulky. By the end of the day, the sponsor related that her hands would be covered in blisters from having to physically handle the heavy equipment for eight or more hours. Besides, there are no video or picture-capturing capabilities with the current model.

Requirements Summary:To sum up, there is a need for gopher scopes to have weather and impact durability, greater mobility, data-acquisition capability, and reduced weight, space especially body length and width.

3. Design ObjectivesIt is essential for scoping system to be resistant to water as well as dirt, and be able to withstand temperatures from 0 to 100°F due to the fact that it will be used in the field. It should be resistant to shock as well in case it is dropped or hits any obstacles. The battery life should last for as long as it takes to complete full days of field testing and the entire system should fit into a backpack and weigh less than the current scope at Tall Timbers.

Gopher tortoises begin to burrow as soon as they hatch with some of their burrows being as small as 4 to 6 inches. Because of this, the scope should be small enough to navigate inside these smaller burrows. Not disturbing the animals in the burrow is important as well, therefore the camera will be infrared and the rover will move as quietly and quickly down the burrow as possible. The camera should be able to record images, capture still photos and take temperature and humidity readings in the burrow. The main goal is to design a mechanism that has testing sensors, better durability, and more advanced video capabilities than the current system in order to enhance the surveying process of gopher tortoises. Most importantly, the dimension of the whole mechanism should be constrained within a small space as small as a normal burrow.

4. Design ConstraintsThe following is a list of the constraints of the project. Solving the constraints is crucial to the success of the project redesign and will allow my team to provide a fully functioning scope to presentation.a. The rover must not be more than 7 inches wide, 10 inches long, and 4 inches highb. The entire system must remain under 50lbsc. The entire system must be water proofd. The duration of system operation has to target 8 hourse. The selected motors need be small enough to be housed in chamber, and provide enough torque.f. User friendly control panel versus multifunctional operation system.

4

Page 5: Gopher Tortoise Scope Redesign

II. Exploration, Analysis, and DesignIn this part, we will go through all details in designing this project along with specific considerations. Moreover, we will also discuss on functions that are being developed but not fully completed. Possible solutions and our exploration processes will be attached.

1. Function AnalysisWhile constrained by malfunctions contained in previous design, several primary specifications affect the overall design of the scope at the same time. The most important of these is cost. The cost for the entire redesign project cost should be no more than $100 from Dr. Clark and rest costs have to be covered by us. The weight and size of the final design is also important to consider, as one person must be able to carry the scope for several miles. For this reason, the full system must weigh no more than 50 pounds and fit in a backpack.

Mechanical subsystems have additional specifications that must also be considered when creating the final design. In order to fit into even the smallest of gopher tortoise burrows, both the height of body and the diameter of rover should be approximately four inches. It will also need to be maneuverable enough to make tight turns, and have good enough traction to be able to function in wet and muddy conditions. To handle these requirements, a body is designed that is 4 inches from one edge of the track to the other. The height of this rover above ground is currently about 1 inch, since most burrows are oval in shape. It will have a treaded design that allows it traction to overcome the resistance from the tether, as well as resistance from obstacles within the burrow. The force that is provided to the treads is about 35 N, while the preliminary estimate for static tether friction force is only about 5.4 N. This yields enough net force for the rover to overcome obstacles. Just how competent it is at doing so will be determined in field testing.

Current tread dimensions for the rover allows a contact patch of about 52 cm. This allows it to have greater traction. The material for the treads must be durable and withstand tension and shock. Sectioned rough patches can be attached to the tread to give it additional tractive force. A challenge arises in finding the proper length belt for the track. It is possible that a desired track product has a length determined by the manufacturer. Hence, the rover wheelbase and body may have to adjust to fit the treads.

The body itself is going to be enclosed in ABS. This material is easy to acquire, relatively inexpensive to cut, and has unique capabilities. The front camera that will be mounted to the dome chassis needs to be infrared capable. In order to mitigate glare, the orientation of the dome cover in front of the camera will be modified.

In addition to the casing material, the body also needs to be weatherproof. Namely, it needs to be water and dirt resistant in order to survive in burrows that are dug into the earth. Hence, special attention must be given to the type of adhesive used to seal out any potential debris, as well as the type of sealing for each wheel axle (so that dirt and water do not seep in through the axles that protrude out of the body).

5

Page 6: Gopher Tortoise Scope Redesign

The body must be strong enough to withstand the weight of the internal components as well as shock from external forces. The high strength of the ABS (110MPa yield strength, 115MPa flexural strength) ensures that it can withstand the impact of colliding with an object at the rover’s top speed, as well as not fatigue under the load of all of the components being fastened to it.

In previous design, a pan-and-tilt system is a major desire by the sponsor. Yet it turns out to be redundant now. Even with a small camera, the need for the camera rotation, as well as the need for a mounting frame that the camera sits in, means that small space will be an issue for the pan-tilt system. The rover will be dependent on a tether. Gopher tortoise burrows can reach up to 15 m in length, and almost 5 m deep. Hence, sending a wireless rover increases the risk of losing the rover within the burrow. With a tether, even if power is lost to the rover, it can still be physically pulled out of the rover. A tether also allows for the power source (battery) to be above ground, transmitting power to the rover through the tether. Hence, the tether will have wires to control the rover, as well as having a tension guide wire (perhaps a steel cable) to relieve tension from the electronics cables. The tether is to have a tough yet flexible exterior. It is desired that a Kevlar material sheath can be used to protect the wires, while not being too rigid or large.

Logitech F310 gamepad was chosen because it has drivers that work with the Raspberry Pi series. Established library with member functions handling gamepad events is provided. Having an intuitive user input is a great way to make the learning curve very low. The two joysticks each control two sets of motors: rover left tread and right tread The USB inputs from the gamepad can be translated to keyboard inputs which will be read by Linux based scripts. Maximum current draw from the gamepad is 400mA at 5V.Raspberry Pi B+ has a 700 MHz CPU and a very capable GPU to handle the data input/output. The four USB ports are also useful in receiving input from the RCA/USB adaptor for video feed, the gamepad for user input, power and data to the Arduino micro. The raspberry pi b+ has a current draw range of 600mA to 1.8A at 5V.

The lithium ion battery is 12V and has a capacity of 14AH. If the current drawn from the system is an estimated 6A, then the system can operate for 2.5 hours continuously. The battery weighs only 0.75kg so if the energy capacity is not enough for a full 8 hour day of operation then a

second battery can be purchased and easily replace the drained battery when needed. The rover system is not expected to be operating longer than a continuous 3 hours out of the 8 hour work day so the battery may be sufficient. There is a power converter from 12V to 5V 3A USB port that will power the screen and raspberry pi b+ with a USB splitter. A DC-DC

6

Page 7: Gopher Tortoise Scope Redesign

converter needs to be purchased to deliver continuous 12V output to the camera and motor drivers.

Arduino Micro is small in size although not the smallest of its type. But it has ample performance in the CPU to read the USB input from the raspberry pi b+ and output PWM signals through the GPIO pins. The GPIOs will also be replaced by USB cable connection for temperature and humidity sensor input. The maximum current draw of the Arduino micro is 50mA at 5V.

Motor drivers use a L298 chip to read the PWM signal from the Arduino to change the power outputted to the motors. Each motor driver has signal input and output for two motors. Each motor driver has an input of 12V and the current draw changes based on the load of the motor.

Easy Cap DC60 RCA to USB adaptor converters the RCA video feed from the camera, and converts it to USB signal. This adaptor was chosen because there are drivers and other projects that use this device on the raspberry pi b+. There is a 0.4 second delay because of the analog to digital data conversion. The maximum power draw of the adaptor is 250mA at 5V.

The size of the 7-inch screen has been proven by mass produced products as a great size for mobile monitors. The screen is the same resolution of 800x480 pixels as the camera feed. This does not allow for distorted image quality. Having a USB for power will make for easy integration into the system by adding a USB hub to the 5V 3A adaptor source from the battery. The maximum current draw is 500mA at 5V.

2. Overall CircuitryIt is helpful to refer to electrical schematic in this part for user to operate even debug every subsystems. The user interface electrical components are connected as follow:

The Raspberry Pi B+ has an HDMI male/male coupler connected to the screen driver. The micro USB connected on the pi is connected to the USB splitter on the 5 V buck/boost converter. The USB hub is connected to the Raspberry Pi B+ through a type-A and type-B USB connection for data.

7

Page 8: Gopher Tortoise Scope Redesign

The screen driver connects to the screen through two multi-pin connectors for power and data. The screen driver has a barrel connection that is powered by 12 V buck/boost converter on the terminal block.

The USB hub is powered by a USB to barrel connector wire from the USB splitter on the 5 V buck converter. The gamepad, RCA to USB Adapter, and tether active USB cable are connected to the USB hub.

The RCA to USB adapter has the tether RCA connected to the yellow male connection. The two buck/boost converters are connected to the battery through a screw terminal. The battery is then connected with the ring terminal wires to the interface casing.

The rover components are connected as follow:

The tether has power from the battery screw terminal to the rover’s 12 V buck/boost converter. The 12 V output is connected to a screw terminal where the camera and motor driver receive power. The screw terminal’s ground is connected to the camera, motor driver, DHT22, and the Arduino Micro.

8

Page 9: Gopher Tortoise Scope Redesign

The motor driver is connected to the two rover motors on pins AB and CD. The 5 V output of the motor driver is connected to a screw terminal where the DHT22 receive power. The motor driver’s two 3-pin signal inputs are connected through a ribbon cable to the Arduino Micro’s pin # 3 – 8.

The Arduino Micro’s pin #9 is connected to the DHT22. The micro USB connection is from the tether active USB.The camera is connected to the tether RCA cable to output video signal.

3. Electrical DesignThis section helps user understand why and how each components being selected and connected is specific ways.

3.1 Circuitry of Microprocessor

3.1.1 Gamepad Control A majority of the I/O and data processing will be handled by the Raspberry Pi B+ located in the User Interface. For this reason, a majority of the code written will also be for the Raspberry Pi. The most critical code will be that which reads in user input from the gamepad joysticks and then makes the rover motors, and pan and tilt motors spin accordingly. When a user moves one of the joysticks on the user interface, the gamepad sends two integer values to the Raspberry Pi; a horizontal coordinate ranging from -32,767 to 32,768 and a vertical coordinate also ranging from -32,767 to 32,768. In order to turn these horizontal and vertical coordinates into useful directions for the motors, they are converted into polar coordinates and the charts below are used.Button Press CommandY Read SensorMode Pause driveSelect Shutdown Raspberry PiJoystick Drive patternFull UP Left, Full UP Right Full speed forwardHalf UP Left, Half UP Right Half speed forwardFull Down Left, Full Down Right Full speed backwardHalf Down Left, Half Down Right Half speed backwardFull UP Left, Full Down Right Full speed CWHalf UP Left, Half Down Right Half speed CWFull Down Left, Full UP Right Full speed CCWHalf Down Left, Half UP Right Half speed CCW

9

Page 10: Gopher Tortoise Scope Redesign

No direction, No direction BreakFull UP Left, Half UP Right Left forwardHalf UP Left, Full UP Right Right ForwardFull Down Left, Half Down Right Left backwardHalf Down Left, Full Down Right Right backward

For the Rover motors, the chart above is used. The domain of possible joystick inputs is represented as a circle. Radially, the circle is divided into 8 sections, corresponding to the direction that the rover will move for a given angle of the joystick. The domain of possible inputs is further broken up into three concentric circles. If the magnitude of the joysticks position falls into the red circle, then the rover will stop for brake. The yellow circle corresponds to slow movement, and the green circle fast movement. Overall, the domain of possible user inputs is dived into 24 sections.

Once the Raspberry Pi reads in which of the 24 possible cases has been selected by the user, a five bit code is sent to the Arduino. Using this and the information in the following table, the Arduino is able to send the proper signals to the motor drivers to move the rover as the user instructed. In order to limit the amount of data being sent between the Raspberry Pi B+ and Arduino, the Arduino will continue to drive the motors in this way until a change in the user input is detected by the Raspberry Pi B+.

10

Page 11: Gopher Tortoise Scope Redesign

3.1.2 Video Streaming & Image CaptureThe video streaming requirement decides selection of microprocessor as Raspberry Pi B+. Before talking about the method we employed streaming video lively, it is necessary to give reason upon processor and graphic driver selection. While power consumption is an important consideration for the overall design, the difference in power usage between most microprocessors is small enough that it does not have a large impact on the design. Similarly, while having a community of consumers that use the microprocessors can aid in programming

11

Page 12: Gopher Tortoise Scope Redesign

and make spare parts easier to obtain, it is not thought to be important enough to heavily influence which microprocessor we use.

The selection criteria were determined to be the graphics, memory, expandability and overall cost. Graphics are a necessity because the end-user must have a live feed of the camera input. It is also one of the major performance differences between the two microprocessors being considered and it is important that this difference be accounted for in the decision matrix. Memory is weighted as average importance because it is needed to record video and images along with keeping the operating system of the microprocessor onboard. Expandability refers to the number of add-on devices that have been designed specifically for the microprocessors by manufactures such as Adafruit and SparkFun. These add on devices can give the microprocessors LCD screen or temperature sensor capabilities without the team having to design custom options. However, since this is not a necessity to complete the design, it was given a lower weight. Cost was given a slightly higher weight since a major part of the design is to make the rover cost effective. The cost category does not just account for the cost of the microprocessor, but also the cost of the necessary peripherals such as microSD cards or USB cables.

The microprocessor will be the hub for the majority of the data being input and output to our system. The processor will need to have a high enough clock speed in order to make the device function with as little lag as possible and ensure a good end-user experience. What connectivity options are available on the microprocessor will also determine how well the final design works. Available input and output ports can include but are not limited to USB, HDMI, RCA, GPIO, I2C and CAN. The more options available, the more likely a product that will be compatible and meet the criteria will be found.

Before editing video stream feature, my group first ran the method employed by previous design group. It turns out that their method does not work but somehow they did not realized reason. Through research, we found that the microprocessor that has been selected does not support video streaming through the player (m-player) that’s preinstalled in Raspbian OS. Later version of Pi series may support this function. However, under the consideration of great cost on replacing microprocessor, we decided to keep using the current microprocessor, while streaming video lively through VGA cable. Anyway, if it is not streaming video on web, there is no necessity to pomp up preinstalled player software in Raspberry pi. This is the first adaption we made on streaming video. By doing that, however, we lose the functionality of taking picture while streaming video. Based on that requirement, we tried to put a tiny web camera aligned with IR camera. In this way, two camera work simultaneously to achieve streaming video and taking snapshot without losing any functionality. To take snapshot, we created a new folder for storing pictures in jpeg format, and create shortcut executable file on desktop using following command (SDL lib supposed to be installed first):

system (device=/dev/video0:fps=1:noaudio:outfmt=uyvy:fps=10 -vo jpeg -frames 3 -fs -vf format=y8,scale -hardframedrop &");

12

Page 13: Gopher Tortoise Scope Redesign

In Align

Web Camera

+5 V

We successfully took a picture by double clicking mouse on desktop icon. However, we failed to initialize the snapshot.exe file on startup. In other word, user has to type long command lines in Xterminal to reinitialize snapshot.exe, which is not desirable. So we gave up this functionality.

3.2 Circuitry of MicrocontrollerIn this section, all parts directly connected to microcontroller (Arduino Micro) will be introduced. Meanwhile, functions realization of each components correlated will also be specified.

3.2.1 Temperature/Humidity Sensor

13

Page 14: Gopher Tortoise Scope Redesign

The DHT22 sensor is manufactured by USPRO. Temperature and humidity is measured by the sensor every two seconds. Temperature precision is 0.5 degrees Celsius. Humidity procession is 0.05% relative humidity. The USPRO model is used because of a built-in series resistor and capacitor on an integrated circuit board.

The microcontroller will have to send and receive data from the microprocessor as well as control four motors and read inputs from two sensors.Arduino Micro is small in size and has ample performance in the CPU to read the USB input from the Raspberry Pi b+ and output PWM signals through the GPIO pins. The GPIOs will also be used for a 4 pin temperature and humidity sensor input. The maximum current draw of the Arduino micro is 50mA at 5V.

Since there is only one USB connecting the Raspberry Pi b+ to the Arduino, it is important the two devices coordinate with one another so that all messages are sent and received properly. In order to achieve this, the default states of the devices will be the Raspberry Pi b+ transmitting data and the Arduino receiving data. This will only change when the Raspberry Pi b+ requests that the Arduino send it data. This request will only be sent once every ten seconds. When it is sent, the Arduino will poll the temperature and humidity sensors and then send the collected data back to the Raspberry Pi b+ to be displayed on the User Interface. The Arduino will then go back to listening for motor control data from the Raspberry Pi b+.

3.2.2 EncoderIt is important to verify how many counts per revolution of selected DC motor with encoder. By running the following program, we verified the encoder along with motor encoder precision:

int val; int encoder0PinA = 3; int encoder0PinB = 4; int encoder0Pos = 0; int encoder0PinALast = LOW; int n = LOW;

void setup() { pinMode (encoder0PinA,INPUT); pinMode (encoder0PinB,INPUT); Serial.begin (9600); }

void loop() { n = digitalRead(encoder0PinA); if ((encoder0PinALast == LOW) && (n == HIGH)) { if (digitalRead(encoder0PinB) == LOW) { encoder0Pos--; } else { encoder0Pos++;

14

Page 15: Gopher Tortoise Scope Redesign

} Serial.print (encoder0Pos); Serial.print ("/"); } encoder0PinALast = n; }

The motor we selected has encoder with six pins. The functionality of each pin is defined as follow:

Red Pin Motor+Black Pin Motor-Green Pin GNDBlue Pin VccYellow Pin Vout-AWhite Pin Vout-B

Since we control two motors separately (see control algorithm part), it is necessary to bring two sets of encoder pins into Arduino PWM pin connections. We connected encoder 1 Vout-A to pin# 2, encoder 1 Vout-B to pin# 10, encoder 2 Vout-A to pin # 3, encoder 2 Vout-B to pin # 11. To detect any pulse indicating encoder rotates by one step, we defined counter + 1 while voltage at interrupter pin (pin 2 and pin 3) falling from high to low. Actually, you can also define a raising voltage as counter – 1 on the other hand.

To make use of default interrupter predefined in Arduino Micro, we can simply attach interrupt mode by calling the following phrase:

attachInterrupt(digitalPinToInterrupt(pin2), counter1++, Falling);attachInterrupt(digitalPinToInterrupt(pin3), counter2++, Falling);

15

Page 16: Gopher Tortoise Scope Redesign

In Arduino setup() section, we also need to define Interrupt Service Routines so that counter understands the behavior of encoder. Generally, an ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be executed after the current one finishes in an order that depends on the priority they have. millis() relies on interrupts to count, so it will never increment inside an ISR. Since delay() requires interrupts to work, it will not work if called inside an ISR. micros() works initially, but will start behaving erratically after 1-2 ms.delayMicroseconds() does not use any counter, so it will work as normal.

Typically global variables are used to pass data between an ISR and the main program. To make sure variables shared between an ISR and the main program are updated correctly, declare them as volatile.

3.2.3 Control AlgorithmIn this section, we will specify how we add controller to control the speed of motor spinning. What comes first is the concern about motor speed difference. If two motors have speed difference, it is difficult to adjust this expanding error by controlling joysticks, even if we have defined CW, CCW rotation. Below is a control diagram of proposed control algorithm

Next, we will use pseudo codes to demonstrate and give reason to proposed control algorithm.

Here’s the code for the equation we used. The gain constants are set in the code, but could be made programmable through some other interface.

void CalculatePD(void){// Set constants here PTerm = 10; DTerm = 0.7; Divider = 10;

// Calculate the PD Accumulator += Error[0]; // accumulator is sum of errors PD = Error[0]*PTerm; // start with proportional gain PD += DTerm*(Error[0]-Error[9]); // differential gain comes next

Here are the major components of our PD controller in detail.

16

Page 17: Gopher Tortoise Scope Redesign

Error Signal: At the heart of PD control is a need to measure an error signal. In this case it is the desired speed (voltage from the pot) minus the actual speed (voltage from the encoder). The error value is signed.

void GetError(void){ byte i = 0;

// read analogs word ActualSpeed = analogRead(ActSpd);

word DesiredSpeed = analogRead(DesSpd);

// shift error values for(i=9;i>0;i--) Error[i] = Error[i-1];

// load new error into top array spot Error[0] = (long)DesiredSpeed-(long)ActualSpeed;

}

PTerm: The error signal is multiplied the P term and this provides most of the “umph” behind the motor’s movement. A negative error signal causes the P term create a negative motor movement. Likewise, if my error signal is 0 then the P term has no impact on the motor.

PD = Error[0]*PTerm; // start with proportional gain

In some systems it is important to prevent “windup” of the accumulator (also called saturation). Windup occurs when the small errors build so high that when movement finally occurs it takes a long time for the accumulator to reduce to an insignificant amount. We didn’t add integration term for this reason.

DTerm: While we have the D term in this equation as 0.7, it is not always the same value before tuned in the end. The D term is multiplied by the change in the error signal (error – last error). Sometimes it is useful to store your error measurements in an array and use as last error something a little further back in time. For fast changing systems, like a motor controller, the derivative portion of the PD has little impact unless you make it very large, or compare error signals with adequate time between their sampling. In this code the derivative error is the latest error signal minus the 10th previous error.

PD += DTerm*(Error[0]-Error[9]); // differential gain comes next

Divider: When we put the PD together you get a pretty big value. This value needs to be scaled to a value that matched the pulse-width modulation range for the controller. The Divider does

17

Page 18: Gopher Tortoise Scope Redesign

that. You’ll notice that the division of the PD is accomplished by right-rotates as opposed to division. This is just a faster way of accomplishing the same thing. And the faster our PD loop runs the more responsive it can be to commanded changes.

PD = PD>>Divider; // scale PD down with divider

Converting the PD to PWM: Once your PD is calculated you need to change it to a motor drive signal. The sign of the PD output determines the direction the motor should be driven and the divider previously discussed should get you in the right neighborhood for a final number. Now we make sure the PD register contains a value that’s neither too large nor too small.

If (PD>=127) PD = 127; If (PD<=-126) PD = -126;

//PWM output should be between 1 and 254 so we add to the PD PWMOutput = PD + 127;The PWM pin accepts a range of 1 to 254 (1 = full reverse, 127 = stopped, 254 = full forward). So we want our PD to be in the area of –126 to +127, and we’ll add 127 to it to get our 1-254 range.

Tuning the PD: There are a number of methods of tuning PD algorithms. For a DC motor speed controller using analog signals we start by adjusting your proportional settings until you get rough control. If your proportional term is too high the movement will be sharp and choppy. If too low, it will be slow. This is also when you dial in the divider value to make sure your PD output falls within your PWM requirements.

The settings we used for this design got me to within +/-10 ADC counts within a couple of seconds. That is right at about 1% accuracy or 3.5 degrees for a single rotation.

3.3 Data Communication and Power plan

18

Page 19: Gopher Tortoise Scope Redesign

Above is the top level design for how the projects power and data flow which has been split into above ground and below ground modules. The battery, at full charge, provides 13.4v and will continue to provide power until it is down to 9 volts, and then needs to be charged, with an average run time of 2.5 hours with a 5 hour charge time, with a life time of 800 cycles. The power out from the battery is driven through a DCDC step-up / step-down converter, which allows a constant 12.0v to be outputted from the converter. Through testing with an alternating voltage, it was determined that the buck boost was stable without any ripple showing in the output of the boost. That output is used for all the 12v systems - the video driver, the motors, and the IR RCA camera. The 12v power is also then input into a 5v step down converter, which powers the raspberry pi, the Arduino micro, the DHT22 temperature and humidity sensor, and the encoder for both motors.

19

Page 20: Gopher Tortoise Scope Redesign

The user interface system can be seen above. This portion is above ground and held by the user. The box that the controller is plugged into contains the raspberry pi, and video driver, the step down 5v converter and 12v step-up/step-down converter, with the video display connected to the top of the box. The user may press a button on the remote attached to the box to switch between the RCA input from the IR camera, and the HDMI input from the raspberry pi, which is where the sensor data will display. The tether connection can be seen below. This is how power and data transfer.

Tether Connections

20

Page 21: Gopher Tortoise Scope Redesign

Encoder

Circuit Diagram for rover

The rovers systems can be broken into those components powered by the 12v input from the tether, while the other systems are powered by the motor drivers 5v output. One of the 12v components are the IR camera which uses RCA video with no audio. The others are the motors which are controlled by a motor driver which uses a 12v input and PWM signal to drive the motor speeds, full controlled by the Arduino Micro. The Arduino Micro is controlled by the 5v source, which receives commands from the raspberry pi, and the micro tells all subsystems what to do. The encoders and sensor are also powered by the 5v source.

4. Mechanical DesignIn this section, mechanical design process is mainly talked about, with an emphasis on dimension concerns and corresponding solutions to them. As stated, to rescale previous design to almost ¾ of it, calculation and components selection need to be taken particular care of.

4.1 Design ConsiderationOne of the most important consideration is size/weight. First of all, it is impossible to purchase any commercially available chassis for rover: none of those chassis has the appropriate dimension as required. The triangular tread design however, would be the largest in the vertical direction due to the shape of its treads. Previous design separate rover body into several chassis. By doing so, their design actually increased a lot redundant space even if it guaranteed that each components do not interfere with others. Power consumption was also considered and the wheeled chassis out scored both the linear and triangular treaded chassis due to the fact that the wheeled chassis requires less torque. Treads are specially designed to maneuver over obstacles. Since the linear treads do not have any open spaces that rocks or dirt can become trapped in as compared to the wheeled and triangular tread design, it has the most maneuverability. Portability was the next concern; the wheeled design scored higher than both treaded designs due to the fact that the wheeled design is easier to clean and place in a backpack. With the treads larger surface area, there is more dirt and cleaning required.

4.2 Motor Torque Calculation

21

Page 22: Gopher Tortoise Scope Redesign

We calculated the required torque each DC motor need to generate using the method recommended by previous designers:

clear allH = input('Enter Motor Power in W ');d = input('Enter wheel diameter in mm ');w = input('Enter rotational speed in rpm ');Wt = 60000*H/(pi*w*10);T = (d/2)*Wt;disp(' ')X = ['Torque ' , '= ', num2str(T)];disp(X)disp(' ')disp(' ')end

Enter wheel diameter in mm 10Enter rotational speed in rpm 300Torque 2 = 4.527

So designed torque is around 4.527N.mm.

4.3 Chamber DesignBased on sponsor’s request, we need to constrain our design to a space within 4inx6inx10in with a max weight of 40 pounds. So our main concern becomes the width of the body. The motor we selected need to be placed shoulder to shoulder inside of the chassis, while their width add up to 4.3 inches. Taking the width of two treads and wheels together, the minimum width of rover has to be 6.5 inches, which is only 0.5 inches longer then required width. The other dimensions are all within the range. Below is a picture specifying dimensional information of our chassis design:

22

Page 23: Gopher Tortoise Scope Redesign

The positions of the holes on base plate (to your left) are left for motor mount seats. Camera extrude from the bridge shape front (to your right). It turns out that our design (after assembly) is 3.7 inches high, 6.5 inches wide, and 8.3 inches long.

4.4 Transmission DesignIn order to combat the vibration brought by two motors simultaneously, each motor is not only mounted on base plate, but also onto the side wall nearest to them. In this way, the weight of body can effectively decrease vibration to minimum, protecting circuits inside from being damaged. Below is a 3D simulation drawing that demonstrate the positional relation between components.

23

Page 24: Gopher Tortoise Scope Redesign

4.5 Camera DesignThe IR camera needs protective cover in front of it. This cover should be transparent to infrared as well as water proof when connected with surrounding parts. The way we machine this cover is to cut a surveillance camera cover into two pieces symmetrically, and then put the half cover against front wall of rover chassis with hot glue sealing edges. In this way, this design satisfied proposed requests as it is shown in the following pictures.

4.6 Manufacturing and AssemblyUnless assembling in the correct sequence, it is not possible to put every components of circuit with a limited space in chassis while not interfering the motion of motor shaft and wheel shaft. Below is the assembly view of designed rover. Referring the explosive view, it is recommended to install wheels onto the wheel shafts using M3 screws. Next, leaving wheel assembly apart, put side walls against base plate. After that, you should be able to install two motors into the chassis, using M4 screws. Arrange circuits components correctly and maybe compress extruding wires/cables a little so that every parts sit inside of chassis. Then install the IR camera in front. Connect wheel shafts to motor shafts and install the other two passive wheels by putting shafts inside of drilled holes. Now safely put screen cover and top plate of chassis against each other and use hot glue gun to seal all slots. Finally, install two treads. Treads are detachable, so it is

24

Page 25: Gopher Tortoise Scope Redesign

easier as well as safer to detach a screw from one tread joint, spread tread out, and align tread with wheels before screw down detached joints.

25

Page 26: Gopher Tortoise Scope Redesign

III. ChallengeAs with all projects there are certain risks and challenges that will need to be overcome during the course of this year. One of the major requirements for the rover is for it to be waterproof. The rover body will be encased in ABS, but there will be a point where the wires from the tether will have to run into the casing. The interior of the case must also be accessible, so not all the joints will be permanently sealed. These two areas of the rover will be extra susceptible to water leakage. The tether and the connections at the rover and the user interface will have to be waterproofed. With the tether it is important that the wires themselves are not stressed when the rover is being pulled out. To mitigate this risk a steel guide wire may be placed in the tether sheath along with the wires. This guide wire will take the brunt of the force when the rover is being pulled out of the burrow.

IV. Conclusion and Future WorkWe did not meet the physical width, we were over by half an inch. We also weren’t able to machine the half cylindrical body we envisioned due to a lack of experience with the machinery involved. Another step to making this system full functional would be to waterproof the system. Another system we would like to implement is an image capture system, to take pictures of the screen to store sensor data and images of the current residents of the burrows. We had tried to implement this system using an Easy Cap USB capture devices but it proved to only be functional for previous operating systems of the raspberry pi.

26

Page 27: Gopher Tortoise Scope Redesign

V. Appendix

1.Arduino Code

/*Xiangzhen Sun, Program Description:This program will be loaded to Arduino Uno for motor motion control. Two PD controllers separately control motor on each sides.This entail using two interrupter at the same time.//Description: This program reads in a character from the serial port. This character is then// stored into the variable "cmd". Based of the value of this variable, this code // can perform a variety of tasks. These tasks are outlined in the table below. // Note that the decimal value of ascii characters is used rather than the actual// characters.//// ====================================================================// | COMMAND ACTION | COMMAND ACTION |// |--------------------------------|---------------------------------|// | 96 read temp/humid | 107 slow backward |// | 97 | 108 slow backward, right |// | 98 | 110 fast right |// | 99 | 111 fast forward right |// | 100 breaks | 112 fast forward |// | 101 slow, right | 113 fast forward left |// | 102 slow forward, right | 114 fast left |// | 103 slow forward | 115 fast backward left |// | 104 slow forward, left | 116 fast backward |// | 105 slow left | 117 fast backward, right |// | 106 slow backward left | |// ====================================================================the COMMAND ACTIONs in () in above chart are not avaialb now.*///------------------------------------start---------------------------------------------------//library and setup for the DHT22 temp and humidity sensor#include <DHT.h>#define DHTTYPE DHT22const float pi = 3.14159;unsigned long prev_cmd_time = 0; //time last command was received

27

Page 28: Gopher Tortoise Scope Redesign

const unsigned long dog_time = 3000; //set watch dog timer to 3 secondsconst unsigned int looptime = 100; //PID loop timeunsigned long curr_time; //this variable stores the current time instantunsigned long prev_time = 0; //this variable stores the previous time instantunsigned long delta_time = 0; //this variable stores the time difference//--------------------------------------------------------------------------------------------volatile long count[2] = {0, 0};// rev counter2, and rev counter3 are stored //--------------------------------------------------------------------------------------------//PD control parameters for left, and right motorfloat Kp = 10; //proportional constant;float Kd = 0.7; //derivative constant;//for tuning PD parameters, we are going to keep Kd = 0 at frist, try Kp, and then keep Kp and try different Kd;//--------------------------------------------------------------------------------------------//pin set up for motor controller//Left motor (green block on motor driver)int pinI1 = 5; //define I1 port, blue wire on ribbon cableint pinI2 = 4; //define I2 port, green wireint pinEA = 6; //define EA(PWM speed regulation)port, yellow wire

int encodPinA1 = 10; //define hall effect sensor A Vout;int encodPinB1 = 3; //define hall effect sensor B Vout; digitalPinToInterrupt(pin 2) ;

//Right motor (red block on motor driver)int pinI3 = 7;//define I3 port, orange wireint pinI4 = 8;//define I4 port, red wireint pinEB = 9;//define EB(PWM spped regulation) port, brown wire

int encodPinA2 = 11; //define hall effect sensor A Vout;int encodPinB2 = 2; //define hall effect sensor B Vout; digitalPinToInterrupt(pin 3) ;//--------------------------------------------------------------------------------------------//speed constants for motor controlfloat act_speed[2] = {0, 0}; //actual speed;int PWM_speed[2] = {0 ,0}; //speed converted to PWM value;int last_error1=0;int last_error2=0;long prev_count[2] = {0, 0}; //--------------------------------------------------------------------------------------------//rpm*2*pi(degree per rev)/60(seconds) = rad/s//const float zero_speed = 5 * (2 * pi / 60);//const float quarter_speed = 90 * (2 * pi / 60);const float half_speed = 180 * (2 *pi / 60);//const float three_quarter_speed = 270 * (2 *pi / 60);const float full_speed = 360 * (2 * pi / 60); const int CPR = 8; //counts per revolutionconst int pause=100; //standize length of delays //--------------------------------------------------------------------------------------------

28

Page 29: Gopher Tortoise Scope Redesign

//variables used for recieving and storing serial dataint cmd=110;int prev_cmd=0;//sensor pinint dhtpin = 12;//Initialize DHT sensor for normal 16mhz ArduinoDHT dht(dhtpin, DHTTYPE);

//--------------------------------------------------------------------------------------------

void setup(){ Serial.begin (9600);//define baud rate at 9600 bps for serial comms dht.begin(); //intialize temp and humidity sensor //set motor controller pins as outputs pinMode(pinI1,OUTPUT); pinMode(pinI2,OUTPUT); pinMode(pinI3,OUTPUT); pinMode(pinI4,OUTPUT); pinMode(pinEA,OUTPUT); pinMode(pinEB,OUTPUT); //enable encoder inputs. pinMode(encodPinA1, INPUT);//sensor A1 input; pinMode(encodPinB1, INPUT);//sensor B1 input; pinMode(encodPinA2, INPUT);//sensor A2 input; pinMode(encodPinB2, INPUT);//sensor B2 input; //enable pullup resistor: digitalWrite(encodPinA1, HIGH); digitalWrite(encodPinB1, HIGH); digitalWrite(encodPinA2, HIGH); digitalWrite(encodPinB2, HIGH);//--------------------------------------------------------------------------------------------//two interrupters work together, each one is responsible for an encoder attachInterrupt(digitalPinToInterrupt(3), rencoder1, FALLING); //system interrupter2 attachInterrupt(digitalPinToInterrupt(2), rencoder2, FALLING); //system interrupter3 //print start-up message //Serial.println("Arduino Ready!");}//end setup

//--------------------------------------------------------------------------------------------//This is the main loopvoid loop(){ //Read and store input command if (Serial.available()>0) {//if data is being received prev_cmd=cmd; //store previous command in an int cmd= Serial.read();//read in new byte and stores it as an int prev_cmd_time = millis(); //store time command was received }

//if time since last command is less than 3 seconds if ((millis() - prev_cmd_time) < dog_time){

29

Page 30: Gopher Tortoise Scope Redesign

prev_time = curr_time; //previous time is equal to the time at the start of previous loop curr_time = millis(); //current time is equal to the time at the start of current loop delta_time = curr_time - prev_time; //delta time is the time difference of two connecting loops getSpeed(); //Obtain the speed of each motor shaft switch (cmd){ //cmd 96 to 99 are trivial, because we do not have servo_control and temp sensor yet case 96: temp(); break; case 100: breaks(); break; case 114: PWM_speed[0] = int((act_speed[0] + control_effort1(half_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(half_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 slow_CW(PWM_speed[0], PWM_speed[1]); break; case 101: PWM_speed[0] = int((act_speed[0] + control_effort1(full_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(half_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 forward_right(PWM_speed[0], PWM_speed[1]); break; case 111: PWM_speed[0] = int((act_speed[0] + control_effort1(half_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(half_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 slow_forward(PWM_speed[0], PWM_speed[1]); break; case 110: PWM_speed[0] = int((act_speed[0] + control_effort1(half_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(full_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 forward_left(PWM_speed[0], PWM_speed[1]); break; case 105: PWM_speed[0] = int((act_speed[0] + control_effort1(half_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(half_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 slow_CCW(PWM_speed[0], PWM_speed[1]); break; case 112:

30

Page 31: Gopher Tortoise Scope Redesign

PWM_speed[0] = int((act_speed[0] + control_effort1(half_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(full_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 backward_left(PWM_speed[0], PWM_speed[1]); break; case 113: PWM_speed[0] = int((act_speed[0] + control_effort1(half_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(half_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 slow_forward(PWM_speed[0], PWM_speed[1]); break; case 103: PWM_speed[0] = int((act_speed[0] + control_effort1(full_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(half_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 backward_right(PWM_speed[0], PWM_speed[1]); break; case 115: PWM_speed[0] = int((act_speed[0] + control_effort1(full_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(full_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 fast_CW(PWM_speed[0], PWM_speed[1]); break; case 102: PWM_speed[0] = int((act_speed[0] + control_effort1(full_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(full_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 fast_forward(PWM_speed[0], PWM_speed[1]); break; case 106: PWM_speed[0] = int((act_speed[0] + control_effort1(full_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(full_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 fast_CCW(PWM_speed[0], PWM_speed[1]); break; case 104: PWM_speed[0] = int((act_speed[0] + control_effort1(full_speed, act_speed[0])) / full_speed * 255); PWM_speed[1] = int((act_speed[1] + control_effort2(full_speed, act_speed[1])) / full_speed * 255);//converts a float speed to a PWM value of 0~255 fast_backward(PWM_speed[0], PWM_speed[1]); break; default: breaks(); }//end swich statement

31

Page 32: Gopher Tortoise Scope Redesign

}//end if statement else{ //if no command has been received in the last 3 seconds breaks(); //the rover will apply the breaks } }//end of main loop//--------------------------------------------------------------------------------------------// The interrupt routine - runs each time a falling edge of a pulse is detectedvoid rencoder1() { // pulse and direction, direct port reading to save cycles if (digitalRead(encodPinB1)==HIGH){ (count[0])++;} // if(digitalRead(encodPinA1)==HIGH) count ++; else{ (count[0])--;} // if (digitalRead(encodPinA1)==LOW) count --;}//--------------------------------------------------------------------------------------------// The interrupt routine - runs each time a falling edge of a pulse is detectedvoid rencoder2() { // pulse and direction, direct port reading to save cycles if (digitalRead(encodPinB2)==HIGH){ (count[1])++;} // if(digitalRead(encodPinA2)==HIGH) count ++; else{ (count[1])--;} // if (digitalRead(encodPinA2)==LOW) count --;}//-----------------------------------------------------------------------------//this function is actually a PD controller, it outputs control effort as a float typefloat control_effort1(const int targetSpeed, int currentSpeed) { float ctrl_effort1 = 0; // PID correctionint error1=0; error1 = abs(targetSpeed) - abs(currentSpeed); ctrl_effort1 = (Kp * error1) + (Kd * (error1 - last_error1)); last_error1 = error1; return ctrl_effort1; } //-----------------------------------------------------------------------------//this function is actually a PD controller, it outputs control effort as a float typefloat control_effort2(const int targetSpeed, int currentSpeed) { float ctrl_effort2 = 0; // PID correctionint error2=0; error2 = abs(targetSpeed) - abs(currentSpeed); ctrl_effort2 = (Kp * error2) + (Kd * (error2 - last_error2)); last_error2 = error2; return ctrl_effort2; } //------------------------------------------------------------------//this function calculates the void getSpeed() { // calculate speed

32

Page 33: Gopher Tortoise Scope Redesign

// last counts for (int i = 0; i < 2; i++){ act_speed[i] = (count[i] - prev_count[i]) / CPR * 2 * pi / delta_time; // delt counts / CPR * 2pi / delta time = rad/s if(act_speed[i] > full_speed){ //speed saturation act_speed[i] = full_speed; } //act_PWM[i] = constrain(act_spped[i], 0, 255); //converts actual speed to prev_count[i] = count[i]; } } //--------------------------------------------------------------------------------------------//This function reads in temperature and humidity data from a DHT22 sensor. It then prints//the humidity, temperature in celcius and temperature in ferenheight.

void temp (){ // Reading temperature or humidity takes about 250 milliseconds! // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) float h = dht.readHumidity(); // Read temperature as Celsius float t = dht.readTemperature(); // Read temperature as Fahrenheit float f = dht.readTemperature(true); // Check if any reads failed and exit early (to try again). if (isnan(h) || isnan(t) || isnan(f)) { Serial.println("Failed to read from DHT sensor!"); return; } //print humidity Serial.print(h); Serial.print("%,"); //print temperature Serial.print(t); Serial.print("C,"); Serial.print(f); Serial.println("F"); cmd=prev_cmd;//reset input command to previous command so motor control isn't interupted }//end of function "temp"//--------------------------------------------------------------------------------------------//This function applies the breaksvoid breaks (){ analogWrite(pinEA,0);//set motor A speed to zero analogWrite(pinEB,0);//set motor B speed to zero //set motor A digitalWrite(pinI1,HIGH);// DC motor stop rotating digitalWrite(pinI2,HIGH); //set motor B

33

Page 34: Gopher Tortoise Scope Redesign

digitalWrite(pinI3,HIGH);// DC motor stop rotating digitalWrite(pinI4,HIGH);}//end of function "breaks"//--------------------------------------------------------------------------------------------//This function moves the rover slowly to the rightvoid slow_CW(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, LOW); //CW rotation digitalWrite(pinI2, HIGH); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, HIGH); //CCW rotation digitalWrite(pinI4, LOW); analogWrite(pinEB, Bspeed);}//end of function "slow_right"//--------------------------------------------------------------------------------------------//This function moves the rover slowly to the forward, rightvoid forward_right(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, LOW); //CW rotation digitalWrite(pinI2, HIGH); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, LOW); //CW rotation digitalWrite(pinI4, HIGH); analogWrite(pinEB, Bspeed);}//end of function "slow_forward_right"//--------------------------------------------------------------------------------------------//This function moves the rover slowly forwardvoid slow_forward(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, LOW); //CW rotation digitalWrite(pinI2, HIGH); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, LOW); //CW rotation digitalWrite(pinI4, HIGH); analogWrite(pinEB, Bspeed);}//end of function "slow_forward"//--------------------------------------------------------------------------------------------//This function moves the rover slowly to the forward, leftvoid forward_left(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, LOW); //CW rotation digitalWrite(pinI2, HIGH); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, LOW); //CW rotation digitalWrite(pinI4, HIGH); analogWrite(pinEB, Bspeed);}//end of function "slow_forward_left"//--------------------------------------------------------------------------------------------//This function moves the rover slowly to the left

34

Page 35: Gopher Tortoise Scope Redesign

void slow_CCW(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, HIGH); //CCW rotation digitalWrite(pinI2, LOW); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, LOW); //CW rotation digitalWrite(pinI4, HIGH); analogWrite(pinEB, Bspeed);}//end of function "slow_left"//--------------------------------------------------------------------------------------------//This function moves the rover slowly to the backward, leftvoid backward_left(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, HIGH); //CCW rotation digitalWrite(pinI2, LOW); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, HIGH); //CCW rotation digitalWrite(pinI4, LOW); analogWrite(pinEB, Bspeed);}//end of function "slow_backward_left"//--------------------------------------------------------------------------------------------//This function moves the rover slowly backwardvoid slow_backward(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, HIGH); //CCW rotation digitalWrite(pinI2, LOW); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, HIGH); //CCW rotation digitalWrite(pinI4, LOW); analogWrite(pinEB, Bspeed);}//end of function "slow_backward"//--------------------------------------------------------------------------------------------//This function moves the rover slowly to the backward, rightvoid backward_right(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, HIGH); //CCW rotation digitalWrite(pinI2, LOW); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, HIGH); //CCW rotation digitalWrite(pinI4, LOW); analogWrite(pinEB, Bspeed);}//end of function "slow_backward_right"//--------------------------------------------------------------------------------------------//This function moves the rover quickly to the rightvoid fast_CW(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, LOW); //CW rotation digitalWrite(pinI2, HIGH); analogWrite(pinEA, Aspeed); //set motor B

35

Page 36: Gopher Tortoise Scope Redesign

digitalWrite(pinI3, HIGH); //CCW rotation digitalWrite(pinI4, LOW); analogWrite(pinEB, Bspeed);}//end of function "fast_right"//--------------------------------------------------------------------------------------------//This function moves the rover quickly forwardvoid fast_forward(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, LOW); //CW rotation digitalWrite(pinI2, HIGH); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, LOW); //CW rotation digitalWrite(pinI4, HIGH); analogWrite(pinEB, Bspeed);}//end of function "fast_forward"//--------------------------------------------------------------------------------------------//This function moves the rover quickly to the leftvoid fast_CCW(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, HIGH); //CCW rotation digitalWrite(pinI2, LOW); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, LOW); //CW rotation digitalWrite(pinI4, HIGH); analogWrite(pinEB, Bspeed);}//end of function "fast_left"//--------------------------------------------------------------------------------------------//This function moves the rover quickly backwardvoid fast_backward(int Aspeed, int Bspeed){ //set motor A digitalWrite(pinI1, HIGH); //CCW rotation digitalWrite(pinI2, LOW); analogWrite(pinEA, Aspeed); //set motor B digitalWrite(pinI3, HIGH); //CCW rotation digitalWrite(pinI4, LOW); analogWrite(pinEB, Bspeed);}//end of function "fast_backward"//--------------------------------------------------------------------------------------------

2. Raspberry Pi Code

//--------------------------------------------------------------------------------------- This program is designed to read inputs form a gamepad and send commands to

the rover. While it has the ability to read all gamepad commands, currently

only the left joystick, directional pad, and a few buttons are used.

36

Page 37: Gopher Tortoise Scope Redesign

This program was designed to be run on a Raspberry Pi running the Raspbian OS

and read commands off of a Logitech Gamepad F310.*///--------------------------------------------------------------------------------------------//Include neccesary libraries

#include <SDL2/SDL.h> //window creation and gamepad input reading features#include <SDL2/SDL_image.h> //image loading and rendering features#include <stdio.h> //print text to console#include <string> //to hadle strings#include <cmath> //basic math function like inverse tangent#include <iostream> //print to console

#include <stdlib.h> //sending system commands in Linux

#include "wiringPi.h" //send commands over USB on raspberry pi#include "wiringSerial.h"//--------------------------------------------------------------------------------------------//Function Declarations

bool init(); //Initialization routine run on start upvoid close(); //Close routine run on shut downchar eventHandler(SDL_Event input, char cmd, bool &quit); //handles events, ya' dummychar motorControl(char cmd); //convert joystick coordinates into motor commandsvoid sendcmd(char cmd); //send commands over usb or prints commands to console//--------------------------------------------------------------------------------------------//Global variables

SDL_GameController* GameController = NULL; //Game Controller handler//SDL_GameController* GameController1 = NULL; //Game Controller hand$

//These global strings can be helpful when dubugging, but are kept commented out for production.//std::string command = "";//std::string prev_command = "";

//These variables are needed to set up serial communication over USB//Look up wireing pi library for more detialschar device [] = "/dev/ttyACM0"; //Name or Arduino's usb portchar device1 [] = "/dev/ttyACM1";int fd;unsigned long baud = 9600;

//--------------------------------------------------------------------------------------------//This function runs once at start up. It initializes the gamepad and serial communications

37

Page 38: Gopher Tortoise Scope Redesign

//with the Arduino. It returns success = true if everything initialzes correctly. It prints//error messages and returns success = false if something fails to initialize. Success = false//will cause the program to quit in main loop.bool init(){

//Initialization flagbool success = true;

//Initialize SDLif( SDL_Init( SDL_INIT_GAMECONTROLLER | SDL_INIT_TIMER ) < 0 ){

printf( "SDL could not initialize! SDL Error: %s\n", SDL_GetError() );

success = false;}else //if SDL initialized succesfully{// SDL_JoystickEventState(SDL_ENABLE);

//Load gamepadGameController = SDL_GameControllerOpen( 0 );//GameController1 = SDL_GameControllerOpen( 1 );if(( GameController == NULL)/* || (GameController1 == NULL )*/ ){

printf( "Warning: Unable to open game controller! SDL Error: %s\n", SDL_GetError() );

success = false;}

}

std::cout<<"Initialized!\n"; //print initialization message to console

fflush(stdout); //clear serial data lines (just in case!)

//open serial device (Arduino)if ((fd = serialOpen (device, baud)) < 0){ if((fd = serialOpen (device1, baud)) < 0)

{printf ("Unable to open serail device\n");success = false;

}}//setup serial commsif (wiringPiSetup () == -1){

printf ("Unable to start wiringPi\n");success = false;

} //Determine number of available joysticks //printf("%i joysticks were found.\n\n", SDL_NumJoysticks() );

//printf("Names: %s \n",SDL_JoystickName(0) , SDL_JoystickName(1));

return success;}//End function "Init"//--------------------------------------------------------------------------------------------

38

Page 39: Gopher Tortoise Scope Redesign

//This function runs once at shut down. It deallocates memory and shuts down the program// properly.void close(){

//Close game controllerSDL_GameControllerClose( GameController );GameController = NULL;

//close serial commsserialClose(fd);

//Quit SDL subsystemsSDL_Quit();

}//End function "close"//--------------------------------------------------------------------------------------------//This funciton determines the event type and then sends the proper command over usb to the//Arduino Micro onboard the rover.//For more info, look up the SDL_Event's "caxis" and "cbutton".

/* Note: It is helpful to uncomment the "command = ..." lines when debugging. These commands can then be printed in the sendcmd function to verify code.

"cmd = ..." lines should not be uncommented unless the Arduino code is updated to include these added commands in it decision logic.*/

char eventHandler(SDL_Event input, char cmd, bool &quit){ //If user requests quit

if( input.type == SDL_QUIT ){

quit = true;}//If input is of Controller axis motion type//This includes the two joysticks and the two triggerselse if( input.type == SDL_CONTROLLERAXISMOTION ){

if (input.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT){

//command = "Left Trigger";cmd = 83;

}else if (input.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT){

//command = "Right Trigger";cmd = 84;

}else{

39

Page 40: Gopher Tortoise Scope Redesign

cmd = motorControl(cmd); //this function will deal with joystick motion and return cmd value

}}//If a controller button has been pushed downelse if( input.type == SDL_CONTROLLERBUTTONDOWN ){

switch(input.cbutton.button){

case SDL_CONTROLLER_BUTTON_A://play live video-feed on UI screen using mplayer//command = "Button A";cmd = 93;system("mplayer tv: -tv

driver=v4l2:norm=PAL-M:device=/dev/video0:fps=1:noaudio:outfmt=uyvy:fps=10 -vo sdl -fs -vf format=y8,scale -hardframedrop &");

system("/home/pi/mediaplayer/run.sh");break;

case SDL_CONTROLLER_BUTTON_B://close video-feed//command = "Button B";cmd = 94;system("pkill mplayer");break;

case SDL_CONTROLLER_BUTTON_X://command = "Button X";cmd = 95;system("mplayer tv: -tv

driver=v4l2:norm=PAL-M:device=/dev/video0:fps=1:noaudio:outfmt=uyvy:fps=10 -vo jpeg -frames 3 -fs -vf format=y8,scale -hardframedrop &");

break;case SDL_CONTROLLER_BUTTON_Y:

//request temp and humidity data from Arduino//command = "Button Y";cmd = 96;break;

case SDL_CONTROLLER_BUTTON_BACK://shutdown raspberry pi//command = "Back";cmd = 88;system("sudo shutdown -h now");break;

case SDL_CONTROLLER_BUTTON_GUIDE://quit program//command = "Guide";quit = true;system("sudo shutdown -h now");break;

case SDL_CONTROLLER_BUTTON_START://command = "Start";cmd = 89;break;

case SDL_CONTROLLER_BUTTON_LEFTSTICK://command = "Left Stick";cmd = 90;break;

case SDL_CONTROLLER_BUTTON_RIGHTSTICK://command = "Right Stick";

40

Page 41: Gopher Tortoise Scope Redesign

cmd = 91;break;

case SDL_CONTROLLER_BUTTON_LEFTSHOULDER://command = "Left Shoulder";cmd = 85;break;

case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER://command = "Right Shoulder";//cmd = 86;break;

case SDL_CONTROLLER_BUTTON_DPAD_UP://center camera//command = "Dpad Up";cmd = 99;break;

case SDL_CONTROLLER_BUTTON_DPAD_DOWN://command = "Dpad Down";cmd = 87;break;

case SDL_CONTROLLER_BUTTON_DPAD_LEFT://pan camera left//command = "Dpad Left";cmd = 98;break;

case SDL_CONTROLLER_BUTTON_DPAD_RIGHT://pan camera right//command = "Dpad Right";cmd = 97;break;

}}

printf ("CMD: %d\n",cmd);return (cmd);

}//End of function "eventHandler"//--------------------------------------------------------------------------------------------//This function converts joystick coordinates into motor commands and sends them over usb.char motorControl(char cmd){

SDL_JoystickEventState(SDL_ENABLE);

const double min = 2500; //deadzoneconst double mid = 20700;//line between fast a slow speed

//read in x and y coordinates. Flip y coordinate to make more sense//Left Stickdouble yCorL = -1*SDL_GameControllerGetAxis(GameController,

SDL_CONTROLLER_AXIS_LEFTY);//double xCorL = SDL_GameControllerGetAxis(GameController,

SDL_CONTROLLER_AXIS_LEFTX);//Right stickdouble yCorR = -1*SDL_GameControllerGetAxis(GameController,

SDL_CONTROLLER_AXIS_RIGHTY);//double xCorR = SDL_GameControllerGetAxis(GameController,

SDL_CONTROLLER_AXIS_RIGHTX);

41

Page 42: Gopher Tortoise Scope Redesign

//Variable for joystick position, up or down//Left Stickdouble joystickPosL = 0;//Right stickdouble joystickPosR = 0;

//determine joystick up or down//this logic converts joystick position to be 1 for up -1 for down//Left stick//Up Positionif (yCorL > min ){

joystickPosL = 1;}//Down Positionelse if (yCorL < -min ){

joystickPosL = -1;}else{

joystickPosL=0;}//Right stick//Up Positionif (yCorR > min ){

joystickPosR = 1;}//Down Positionelse if (yCorR < -min ){

joystickPosR = -1;}else {

joystickPosR = 0;}

//calculate joystick magnitudedouble joystickMagL = sqrt(/* (xCorL * xCorL) + (*/yCorL * yCorL)/*)*/;

double joystickMagR = sqrt(/* (xCorR * xCorR) + (*/yCorR * yCorR)/*)*/;

//For debuggingprintf ("PosL: %f\n", joystickPosL);printf ("MagL: %f\n", joystickMagL);printf ("PosR: %f\n", joystickPosR);printf ("MagR: %f\n", joystickMagR);

//Finally, joystick angle and magnitude is used to determine the direction//and speed the rover should move in.if ( (joystickPosL || joystickPosR) == 0 ){

42

Page 43: Gopher Tortoise Scope Redesign

//command = "Break";cmd = 100;

}//Fwd commandselse if ( (joystickPosL > 0) && (joystickPosR > 0)){

if (( joystickMagL < mid )&& ( joystickMagR < mid )){

//command = "Slow Fwd";cmd = 111;

} else if (( joystickMagL < mid )&& ( joystickMagR > mid ))

{//command = "Left Fwd";cmd = 110;

} else if (( joystickMagL > mid )&& ( joystickMagR < mid ))

{//command = "Right Fwd";cmd = 101;

}

else{

//command = "Fast Fwd";cmd = 102;

}}//Bwd commandselse if ( (joystickPosL < 0) && (joystickPosR < 0)){

if (( joystickMagL < mid )&& ( joystickMagR < mid )){

//command = "Slow Bwd";cmd = 113;

} else if (( joystickMagL < mid )&& ( joystickMagR > mid ))

{//command = "Left Bwd";cmd = 112;

} else if (( joystickMagL > mid )&& ( joystickMagR < mid ))

{//command = "Right Bwd";cmd = 103;

}else{

//command = "Fast Bwd";cmd = 104;

}}else if ( (joystickPosL < 0) && (joystickPosR > 0)){

if (( joystickMagL > mid )&& ( joystickMagR > mid )){

//command = "Fast Counter Clockwise Rotation";cmd = 106;

43

Page 44: Gopher Tortoise Scope Redesign

}else{

//command = "Slow Counter Clockwise Rotation ";cmd = 105;

}}else if ( (joystickPosL > 0) && (joystickPosR < 0)){

if (( joystickMagL > mid )&& ( joystickMagR > mid )){

//command = "Fast Clockwise Rotation";cmd = 115;

}else{

//command = "Slow Clockwise Rotation ";cmd = 114;

}}return cmd;

}//End of funciton "motorControl"//--------------------------------------------------------------------------------------------//This function sends characters over usb using the wireing pi libraries. It also reads in//temp and humidty data.void sendcmd(char cmd){

if (cmd == 96) //request temp and humidty data from rover{

char humidity [10];char celsius [10];char fahrenheit [10];char receivedChar = 0;int i = 0;int j = 0;int k = 0;

serialFlush(fd); //clear serail lines

serialPutchar (fd, cmd); //send commandwhile ( serialDataAvail(fd) < 1 ) //delay until arduino sends

data{

SDL_Delay(1);}

receivedChar = serialGetchar(fd); //read in first chracter

do{

humidity[i] = receivedChar; //store character as humidity data

i++;receivedChar = serialGetchar(fd);

44

Page 45: Gopher Tortoise Scope Redesign

} while ( receivedChar != ','); //store characters until , is reached

receivedChar = serialGetchar(fd); //begin reading temperature data

do{

celsius[j] = receivedChar;j++;receivedChar = serialGetchar(fd);

} while ( receivedChar != ',');

receivedChar = serialGetchar(fd);

do{

fahrenheit[k] = receivedChar;k++;receivedChar = serialGetchar(fd);

} while ( receivedChar != ',');

//print data to the consolestd::cout<<"Humidity: ";

for (int lcv = 0; lcv < i; lcv++){

std::cout<<humidity[lcv];}

std::cout<<"\n"<<"Celsius: ";

for (int lcv = 0; lcv < j; lcv++){

std::cout<<celsius[lcv];}

std::cout<<"\n"<<"Fahrenheit: ";

for (int lcv = 0; lcv < k; lcv++){

std::cout<<fahrenheit[lcv];}

std::cout<<"\n";}else //send command to rover and move on, if we are not expecting data in

reply{

serialPutchar (fd, cmd);}

//Useful for debugging//std::cout<<command<<"\n";//printf("%c\n", cmd);

}//End of function "sendcmd"

45

Page 46: Gopher Tortoise Scope Redesign

//--------------------------------------------------------------------------------------------//main control logic loopint main( int argc, char* args[] ){

//Run initialization function and check for successif( !init() ){

printf( "Failed to initialize!\n" );}

else //if initialization is successful{

//displaying camera feed//system("mplayer tv:// -tv driver=v4l2:norm=PAL-M:device=/dev/video0

-vo sdl -framedrop");

bool quit = false; //flag to exit main loopSDL_Event input; //store input commandschar cmd = 0; //commands to be sent to arduinochar prev_cmd = 0; //store old commandsint WatchDog = SDL_GetTicks() + 300; //watchdog timer

//While user hasn't quitwhile( !quit ){

while( SDL_PollEvent( &input ) != 0 ) //poll gamepad, store events in input variable

{cmd = eventHandler( input, cmd, quit); //determine

event type and corresponding cmd to send

if (cmd != 0){

//limit number of commands we send for efficiency and power savings

if ( (cmd != prev_cmd) || (SDL_TICKS_PASSED(SDL_GetTicks(), WatchDog)))

{sendcmd(cmd);WatchDog = SDL_GetTicks() + 300; //reset

watchdog timer//prev_command = command;prev_cmd = cmd;

}}

//command = "";cmd = 0;

}//end while input event present}//end while not quite

}

//For Debugging//SDL_Delay(4000);

//Free resources and close SDL

46

Page 47: Gopher Tortoise Scope Redesign

close();//system("sudo shutdown -h now");return 0;

}//End "main"//--------------------------------------------------------------------------------------------

47