Skip to content

CrzyMan/ADEV-Automation_Navigation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 

Repository files navigation

Hotswap API

It is important to note that some of the code blocks exist in the same scope and are separated by their conceptual function. There are still some blocks which are in separate files and classes. They will be notated explicitly as such.

The diagram in Figure 1 illustrates the relationships between code blocks. Code blocks are portions of the code that exist to perform a specific task. They are represented as solid rectangles. Closely related code blocks are contained within a dashed lined rectangle. Relationships are represented as solid lined arrows. Implicit relationships are represented with dashed lined arrows. The individual blocks, their functions, fields, and implementations will be more thoroughly explained through the rest of this document.

Figure 1: The high level interaction diagram for the code design.

Top Level

The top level code is in the base scope and is what controls the rest of the code blocks. It is in charge of instantiating variables that are used amongst the code blocks. All of the setup for any part of the program happens in the setup function, or while instantiating variables and constants.

Field Summary

Type Name and Description
MovementModule m
The code updates this generic movement module so that it contains the code of whichever specific movement module should be running.
GoHome g
An extension of MovementModule that specifies the behavior of the robot while returning to its home position.
Picking p
An extension of MovementModule that specifies the behavior of the robot while it is picking strawberries.
Idle i
An extension of MovementModule that specifies the behavior of the robot while it is stationary in the field.
Demo d
An extension of MovementModule that specifies the behavior of the robot while its capabilities are being demonstrated.

Method Summary

Type Method and Description
void setup()
The first method to be called when execution begins
void loop()
Called repeatedly from an inaccessible infinite loop.

Method Detail

Functions
public void setup()
Setup is called at the very beginning of execution. So, it should be reserved for instantiating variables and calling other setup operations. For instance, establishing serial communication, attaching each motor, connecting the USB, and pre-populating the LIDAR data with live data to ensure smooth start up.
public void loop()
This function is automatically called by a hidden infinite loop. This loop should be reserved for the functions which must be constantly run. For instance, updating the LIDAR data, picking a movement module, running that movement module, and controlling the motors.

Goal Handler

This code block is in its own namespace. So, in order to reference any field or function, the name must be prepended with "GoalHandler::" such as "GoalHandler::left". It keeps track of the direction that the robot is attempting to go. This can be either, left, right, or straight. When asked to update the goals, it calculates the new goals based on the currently selected direction and the LIDAR data. The objective being that it will achieve the direction without hitting anything.

Field Summary

Type Name and Description
Constant Integer left
The value is -1, and is used to uniquely identify this direction from the other directions: right and straight.
Constant Integer right
The value is 1, and is used to uniquely identify this direction from the other directions: left and straight.
Constant Integer straight
The value is 0, and is used to uniquely identify this direction from the other directions: right and left.
Integer currDir
This variable represents the direction that the robot is currently attempting to go in
ConstantChar _biases_lateral
The value is 0, representing the index in the biases array that contains the lateral bias
ConstantChar _biases_rotational
The value is 1, representing the index in the biases array that contains the rotational bias
ConstantChar _biases_speed
The value is 2, representing the index in the biases array that contains the speed bias
Float Array biases[]
An array of the biases: lateral, rotational and speed
Float latSensitivity
The value is 4, representing the lateral sensitivity for use in the logistic function
Float rotSensitivity
The value is 4, representing the rotational sensitivity for use in the logistic function
Float speedSensitivity
The value is 6, representing the speed sensitivity for use in the logistic function
ConstantChar _fuzzy_sideBack
The value is 0, representing the index in the fuzzyGoals array that contains the the fuzzy logic modifier for the side-back location
ConstantChar _fuzzy_side
The value is 1, representing the index in the fuzzyGoals array that contains the the fuzzy logic modifier for the side location
ConstantChar _fuzzy_sideFront
The value is 2, representing the index in the fuzzyGoals array that contains the the fuzzy logic modifier for the side-front location
ConstantChar _fuzzy_frontSide
The value is 3, representing the index in the fuzzyGoals array that contains the the fuzzy logic modifier for the front-side back location
ConstantChar _fuzzy_front
The value is 4, representing the index in the fuzzyGoals array that contains the the fuzzy logic modifier for the front location
ConstantChar _fuzzy_size
The value is 5, representing the size of the fuzzyGoals array
Integer Array fuzzyGoals[_fuzzy_size]
The array of all of the fuzzy goals
Float Array goals[2]
The array of floats which contain the movement goals for the robot. The values are floats because they represent percentages. The turning goal can be inclusively between -1 and 1. For -1, the robot will turn at maximum turning speed to the left, and for 1 will do the same for the right. For 0, the robot will not turn in either direction. The forward speed can be inclusively between 0 and 1. For 0, the robot is not moving forward but may turn. For 1, the robot is moving forward at the maximum allowed speed.
Constant Character _goals_turningSpeed
The value is 0, representing the index in the goals array that contains the percent of the maximum turning speed the robot should turn.
Constant Character _goals_forwardSpeed
The value is 1, representing the index in the goals array that contains the percent of the maximum forward speed the robot should travel.

