Skip to content

Lowcar Devices

DanielMolina24 edited this page Aug 22, 2020 · 18 revisions

Lowcar Devices

Devices that work are supported by the lowcar protocol. This section contains an assortment of physical devices and "virtual" devices, along with their parameters and a description of each device

Physical Devices

These devices are part of the students toolkit. I would recommend playing around with them when you get the chance. Not only is good to "visualize" the parameters, it's also really fun :)

Dummy Device

Name type Readable Writeable
RUNTIME INT 1 0
SHEPHERD FLOAT 1 0
DAWN BOOL 1 0
DEVOPS INT 1 0
ATLAS FLOAT 1 0
INFRA BOOL 1 0
SENS INT 0 1
PDB FLOAT 0 1
MECH BOOL 0 1
CPR INT 0 1
EDU FLOAT 0 1
EXEC BOOL 0 1
PIEF INT 1 1
FUNTIME FLOAT 1 1
SHEEP BOOL 1 1
DUSK INT 1 1

This thicc boi is as the name implies, a dummy device with no advanced functionality. This only really used for testing purposes on a bare physical Arduino micro. It allows us to experiment and test all the possible parameters and their functionalities. It allows us to simulate how a lowcar device may interact with dev_handler and the lowcar protocol. It has a decent amount of read-only, write-only, and readable/writeable params based on the different runtime teams and a couple of easter eggs ;)

LIMIT SWITCH

Name type Readable Writeable
switch0 BOOL 1 0
switch1 BOOL 1 0
switch2 BOOL 1 0

A limit switch is a device wired to three switches. These switches, SWITCH1, SWITCH2, and SWITCH3, each have a metal actuator attached to them. The original use of a limit switch is as the name implies, to limit an object from going past a certain endpoint. Unlike the original use, however, we allow students to dictate what action the robot should perform if the actuator was pressed against. Students also have free range to put the three switches wherever they please.

Each switch has a boolean, read-only value that changes depending on whether the actuator was pressed against. This value can be read from the pin that the corresponding limit switch is attached too.

LINE FOLLOWER

Name type Readable Writeable
left FLOAT 1 0
center FLOAT 1 0
right FLOAT 1 0

A line follower is an active sensor that shines an infrared light down and reads the reflection of said infrared light. There are three sensors attached to the bottom of the limit switch to read the reflected light. Using the reflected light, the line follower can send how much light was reflected in three main areas relative to the infrared light: the left to it, the center, or middle, of it, and the right of it. The reflected light values are represented as floats with a range between 0 and 1, where 0 represents no light reflected and 1 represents all the infrared light being reflected. The device then takes that value from the sensor, and subtracts it from 1 to get the total amount of light reflected.

Each sensor returns a value and by getting the value from the pin associated with the sensor, the students can make calculated moves based on what the line follower is reading.

Battery Buzzer

Name type Readable Writeable
is_unsafe BOOL 1 0
calibrated BOOL 1 0
v_cell1 FLOAT 1 0
v_cell2 FLOAT 1 0
v_cell3 FLOAT 1 0
v_batt FLOAT 1 0
dv_cell2 FLOAT 1 0
dv_cell3 FLOAT 1 0

Have you ever thought about how your robot’s battery is doing? Well guess what, us too! With the battery buzzer, students are able to plug their battery into this device and get readings on how their device is doing and whether its safe to continue usage. Battery buzzer is on the larger side of device parameters, coming in at 8 parameters.

The first param is is_unsafe. This param is mostly determined by handle_safety() which in turn, calls compute_safety(). Compute_safety() checks for 4 cases of unsafe conditions in the battery based on the most recent battery readings. These include:

  1. Being below the minimum required voltage values
  2. Being above the maximum voltage value
  3. Imbalanced cell voltages
  4. The battery is occasionally, but still often, dipping under the minimum threshold and then coming back up to the “safe” threshold.

If the battery falls under one of these cases, a flag is set depending on which case along with an unsafe tag. So as an example, if we are below minimum values, a “under_volt” flag and “is_unsafe” variable are set to true. After running these checks, we then buzz the battery if the “is_unsafe” variable was true.

