We now wanted to try to test and practice driving with our robot. To do this we needed to add the motor to the lift.
Create
We added the motor to the side of our lift.
We mounted a Rotational Sensor to the lift, allowing us to know its position at all times.
Worked on new code for the lift using the Rotational Sensor.
Added a triangle of rubber bands to the lift to help counteract gravity’s uneven pull on the lift. Because torque is given by r*f*sin(theta), the torque due to gravity acting on the lift changes as the lift changes height. The triangle banding creates a nonlinear torque that oppositely matches the force of gravity. This is a trick we picked up in Tower Takeover.
Test
The lift worked great and was very much improved by the rubber bands.
Code
To set up control of the lift, we can use a state machine to set the state of the lift (like top, bottom, etc–what the lift should be doing) with the controlState() function, then actually make the robot execute the state with the update() function. The organizational paradigm is very useful for keeping everything straight.
/**
* LiftStateMachine.hpp
*
* This file contains the declaration of the LiftStateMachine class.
* LiftStateMachine is a state machine that inherits from VStateMachine.
* It has an enumeration of different possible states to make it easy for
* the user to controll the drivetrain.
*
* To use the state machine in auton, make sure you disable/reenable
* the normal state machine tasks and run the specified action.
*/#pragma once // makes sure the file is only included once
#include "main.h" // gives access to dependancies from other files
classLiftStateMachine:publicVStateMachine// state machine to represent the drivetrain{public:LiftStateMachine();// constructor to set defaultsenumclassMStates// enumeration to organize possible states{off,// not doing anythinghold,// hold the lift where it isup,// moves the lift updown,// moves the lift downtop,// moves the arm to the top and holdsbottom,// moves the lift to the bottom and holds};MStatesgetState();voidsetState(constMStatesistate);boolstateChanged();voidengageClaw();voiddisengageClaw();voidcontrolState()override;// update the state based on controller inputvoidupdate()override;// move the robot based on the stateprivate:/* ------------------------- Devices ------------------------- */Motor&mmtr;SolenoidWrappermclaw;RotationSensor&mrotation;DistanceSensorWrappermdistance;/* -------------------------- State -------------------------- */MStatesmstate,mlastState;boolmoverrideDistance;boolmengageClaw;/* ------------------------- Controls ------------------------ */ControllerButton&mbtnToggle;// botton to toggle the lift being up/downControllerButton&mbtnUp;// button to raise the liftControllerButton&mbtnDown;// button to lower the liftControllerButton&mbtnPneumaticToggle;// button to toggle the claw actuated/not};namespacedef{externLiftStateMachinesm_lift;// declares the sm_dt object as extern, to make sure it only gets constructed once}// namespace def
controlState() and update() in LiftStateMachine.cpp
voidLiftStateMachine::controlState()// update the state based on controller input{if(mbtnToggle.changedToPressed()){if(mstate==LIFT_STATES::top||mrotation.get()>def::SET_LIFT_TOP_DEG/2)// if the lift is at the top, or closer to the top{setState(LIFT_STATES::bottom);}else// if the lift is closer to the bottom{setState(LIFT_STATES::top);}}elseif(mbtnUp.isPressed()){setState(LIFT_STATES::up);}elseif(mbtnDown.isPressed()){setState(LIFT_STATES::down);}elseif(mstate!=LIFT_STATES::top&&mstate!=LIFT_STATES::bottom)// if the lift isn't set to a position, hold{setState(LIFT_STATES::hold);}if(mbtnPneumaticToggle.changedToPressed())// if pneumatics are manually toggled{moverrideDistance=true;// give manual control rightsmclaw.toggle();// toggle}if(moverrideDistance&&mclaw.isEngaged()==mdistance.getDistance()<def::SET_LIFT_DISTANCE_MIN_MM)// if sensor is overridden but agrees with manual instruction{moverrideDistance=false;// reengage sensor}if(!moverrideDistance)// if the sensor isn't disabled{if(mdistance.getDistance()<def::SET_LIFT_DISTANCE_MIN_MM)// if something is close enough to the distance sensor{mclaw.toggle(true);}else{mclaw.toggle(false);}}}voidLiftStateMachine::update()// move the robot based on the state{switch(mstate){caseLIFT_STATES::off:if(stateChanged()){mmtr.setBrakeMode(AbstractMotor::brakeMode::coast);mmtr.moveVoltage(0);}break;caseLIFT_STATES::hold:if(stateChanged()){mmtr.setBrakeMode(AbstractMotor::brakeMode::hold);mmtr.moveVoltage(0);}break;caseLIFT_STATES::up:if(stateChanged()){mmtr.moveVoltage(12000);}break;caseLIFT_STATES::down:if(stateChanged()){mmtr.moveVoltage(-12000);}break;caseLIFT_STATES::top:mmtr.setBrakeMode(AbstractMotor::brakeMode::hold);if(mrotation.get()<def::SET_LIFT_TOP_DEG-def::SET_LIFT_RANGE_DEG)// if the lift is below the minimum height{mmtr.moveVoltage(12000);}elseif(mrotation.get()>def::SET_LIFT_TOP_DEG+def::SET_LIFT_RANGE_DEG)// if the lift is above the maximum height{mmtr.moveVoltage(-12000);}else// if the lift is in range, don't move{mmtr.moveVoltage(0);}break;caseLIFT_STATES::bottom:mmtr.setBrakeMode(AbstractMotor::brakeMode::coast);if(mrotation.get()<-def::SET_LIFT_RANGE_DEG)// if the lift is below the minimum height{mmtr.moveVoltage(12000);}elseif(mrotation.get()>def::SET_LIFT_RANGE_DEG)// if the lift is above the maximum height{mmtr.moveVoltage(-12000);}else// if the lift is in range, don't move{mmtr.moveVoltage(0);}break;}}
Robot-1
We also had to add the radio in order to start practicing.
Create
We added the Radio to the top of our robot
We decided to mount the Radio on standoffs with rubber from Omni-Directional Wheels
The rubber can absorb vibrations to prevent problems communicating with the Controller
The rubber also prevents static from reaching the Radio by creating a break in conductors.
Holder-1.1.1
After we added a Lexan ramp in Holder 1.1.0 to allow us to hold 3 mobile goals we where happy by the results but realized we lost some range. We found the lexon was blocking the Mobile Goal from going all the way into our grabber before the holder was powered.
Build
We found the most effective way to do this was to add two Standoffs in order to extend the range and stop Mobile Goals from slipping out of the unpowerd grabber.
Test
The Grabber worked a lot better with the Standoffs and fixed our range problem.