Method Summary

Type Method and Description
void updateGoals()
Use the LIDAR data and currDir to produce new goals
void setDirection(int newDir)
Sets currDir to be newDir
float balancedLogistic(float x, float k)
Returns a value according to a balanced logistical function
void updateBiases()
Calculates the lateral bias, the rotational bias, and the speed bias

Method Details

Functions
void updateGoals()
This function decides which direction that the robot should be traveling in. It uses the LIDAR and other environmental data, such as sensors, to determine whether it is appropriate to run this module. It will set a flag if the environment. This function is called by movement modules.
void setDirection(int newDir)
This function sets the direction that the robot is currently headed to be the new direction. This method is called by movement modules.
float balancedLogistic(float x, float k)
Returns a value exclusively between -1 and 1 according to a logistical function. As x approaches ±∞, the function approaches ±1. When x is zero, the output is also zero. How quickly the function approaches a bound is proportional to the sensitivity k.
void updateBiases()
This function calculates the lateral bias, the rotational bias and the speed bias. These are all calculated using the appropriate readings values and fuzzy logic modifiers for each bias location.

Movement Logic

This code block is in the same scope as Top level. The purpose of the movement logic block is to determine which movement module to delegate to. It has the knowledge of which modules should be used when certain flags are set.

Method Summary

Type Method and Description
void pickModule()
Sets which movement module should be running.
void runModule()
Updates goals and executes movement module

Method Details

| Functions | | void updateGoals()
This function uses the currently set flags to decide which movement module would be most appropriate to run. It then sets the generic MovementModule m to be an instance of that module. | | void runModule()
This function updates the goals then executes the MovementModule m code. |

Movement Module

This code block is the generic name for any implementation which determines how the robot should move. The responsibility of a movement module is to determine which direction the robot needs to move. Movement Modules are instantiated in the top level code, and are called by the Movement Logic code. Each movement module may have different implementations, but the code for GoHome and Picking are based on finite state machines. Idle simply sets the goals manually such that the robot will remain stationary

Field Summary

Type Name and Description
Integer Turning::initial
The value is -1, and is used to uniquely identify this direction from the other directions: right and straight.
Integer Turning::next
The value is 1, and is used to uniquely identify this direction from the other directions: left and straight.
Integer Turning::rows_picked
This value tracks the number of turns that have been made.

Method Summary

Type Method and Description
void execute()
Decides which direction to move
void Turning::toggleNext()
Switched which direction is next.

Method Details

Functions
void execute()
This function uses the LIDAR readings and other environmental data, such as sensors, to determine the appropriate direction.
void Turning::toggleNext()
Exists in the turning namespace. Toggles Turning::next between GoalHandler::left and GoalHandler::right. If Turning::next is set to GoalHandler::straight, it will not do anything

Flag Protocol

This code block is in it's own namespace (scope). It is in charge of storing, setting, and clearing all of the flags. In order to reference anything inside of the namespace, it must be prepended with the name of the namespace followed by two colons. For example, to set the flag to start picking, you must type "FlagProtocol::setFlag(FlagProtocol::flag_startPicking);". This is a lot of typing, but it keeps functionalities separated.

Field Summary

Type Name and Description
Integer flags
Every bit of this integer corresponds to a different flag. Each bit is set and read individually as 1 or 0. If a flag's bit is 1, the flag has been set. If a flag's bit is 0, the flag has been cleared.
Enum FlagNames
Contains the names of all of the flags. The default set of flag names are: flagsActive, basketFull, batteryLow, armBusy, goHomeRequest, batteryDead, obstacleWhileTurning.

Method Summary

Type Method and Description
void setFlag(int flag)
Sets the given flag
bool getFlag(int flag)
Returns whether the flag is set
void clearAllFlags()
Clears all of the flags