The other Boolean variable in battery buzzer is “calibrated.” This checks to see if the buzzer is calibrated in relation to the battery. Without proper calibration, the voltage readings from the battery buzzer pins may be inaccurate. It does this by checking a calibration array that gets initialized to default values from pdb_defs.h. Upon checking, if these values match the default values, then it is safe to assume it hasn’t been calibrated yet and set the bool value to false.

The calibration array is modified in handle_calibration(), which is ran pretty often in a loop and checks to see if a student hit the calibration function. If hit, we check to see if the calibration array is default values, and if so, calculate the vref of each pin and overwrite them in the calibration array. If the calibration array is set to anything other than default values, then we clear it and re calculate the vref values in the calibration array.

The next three parameters in a battery buzzer are the v_cells, v_cell1, v_cell2, and v_cell3. These are used to calculate whether the battery is safe for use or should be replaced. The values are calculated at least twice a second. In measure_cells(), we read from the resistor values from each cell corresponding to their analog.We then use these values to calculate the voltage of each cell. The dv_cell2 and dv_cell3 parameters are also updated in the same calculation, since its based on the voltage of the cells.

Lastly, we have the v_batt parameter which is essentially just the v_cell3 parameter and represents how much voltage is in the battery as a whole.

Servo Controller

Name type Readable Writeable
servo0 FLOAT 1 1
servo1 FLOAT 1 1

A servo controller is a device that controls the movement of two servo motors it is attached too. Servos are small mechanical devices that allow students to make precise movements without the size and weight of a regular motor. The tradeoff here is that it has significantly less power than a motor and has a smaller range of motion.

Both servos, servo1 and servo2, serve as parameters to the servo controller and are readable and writeable parameters. Upon initialization, the servo controller resets the servos to a default starting position and sets the values in the position array to 0. The servo also isn’t technically connected to a pin on the servo controller until the first write to that servo. If already attached or after being attached, the servo controller then calculates how much to move the servo by depending on its starting position and the input that was fed to the servo controller. Each servo has a range of motion of 180 degrees. We can also read each servo’s current positions by grabbing it from the positions array. Each servo’s position is stored as a float.

Polar Bear

Name type Readable Writeable
duty_cycle FLOAT 1 1
motor_current FLOAT 1 0
deadband FLOAT 1 1

Ah yes the beautiful polar bear. Quite a majestic device really. The polar bear is known as a motor controller. Essentially, a motor controller manages the movement speed of the motor it is attached to. This reliable beauty has three parameters.

The first one is duty_cycle, a float value which essentially dictates how powerful the motor should be and in what direction. Students are allowed to modify this to be a value between -1 and 1, where 1 is max power in a clockwise direction and -1 is power in a counterclockwise direction.

The next parameter is motorcurrent, a read only float that stands for the current flowing through the motor. This is read from the “FEEDBACK” pin.

Lastly, we have the “deadband” parameter, which is a float used to create a limit that a parameter must meet. Deadbands are typically used to prevent oscillation in a circuit. So if the change to some value, such as the duty_cycle, is small enough to be less than the deadband, then the motor controller ignores that change. For example, if upon initialization is the deadband is set to 0.05, and the duty_cycle input is 0.04, then no action will be taken by the motor controller. If the duty_cycle input is changed to 0.07, then the motor controller will handle that input.

Other functionalities of the motor controller is that it has LEDs that light up depending on the motion. The green LED lights up in forward movement, yellow in backward, and red if stopped. The motor controller also calculates how much to accelerate by manipulating the pins in the motor. The beast, has its drawbacks though, needing each of these titans to take control of a separate motor.

Distance Sensor

WAITING ON ELECTRICAL FOR EXACT PARAMETERS

The distance sensor is another active sensor in the student’s toolkit. The sensor does as is described, it detects the distance between the sensor and an object in front of it. The range of distance it reads is from 0cm to 500 cm. The distance sensor is, in fact, two sensors on this one device.

The first sensor is an ultrasonic sensor. This sensor utilizes ultrasonic waves and theior reflections to detect how far away an object is. It is stored as a read only long. The ultrasonic sensor can pick up the distance of objects from about 500cm away. One drawback about the ultrasonic sensor is it can get “fuzzy” at closer ranges, i.e. about 5cm. However, our brilliant staff from electrical have come up with a solution!

When the sensor is too close to an object, the IR sensor kicks in to notify the sensor that there is an object in front of it. The drawback for the IR sensor is it’s only a Boolean value. It cannot say how far an object is, only if its close. The IR sensor has a range of about 30 cm.

KoalaBear

Name type Readable Writeable
duty_cycle_a FLOAT 1 1
deadband_a FLOAT 1 1
current_a FLOAT 1 1
pid_enabled_a BOOL 1 1
pid_kp_a FLOAT 1 1
pid_ki_a FLOAT 1 1
pid_kd_a FLOAT 1 1
enc_a FLOAT 1 1
duty_cycle_b FLOAT 1 1
deadband_b FLOAT 1 1
current_b FLOAT 1 1
pid_enabled_b BOOL 1 1
pid_kp_b FLOAT 1 1
pid_ki_b FLOAT 1 1
pid_kd_b FLOAT 1 1
enc_b FLOAT 1 1

KoalaBear is the newest motor controller and the one that will be used from here on out. It has the same basic functionality as the PolarBear, it controls the motor’s speed, but is more advanced and has greater functionality than its predecessor. One of the two big changes is that a single KoalaBear can reign supremacy over two motors as opposed to the one like with a PolarBear. Because of this change, the KoalaBear comes with 16 parameters, making it a thicc device. 8 of the parameters are dedicated to “motor A” and the other 8 are dedicated to “motor b.”

The first three parameters are exactly like PolarBear’s parameters, duty_cycle, deadband, and current. Duty_cycle, once again, is the speed the students want the motor to operate at. It is a float ranging from -1 to 1. A deadband is a threshold that the duty_cycle input must pass before any changes are made to the motor. It is also a float between 0 and 1. The third parameter is the current of the motor, which at the time of writing this, still needs to be implemented. For a little more detail and example on how these parameters work together, I recommend checking out the section on Polar Bear devices.

Before moving on to the next set of parameters, we must first talk about the other great change with KoalaBear. Each KoalaBear has built in encoder that allows us to utilize PID control! An encoder is basically a device that allows us to translate the motor’s movements into actual distance values. The outputs for an encoder are in the form of square waves at the frequency of the motor’s rotation. By examining the wave right after a rising edge of Encoder A and comparing it to the voltage of Encoder B, we can determine in what direction its spinning. If the voltage of B is 0, then its spinning clockwise, but if its 5v its counterclockwise. This check is triggered after each rising edge of the encoder related to either motor A or motor B. With these checks, we either increment or decrement the enc_a or enc_b float parameters depending on which motor is the moving and in which direction. With this information, we can then implement PID control.

PID, which stands for proportional integral derivative, is a control loop feedback mechanism to control variables and give the most stable outputs. Essentially, it uses its own outputs as a variable in the inputs to produce accurate outputs. It does this by trying to minimize the “error” of the system down to zero. When the system first starts up, its error to the outcome is initially high, since we haven’t achieved the desired outcome. What I mean by this, is that the closer we get the desired outcome, the more our error will decrease which will be taken into account by the system. To calculate the error, we must sum three things together: the error itself, the accumulated error, and the expected error. These three are respectively multiplied by constant weights KP, KI, and KD. These K values must be adjusted correctly so that its not overtly sensitive or lack sensitivity. For a more in-depth, cohesive explanation, check out these videos: God Tier PID explanation and PID Examples!

PID can be used for many scenarios, but in our case, we just want to make sure the motor’s drive our robot at the appropriate speed. This is only used if the flag pid_enabled is set to true for either motor. When the robot moves forward, we use the enc_a/enc_b variables as the current position to calculate the error values and the desired output. The desired output is a value between [-1,1] that will be used to tell us how much to adjust the motor controller pins by. Upon each calculation, the values that were generated in this iteration are stored into previous values for use at the next calculation. Each motor comes with its own KP, KI, and KD variables as floats to use in this calculation.

The output is then fed into the drive() function in Koalabear to set the appropriate pins at the needed positions to get the robot to move at its intended speed. To move forward, we set the pwm2 pin to 255 and move pmw1 down to the calculated number. To move backwards, we set pmw1 to 255 and the pmw2 pin to the calculated number. This device is really remarkable and really shows the might of our Electrical team!