Method Detail

Functions
void setFlag(int flag)
This function is called when a given flag needs to be set. The function takes an integer parameter which corresponds to the flag that is being set. For instance, FlagProtocol::setFlag(FlagProtocol::flag_basketFull) will set the "basket full" flag. The function also automatically sets the flag "flags active". So it is easy to tell when any flag has been set.
Boolean getFlag(int flag)
This function returns whether a flag has been set or not. It reads the flag's bit from the flags variable, and returns true if the bit is 1 and returns false if the bit is 0.
void clearAllFlags()
This function sets all flags to be cleared. This is done by setting the flags variable to 0. This should be done by the movement logic before calling the movement module

Motor Controller

This code block is in the top level namespace. It is in charge of setting up the motors as well as deciding which commands to send to them.

Field Summary

Type Name and Description
Float Array goals[]
A two element array which contains the forward speed and turning goals for robot movement.
Servo leftMotor
A servo object that simplifies the communication to the left motor.
Servo rightMotor
A servo object that simplifies the communication to the right motor.
Integer lastLeftCommand
Variable to track most recent command sent to the left motor.
Integer lastRightCommand
Variable to track most recent command sent to the right motor.
Constant Integer MOTOR_STOP
The value is 90. If sent as a command to the motors, the motors will stop.
Constant Float SPEED_MULTI
The value is 0.35. This slows the robot down to 35% of max speed.
Constant Float MAX_FORWARD_SPEED
The value is 0.5. This represents 0.5 m/s.
Constant Float MAX_ROTATIONAL_SPEED
The value is 10. This sets the maximum rate of turning of the robot to 10 rotations/second. This rotational speed will not be achieved, but forces the robot to turn with enough torque such that it is able to turn on high friction terrain.
Constant Float HALF_TANK_WIDTH
The value is 0.5, for half of the 1 meter tank width. The tank is not 1 meter wide, but treating it as such forces the robot to turn with enough torque such that it is able to turn on high friction terrain.

Method Summary

Type Method and Description
void controlMotors()
Calculates commands to send to motors based on goal, and then
void sendMotorCommands(int leftCommand, int rightCommand)
Sends commands to the motors.
void motorSetup()
Sets up the motors and makes certain they are stopped.

Method Detail

Functions
void controlMotors()
This function takes the goals, translates them to tread movements, and then converts the tread movements into commands to be sent to the motors.
void sendMotorCommands(int leftCommand, int rightCommand)
This function takes the commands passed in and writes them to the corresponding motors. A command will only be written if it is different than the most recent command written to that motor.
void motorSetup()
This function attaches the left and right servo motors to their respective pins on the Arduino board and sends the motors a stop command.

Environment Data Updater

This code block is in the scope of the Top Level Code. It is in charge of pulling in data from the LIDAR, parsing it, assigning the appropriate distance values to the data and readings arrays.

Field Summary