Virtual Devices

These devices exist for testing purposes and mimic physical lowcar devices. They allow us to write a wide range of tests.

TimeTestDevice

Name type Readable Writeable
GET_TIME BOOL 1 1
TIMESTAMP INT 1 0

The TimeTestDevice is essentially a device used for performance testing. With this device, we are testing the responsiveness between a button press and the time a device receives a response from net handler. Of course this isn’t an exact measurement but rather a best approximation.

This device has two parameters, get_time, a bool value which sets of the change in the next parameter, timestamp. Timestamp is an int that takes the last 9 digits of the time in milliseconds. This is because the time is in UNIX epoch, so the later digits aren’t necessarily as important. This device returns that time stamp so we can then subtract the time of a button press to the response of the device.

UnstableTestDevice

Name type Readable Writeable
NUM_ACTIONS INT 1 0

Another virtual device that we use for testing. This device is supposed to mimic a real lowcar device for very few seconds. After those seconds, the device goes silent and doesn’t send any more packets. This is to test that lowcar properly disconnects the device from shared memory after the device goes silent.

The only parameter in this virtual devuce is the NUM_ACTIONS param which is essentially a counter that gets checked and incremented on each device_action. Once it passes a threshold, the device sleeps for 60 seconds, giving dev_handler more than enough time to properly handle the device.

UnresponsiveTestDevice

NO PARAMETERS

A device that does literally nothing. It just sleeps. Still more active than me in any history classes sooooo :p

In all seriousness this is just to make sure that a device that doesn't send back an ACK also doesn't get connected to shared memory.

ForeignTestDevice

NO PARAMETERS

This device continuosly sends random bytes. It does include the delimiter, 0x00, but outside of that it's just random bytes that don't really mean anything. This device is also used to make sure no communication continues between a dev_handler and a device that doesn't send an ack.

SimpleTestDevice

Name type Readable Writeable
INCREASING INT 1 0
DOUBLING FLOAT 1 0
FLIP_FLOP BOOL 1 0
MY_INT INT 1 1

This virtual device acts low a lowcar device with a few parameters. The three out of the four are read-only parameters and the fourth one is a readable and writeable parameter. Upon each action, the device modifies its read only parameters. Its read only params cover all possible parameters in a lowcar device, ints, floats, and bools. This device is ideally used for sanity checks to make sure that dev handler and lowcar are both properly functioning.

GeneralTestDevice

Name type Readable Writeable
INCREASING_ODD INT 1 0
DECREASING_ODD INT 1 0
INCREASING_EVEN INT 1 0
DECREASING_EVEN INT 1 0
INCREASING_FLIP INT 1 0
ALWAYS_LEET INT 1 0
DOUBLING FLOAT 1 0
DOUBLING_NEG FLOAT 1 0
HALFING FLOAT 1 0
HALFING_NEG FLOAT 1 0
EXP_ONE_PT_ONE FLOAT 1 0
EXP_ONE_PT_TWO FLOAT 1 0
ALWAYS_PI FLOAT 1 0
FLIP_FLOP FLOAT 1 0
ALWAYS_TRUE BOOL 1 1
ALWAYS_FALSE INT 1 1
RED_INT INT 1 1
ORANGE_INT INT 1 1
GREEN_INT INT 1 1
BLUE_INT INT 1 1
PURPLE_INT INT 1 1
RED_FLOAT FLOAT 1 1
ORANGE_FLOAT FLOAT 1 1
GREEN_FLOAT FLOAT 1 1
BLUE_FLOAT FLOAT 1 1
PURPLE_FLOAT FLOAT 1 1
RED_BOOL FLOAT 1 1
ORANGE_BOOL BOOL 1 1
GREEN_BOOL BOOL 1 1
BLUE_BOOL BOOL 1 1
PURPLE_BOOL BOOL 1 1
YELLOW_BOOL BOOL 1 1

Exactly like a SimpleTestDevice but exercises all 32 parameters. Just like SimpleTestDevice it is an assortment of int, float, and bool values. The first 16 parameters are all read only and are changed upon each device action.

The names of the 16 read-only parameters describe what exactly is changing on each device action. The other 16 parameters are different types that the tests can write to and read from. This virtual device is used across many of our dev handler test.