Type Name and Description
Integer Array data[]
A 360 element array which contains the LIDAR data for each angle.IMPORTANT: The data in this array in never wiped. It is constantly being overwritten. If an angle is skipped for any reason, it will retain its most recently assigned value. This causes objects to "fade in and out of existence," according to the robot.
Integer Array readings[]
An array of size _reading_size, which contains the reading for every "feeler."
Constant Character _readings_leftSideBack
Value is 0, is the index in the readings array for the left side back reading.
Constant Character _readings_leftSide
Value is 1, is the index in the readings array for the left side reading.
Constant Character _readings_leftSideFront
Value is 2, is the index in the readings array for the left side front reading.
Constant Character _readings_frontLeft
Value is 3, is the index in the readings array for the front left reading.
Constant Character _readings_front
Value is 4, is the index in the readings array for the front reading.
Constant Character _readings_frontRight
Value is 5, is the index in the readings array for the front right reading.
Constant Character _readings_rightSideFront
Value is 6, is the index in the readings array for the right side front reading.
Constant Character _readings_rightSide
Value is 7, is the index in the readings array for the right side reading.
Constant Character _readings_rightSideBack
Value is 8, is the index in the readings array for the right side back reading.
Constant Character _readings_size
Value is 9, is the number of elements in the readings[] array.
Constant Integer Array angleArray[_readings_size]
Contains the angles for each of the readings.
Constant Integer _readings_max
Value is 3000, the max range of the LIDAR system, and the value when the LIDAR system can't get a reading.
Constant Character _readings_spread
Values around the 'feeler' locations to average. Higher the value, less 'feelers'.
Constant Integer packet_maxSize
Value is 12, this is the number of characters in a packet string.
Character Array packet[packet_maxSize]
The character array that contains the packet of data from the LIDAR system. It takes the form, "A,XXX,XXXX,Z", where each "X" is a single digit. The first group of digits is the angle of the distance data. The second group of digits is the distance in millimeters at the angle. "A" and "Z" serve as limiting character to make forming the packet easier.
Character packet_writeIndex
Used to determine where in the packet to continue writing information. uint8_t is roughly equivalent to a char.
USB Usb
The usb object used for communicating with the LIDAR system.
Constant Integer Array mock_middleLeft
This data was collected at each angle of the readings when the sensor was in the middle of the hallway, pointed to the left.
Constant Integer Array mock_middleStraight
This data was collected at each angle of the readings when the sensor was in the middle of the hallway, parallel to the walls.
Constant Integer Array mock_middleRight
This data was collected at each angle of the readings when the sensor was in the middle of the hallway, pointed to the right.
Constant Integer Array mock_leftLeft
This data was collected at each angle of the readings when the sensor was on the left side of the hallway, pointed to the left.
Constant Integer Array mock_leftStraight
This data was collected at each angle of the readings when the sensor was on the left side of the hallway, parallel to the walls.
Constant Integer Array mock_leftRight
This data was collected at each angle of the readings when the sensor was on the left side of the hallway, pointed to the right.
Constant Integer Array mock_rightLeft
This data was collected at each angle of the readings when the sensor was on the right side of the hallway, pointed to the left.
Constant Integer Array mock_rightStraight
This data was collected at each angle of the readings when the sensor was on the right side of the hallway, parallel to the walls.
Constant Integer Array mock_rightRight
This data was collected at each angle of the readings when the sensor was on the right side of the hallway, pointed to the right.
Constant Integer Array mock_blind
This data simulates the LIDAR being completely "blind" to any objects that might be within its range.
Constant Integer Array mock_blindToTheRight
This data simulates the LIDAR being completely "blind" to any objects which are to the right of it.
Constant Integer inRowThreshold
The value is 2000. This represents the number of millimeters from the sensor that, when the robot senses objects within that amount, it will consider itself to be in a row.

Method Summary

Type Method and Description
void getData()
Gets the raw data from the USB connection.
void loadPacketToData()
Loads the packet's angle and distance into the data.
void dataToReadings()
Turns the raw data into readings.
void loadMockData(int mock[])
Loads mock data into the distance data structure.
bool robotInRow()
Returns whether the robot thinks it is in a row or not.

Method Detail

Functions
void getData()
This function is called when data from the LIDAR system (via USB) is needed. The primary use of this function is to have an updated representation of the robot's surroundings. The raw LIDAR data is pulled from the USB shield and parsed into a valid packet. These packets are transmitted in disjoint chunks, so getData() is not guaranteed to form a full packet every time. The function will append new data onto previously started packets until a full packet is formed, or it will start a new packet if the previous one was malformed. It will only parse a packet once it is full. This function serves as the main function of LIDAR Updater and is the only function to call loadPacketToData().
void loadPacketToData()
This function is called by getData() when a packet is properly formed. It extracts the angle and distance information from the packet, and then assigns that distance to the corresponding angle index in data[].
void dataToReadings()
This function uses the 360 values contained within data[] to simplify the representation of the robot's surroundings into "feelers". Each feeler has an assigned angle which is inside of angleArray[]. In order, they are 130, 90, 35, 12, 0, 348, 325, 270, and 230 degrees. For each feeler, the distances of the angles within _readings_spread degrees of the feeler are averaged and stored in readings[] for that feeler. If a distance value is zero, that means that the LIDAR could not sense anything at that angle. If there is something at that angle, it is beyond the range of the LIDAR. So, the distance is treated as though it is equal to _readings_max as this is a value just outside the sensing range.
void loadMockData(int mock[])
The purpose of this function is to fill data[] with mock data. mock[] contains distance data for each feeler. The function will read the distance data out of mock[] and place it into data[] for the corresponding angles of each feeler.
bool robotInRow()
The purpose of this function is to return whether or not evidence suggests that the robot is in a row. The robot looks at the left and right side front readings, and if they are both less than inRowThreshold, then the robot is in a row and the function will return true. Otherwise, it is not in a row, and the function will return false.

About

The Arduino code that controls the robot

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages