├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── common.mk ├── docs-dev ├── LICENSE ├── README.md ├── archetypes │ └── default.md ├── config.toml ├── content │ ├── api │ │ ├── chassisController │ │ │ ├── chassisController.md │ │ │ ├── chassisControllerPID.md │ │ │ └── odomChassisController │ │ │ │ ├── odomChassisController.md │ │ │ │ └── odomChassisControllerPID.md │ │ ├── chassisModel │ │ │ ├── chassisModel.md │ │ │ ├── chassisModelParams.md │ │ │ ├── skidSteerModel │ │ │ │ ├── skidSteerModel.md │ │ │ │ └── skidSteerModelParams.md │ │ │ └── xDriveModel │ │ │ │ ├── xDriveModel.md │ │ │ │ └── xDriveModelParams.md │ │ ├── control │ │ │ ├── controlObject.md │ │ │ ├── genericController.md │ │ │ ├── pid │ │ │ │ ├── nsPid.md │ │ │ │ ├── pid.md │ │ │ │ ├── pidParams.md │ │ │ │ ├── velPid.md │ │ │ │ └── velPidParams.md │ │ │ └── velMath.md │ │ ├── device │ │ │ ├── button.md │ │ │ ├── cubicMotor.md │ │ │ ├── cubicSlewMotor.md │ │ │ ├── ime.md │ │ │ ├── motor.md │ │ │ ├── potentiometer.md │ │ │ ├── quadEncoder.md │ │ │ ├── rangeFinder.md │ │ │ ├── rotarySensor.md │ │ │ └── slewMotor.md │ │ ├── filter │ │ │ ├── avgFilter.md │ │ │ ├── demaFilter.md │ │ │ ├── emaFilter.md │ │ │ └── filter.md │ │ ├── index.md │ │ ├── odometry │ │ │ ├── distanceAndAngle.md │ │ │ ├── odomMath.md │ │ │ └── odometry.md │ │ └── util │ │ │ ├── mathUtil.md │ │ │ └── timer.md │ ├── getting-started │ │ └── index.md │ ├── home │ │ └── index.md │ ├── images │ │ ├── okapi.jpg │ │ └── skillsRobotPicture.jpg │ ├── index.md │ ├── license │ │ └── index.md │ └── tutorials │ │ ├── buttonTutorial.md │ │ ├── chassisControllerTutorial.md │ │ ├── chassisModelTutorial.md │ │ ├── genContTutorial.md │ │ ├── index.md │ │ ├── motorTutorial.md │ │ └── pidTutorial.md ├── data │ └── .gitkeep ├── layouts │ ├── .gitkeep │ └── shortcodes │ │ ├── importPartial.html │ │ ├── insert_file.html │ │ └── readfile.html └── static │ ├── .gitkeep │ └── css │ └── imageAlign.css ├── docs ├── .gitkeep ├── api │ ├── chassiscontroller │ │ ├── chassiscontroller │ │ │ └── index.html │ │ ├── chassiscontrollerpid │ │ │ └── index.html │ │ └── odomchassiscontroller │ │ │ ├── odomchassiscontroller │ │ │ └── index.html │ │ │ └── odomchassiscontrollerpid │ │ │ └── index.html │ ├── chassismodel │ │ ├── chassismodel │ │ │ └── index.html │ │ ├── chassismodelparams │ │ │ └── index.html │ │ ├── skidsteermodel │ │ │ ├── skidsteermodel │ │ │ │ └── index.html │ │ │ └── skidsteermodelparams │ │ │ │ └── index.html │ │ └── xdrivemodel │ │ │ ├── xdrivemodel │ │ │ └── index.html │ │ │ └── xdrivemodelparams │ │ │ └── index.html │ ├── control │ │ ├── controlobject │ │ │ └── index.html │ │ ├── genericcontroller │ │ │ └── index.html │ │ ├── pid │ │ │ ├── nspid │ │ │ │ └── index.html │ │ │ ├── pid │ │ │ │ └── index.html │ │ │ ├── pidparams │ │ │ │ └── index.html │ │ │ ├── velpid │ │ │ │ └── index.html │ │ │ └── velpidparams │ │ │ │ └── index.html │ │ └── velmath │ │ │ └── index.html │ ├── device │ │ ├── button │ │ │ └── index.html │ │ ├── cubicmotor │ │ │ └── index.html │ │ ├── cubicslewmotor │ │ │ └── index.html │ │ ├── ime │ │ │ └── index.html │ │ ├── motor │ │ │ └── index.html │ │ ├── potentiometer │ │ │ └── index.html │ │ ├── quadencoder │ │ │ └── index.html │ │ ├── rangefinder │ │ │ └── index.html │ │ ├── rotarysensor │ │ │ └── index.html │ │ └── slewmotor │ │ │ └── index.html │ ├── filter │ │ ├── avgfilter │ │ │ └── index.html │ │ ├── demafilter │ │ │ └── index.html │ │ ├── emafilter │ │ │ └── index.html │ │ └── filter │ │ │ └── index.html │ ├── index.html │ ├── index.xml │ ├── odometry │ │ ├── distanceandangle │ │ │ └── index.html │ │ ├── odometry │ │ │ └── index.html │ │ └── odommath │ │ │ └── index.html │ └── util │ │ ├── mathutil │ │ └── index.html │ │ └── timer │ │ └── index.html ├── categories │ └── index.xml ├── css │ └── imageAlign.css ├── fonts │ ├── icon.eot │ ├── icon.svg │ ├── icon.ttf │ └── icon.woff ├── getting-started │ ├── index.html │ └── index.xml ├── home │ ├── index.html │ └── index.xml ├── images │ ├── colors.png │ ├── favicon.ico │ ├── logo.png │ ├── okapi.jpg │ ├── screen.png │ └── skillsRobotPicture.jpg ├── index.html ├── index.xml ├── javascripts │ ├── application.js │ └── modernizr.js ├── license │ ├── index.html │ └── index.xml ├── sitemap.xml ├── stylesheets │ ├── application.css │ ├── highlight │ │ └── highlight.css │ ├── palettes.css │ └── temporary.css ├── tags │ └── index.xml └── tutorials │ ├── buttontutorial │ └── index.html │ ├── chassiscontrollertutorial │ └── index.html │ ├── chassismodeltutorial │ └── index.html │ ├── genconttutorial │ └── index.html │ ├── index.html │ ├── index.xml │ ├── motortutorial │ └── index.html │ └── pidtutorial │ └── index.html ├── firmware ├── STM32F10x.ld ├── cortex.ld ├── libpros.a └── uniflash.jar ├── include ├── API.h ├── PAL │ └── PAL.h ├── chassis │ ├── chassisController.h │ ├── chassisModel.h │ └── odomChassisController.h ├── control │ ├── controlObject.h │ ├── genericController.h │ ├── nsPid.h │ ├── pid.h │ ├── velMath.h │ └── velPid.h ├── device │ ├── button.h │ ├── ime.h │ ├── motor.h │ ├── potentiometer.h │ ├── quadEncoder.h │ ├── rangeFinder.h │ └── rotarySensor.h ├── filter │ ├── avgFilter.h │ ├── demaFilter.h │ ├── emaFilter.h │ └── filter.h ├── main.h ├── odometry │ ├── odomMath.h │ └── odometry.h └── util │ ├── mathUtil.h │ └── timer.h ├── okapilib-template ├── firmware │ └── okapilib.a ├── include │ ├── API.h │ ├── chassis │ │ ├── chassisController.h │ │ ├── chassisModel.h │ │ └── odomChassisController.h │ ├── control │ │ ├── controlObject.h │ │ ├── genericController.h │ │ ├── nsPid.h │ │ ├── pid.h │ │ ├── velMath.h │ │ └── velPid.h │ ├── device │ │ ├── button.h │ │ ├── ime.h │ │ ├── motor.h │ │ ├── potentiometer.h │ │ ├── quadEncoder.h │ │ ├── rangeFinder.h │ │ └── rotarySensor.h │ ├── filter │ │ ├── avgFilter.h │ │ ├── demaFilter.h │ │ ├── emaFilter.h │ │ └── filter.h │ ├── main.h │ ├── odometry │ │ ├── odomMath.h │ │ └── odometry.h │ └── util │ │ ├── mathUtil.h │ │ └── timer.h └── template.pros ├── project.pros ├── src ├── Makefile ├── auto.cpp ├── chassis │ ├── chassisController.cpp │ └── odomChassisController.cpp ├── control │ ├── nsPid.cpp │ ├── pid.cpp │ ├── velMath.cpp │ └── velPid.cpp ├── init.cpp ├── odometry │ ├── odomMath.cpp │ └── odometry.cpp ├── opcontrol.cpp └── util │ └── timer.cpp └── template.mk /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | *.o 3 | program 4 | *.dblite 5 | .vscode/ 6 | okapilib-template.zip 7 | .clang/ 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docs-dev/themes/hugo-material-docs"] 2 | path = docs-dev/themes/hugo-material-docs 3 | url = https://github.com/digitalcraftsman/hugo-material-docs.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | 4 | before_install: 5 | - sudo apt-get update -y 6 | - sudo apt-get install -y lib32z1 lib32ncurses5 lib32bz2-1.0 7 | 8 | install: 9 | - wget -O ~/gcc-arm-none-eabi-4_9-2014q4-20141203-linux.tar.bz2 https://launchpad.net/gcc-arm-embedded/4.9/4.9-2014-q4-major/+download/gcc-arm-none-eabi-4_9-2014q4-20141203-linux.tar.bz2 10 | - tar -xf ~/gcc-arm-none-eabi-4_9-2014q4-20141203-linux.tar.bz2 -C ~ 11 | 12 | language: cpp 13 | compiler: gcc 14 | 15 | script: 16 | - make all MCUPREFIX=~/gcc-arm-none-eabi-4_9-2014q4/bin/arm-none-eabi- 17 | 18 | # test: make all CCFLAGS+=-DDEBUG 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Universal C Makefile for MCU targets 2 | 3 | # Path to project root (for top-level, so the project is in ./; first-level, ../; etc.) 4 | ROOT=. 5 | # Binary output directory 6 | BINDIR=$(ROOT)/bin 7 | # Subdirectories to include in the build 8 | SUBDIRS=src 9 | 10 | # Nothing below here needs to be modified by typical users 11 | 12 | # Include common aspects of this project 13 | -include $(ROOT)/common.mk 14 | -include $(ROOT)/template.mk 15 | 16 | ASMSRC:=$(wildcard *.$(ASMEXT)) 17 | ASMOBJ:=$(patsubst %.o,$(BINDIR)/%.o,$(ASMSRC:.$(ASMEXT)=.o)) 18 | HEADERS:=$(wildcard *.$(HEXT)) 19 | CSRC=$(wildcard *.$(CEXT)) 20 | COBJ:=$(patsubst %.o,$(BINDIR)/%.o,$(CSRC:.$(CEXT)=.o)) 21 | CPPSRC:=$(wildcard *.$(CPPEXT)) 22 | CPPOBJ:=$(patsubst %.o,$(BINDIR)/%.o,$(CPPSRC:.$(CPPEXT)=.o)) 23 | OUT:=$(BINDIR)/$(OUTNAME) 24 | 25 | .PHONY: all clean flash upload upload-legacy _force_look 26 | 27 | # By default, compile program 28 | all: $(BINDIR) $(OUT) 29 | 30 | # Remove all intermediate object files (remove the binary directory) 31 | clean: 32 | -rm -f $(OUT) 33 | -rm -rf $(BINDIR) 34 | 35 | # Uploads program to device 36 | upload: all 37 | $(FLASH) 38 | 39 | # Alias to upload, more consistent with our terminology 40 | flash: upload 41 | 42 | # Uploads program to device using legacy uniflasher JAR file 43 | upload-legacy: all 44 | $(UPLOAD) 45 | 46 | # Phony force-look target 47 | _force_look: 48 | @true 49 | 50 | # Looks in subdirectories for things to make 51 | $(SUBDIRS): %: _force_look 52 | @$(MAKE) --no-print-directory -C $@ 53 | 54 | # Ensure binary directory exists 55 | $(BINDIR): 56 | -@mkdir -p $(BINDIR) 57 | 58 | # Compile program 59 | $(OUT): $(SUBDIRS) $(ASMOBJ) $(COBJ) $(CPPOBJ) 60 | @echo LN $(BINDIR)/*.o $(LIBRARIES) to $@ 61 | @$(CC) $(LDFLAGS) $(BINDIR)/*.o $(LIBRARIES) -o $@ 62 | @$(MCUPREFIX)size $(SIZEFLAGS) $(OUT) 63 | $(MCUPREPARE) 64 | 65 | # Assembly source file management 66 | $(ASMOBJ): $(BINDIR)/%.o: %.$(ASMEXT) $(HEADERS) 67 | @echo AS $< 68 | @$(AS) $(AFLAGS) -o $@ $< 69 | 70 | # Object management 71 | $(COBJ): $(BINDIR)/%.o: %.$(CEXT) $(HEADERS) 72 | @echo CC $(INCLUDE) $< 73 | $(CC) $(INCLUDE) $(CFLAGS) -o $@ $< 74 | 75 | $(CPPOBJ): $(BINDIR)/%.o: %.$(CPPEXT) $(HEADERS) 76 | @echo CPC $(INCLUDE) $< 77 | @$(CPPCC) $(INCLUDE) $(CPPFLAGS) -o $@ $< 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OkapiLib 2 | 3 | ![Build status](https://travis-ci.org/OkapiLib/OkapiLib.svg?branch=master) 4 | 5 | A PROS library for programming Vex robots. Build currently tested working with arm-none-eabi-g++ 4.9.3 20141119 (release) [ARM/embedded-4_9-branch revision 218278]. The Travis script contains the full URL for wget. 6 | 7 | The actual PROS API is split into include/ and src/ folders. Documentation is hosted out of docs/ and developed using Hugo out of docs-dev/. 8 | 9 | Documentation here https://okapilib.github.io/OkapiLib/ and Trello here https://trello.com/b/MO6LoUix/okapilib. -------------------------------------------------------------------------------- /common.mk: -------------------------------------------------------------------------------- 1 | # Universal C Makefile for MCU targets 2 | # Top-level template file to configure build 3 | 4 | MAKE_COMMAND=make 5 | 6 | # Makefile for IFI VeX Cortex Microcontroller (STM32F103VD series) 7 | DEVICE=VexCortex 8 | # Libraries to include in the link (use -L and -l) e.g. -lm, -lmyLib 9 | LIBRARIES=$(wildcard $(ROOT)/firmware/*.a) -lgcc -lm 10 | # Prefix for ARM tools (must be on the path) 11 | MCUPREFIX=~/gcc-arm-none-eabi-4_9-2014q4/bin/arm-none-eabi- 12 | # Flags for the assembler 13 | MCUAFLAGS=-mthumb -mcpu=cortex-m3 -mlittle-endian 14 | # Flags for the compiler 15 | MCUCFLAGS=-mthumb -mcpu=cortex-m3 -mlittle-endian -mfloat-abi=soft 16 | # Flags for the linker 17 | MCULFLAGS=-nostartfiles -Wl,-static -Bfirmware -Wl,-u,VectorTable -Wl,-T -Xlinker firmware/cortex.ld 18 | # Prepares the elf file by converting it to a binary that java can write 19 | MCUPREPARE=$(OBJCOPY) $(OUT) -O binary $(BINDIR)/$(OUTBIN) 20 | # Advanced sizing flags 21 | SIZEFLAGS= 22 | # Uploads program using java 23 | UPLOAD=@java -jar firmware/uniflash.jar vex $(BINDIR)/$(OUTBIN) 24 | # Flashes program using the PROS CLI flash command 25 | FLASH=pros flash -f $(BINDIR)/$(OUTBIN) 26 | 27 | # Advanced options 28 | ASMEXT=s 29 | CEXT=c 30 | CPPEXT=cpp 31 | HEXT=h 32 | INCLUDE=-I$(ROOT)/include -I$(ROOT)/src 33 | OUTBIN=output.bin 34 | OUTNAME=output.elf 35 | 36 | # Flags for programs 37 | AFLAGS:=$(MCUAFLAGS) 38 | ARFLAGS:=$(MCUCFLAGS) 39 | CCFLAGS:=-c -Wall -pedantic -Wextra -Wconversion -Wno-implicit-fallthrough -Wmissing-include-dirs $(MCUCFLAGS) -O2 -ffunction-sections -fsigned-char -fomit-frame-pointer -fsingle-precision-constant 40 | CFLAGS:=$(CCFLAGS) -std=gnu99 -Werror=implicit-function-declaration 41 | CPPFLAGS:=$(CCFLAGS) -std=c++14 -fno-exceptions -fno-rtti -felide-constructors 42 | LDFLAGS:=-Wall $(MCUCFLAGS) $(MCULFLAGS) -Wl,--gc-sections 43 | 44 | # Tools used in program 45 | AR:=$(MCUPREFIX)ar 46 | AS:=$(MCUPREFIX)as 47 | CC:=$(MCUPREFIX)gcc 48 | CPPCC:=$(MCUPREFIX)g++ 49 | OBJCOPY:=$(MCUPREFIX)objcopy 50 | -------------------------------------------------------------------------------- /docs-dev/README.md: -------------------------------------------------------------------------------- 1 | # OkapiDocs 2 | 3 | Documentation for OkapiLib, hosted on GitHub Pages: https://okapilib.github.io/OkapiDocs/ 4 | -------------------------------------------------------------------------------- /docs-dev/archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .TranslationBaseName "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /docs-dev/config.toml: -------------------------------------------------------------------------------- 1 | baseurl = "https://okapilib.github.io/OkapiLib/" 2 | languageCode = "en-us" 3 | title = "Okapi Docs" 4 | theme = "hugo-material-docs" 5 | metadataformat = "yaml" 6 | canonifyurls = true 7 | googleAnalytics = "UA-108357936-1" 8 | publishDir = "../docs" 9 | 10 | [params] 11 | # General information 12 | author = "OkapiLib" 13 | description = "A PROS library for fast C++ development." 14 | copyright = "" 15 | 16 | # Repository 17 | provider = "GitHub" 18 | repo_url = "https://github.com/OkapiLib/OkapiLib" 19 | 20 | version = "0.3.0" 21 | logo = "images/okapi.jpg" 22 | favicon = "" 23 | 24 | permalink = "#" 25 | 26 | # Custom assets 27 | custom_css = ["css/imageAlign.css"] 28 | custom_js = [] 29 | 30 | # Syntax highlighting theme 31 | highlight_css = "" 32 | 33 | [params.palette] 34 | primary = "red" 35 | accent = "teal" 36 | 37 | [params.font] 38 | text = "Ubuntu" 39 | code = "Ubuntu Mono" 40 | 41 | 42 | [social] 43 | twitter = "" 44 | github = "OkapiLib" 45 | email = "" 46 | 47 | 48 | [[menu.main]] 49 | name = "Home" 50 | url = "home/" 51 | weight = 10 52 | 53 | [[menu.main]] 54 | name = "Getting started" 55 | url = "getting-started/" 56 | weight = 20 57 | 58 | [[menu.main]] 59 | name = "Tutorials" 60 | url = "tutorials/" 61 | weight = 30 62 | 63 | [[menu.main]] 64 | name = "API" 65 | url = "api/" 66 | weight = 40 67 | 68 | [[menu.main]] 69 | name = "License" 70 | url = "license/" 71 | weight = 50 72 | 73 | 74 | [blackfriday] 75 | smartypants = true 76 | fractions = true 77 | smartDashes = true 78 | plainIDAnchors = true 79 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisController/chassisController.md: -------------------------------------------------------------------------------- 1 | ## ChassisController (abstract) 2 | 3 | The `ChassisController` class an interface for controlling a robot's chassis: it provides methods that build upon the basic methods `ChassisModel` has for more accurate control. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | ChassisController(const ChassisModelParams& imodelParams) 10 | ChassisController(std::shared_ptr imodel) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | imodelParams | `ChassisModelParams` (used to make a new `ChassisModel`) 16 | imodel | An existing `ChassisModel` 17 | 18 | ### driveStraight 19 | 20 | ```c++ 21 | //Signature 22 | virtual void driveStraight(const int itarget) = 0 23 | ``` 24 | 25 | Drive the robot straight for a distance of `itarget` in the units of `itarget`. 26 | 27 | Parameter | Description 28 | ----------|------------ 29 | itarget | Distance for the robot to travel 30 | 31 | ### pointTurn 32 | 33 | ```c++ 34 | //Signature 35 | virtual void pointTurn(const float idegTarget) = 0 36 | ``` 37 | 38 | Turn the robot in place for an angle of `idegTarget`. The units of the angle travel is most often the difference in encoder ticks between the two sides of the chassis. 39 | 40 | ### driveForward 41 | 42 | ```c++ 43 | //Signature 44 | void driveForward(const int power) 45 | ``` 46 | 47 | Passthrough function to call `driveForward` on the internal `ChassisModel`. 48 | 49 | ### driveVector 50 | 51 | ```c++ 52 | //Signature 53 | void driveVector(const int distPower, const int anglePower) 54 | ``` 55 | 56 | Passthrough function to call `driveVector` on the internal `ChassisModel`. 57 | 58 | ### turnClockwise 59 | 60 | ```c++ 61 | //Signature 62 | void turnClockwise(const int power) 63 | ``` 64 | 65 | Passthrough function to call `turnClockwise` on the internal `ChassisModel`. 66 | 67 | ### tank 68 | 69 | ```c++ 70 | //Signature 71 | void tank(const int leftVal, const int rightVal, const int threshold = 0) 72 | ``` 73 | 74 | Passthrough function to call `tank` on the internal `ChassisModel` 75 | 76 | ### arcade 77 | 78 | ```c++ 79 | //Signature 80 | void arcade(int verticalVal, int horizontalVal, const int threshold = 0) 81 | ``` 82 | 83 | Passthrough function to call `arcade` on the internal `ChassisModel` 84 | 85 | ### left 86 | 87 | ```c++ 88 | //Signature 89 | void left(const int val); 90 | ``` 91 | 92 | Passthrough function to call `left` on the internal `ChassisModel`. 93 | 94 | ### leftTS 95 | 96 | ```c++ 97 | //Signature 98 | void leftTS(const int val); 99 | ``` 100 | 101 | Passthrough function to call `leftTS` on the internal `ChassisModel`. 102 | 103 | ### right 104 | 105 | ```c++ 106 | //Signature 107 | void right(const int val); 108 | ``` 109 | 110 | Passthrough function to call `right` on the internal `ChassisModel`. 111 | 112 | ### rightTS 113 | 114 | ```c++ 115 | //Signature 116 | void rightTS(const int val); 117 | ``` 118 | 119 | Passthrough function to call `rightTS` on the internal `ChassisModel`. 120 | 121 | ### getEncoderVals 122 | 123 | ```c++ 124 | //Signature 125 | std::valarray getEncoderVals() const 126 | ``` 127 | 128 | Passthrough function to call `getEncoderVals` on the internal `ChassisModel`. 129 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisController/chassisControllerPID.md: -------------------------------------------------------------------------------- 1 | ## ChassisControllerPid 2 | 3 | The `ChassisControllerPid` class inherits from `ChassisController` and implements its interface using PID control. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | ChassisControllerPid(const ChassisModelParams& imodelParams, const PidParams& idistanceParams, const PidParams& iangleParams) 10 | ChassisControllerPid(const std::shared_ptr& imodel, const PidParams& idistanceParams, const PidParams& iangleParams) 11 | 12 | //Make a new ChassisControllerPid using a skid steer model with two motors per side 13 | ChassisControllerPid foo( 14 | SkidSteerModelParams<2>({1, 3, 2, 4}, //The four motor ports 15 | encoderInit(1, 2, false), //Left encoder 16 | encoderInit(3, 4, true)), //Right encoder 17 | PidParams(2, 0.1, 0.4), //Distance PID controller 18 | PidParams(0.3, 1.2, 0.1)); //Angle PID controller 19 | ``` 20 | 21 | Parameter | Description 22 | ----------|------------ 23 | imodelParams | `ChassisModelParams` (used to make a new `ChassisModel`) 24 | imodel | An existing `ChassisModel` 25 | idistanceParams | `PidParams` for the distance PID controller 26 | iangleParams | `PidParams` for the angle PID controller 27 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisController/odomChassisController/odomChassisController.md: -------------------------------------------------------------------------------- 1 | ## OdomChassisController (abstract) 2 | 3 | The `OdomChassisController` class inherits from `ChassisController`. It extends the `ChassisController` interface to add odometry-based functionality. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | OdomChassisController(OdomParams iparams) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | iparams | `OdomParams` (used to make a new `Odometry`) 15 | 16 | 19 | 20 | ### driveToPoint 21 | 22 | ```c++ 23 | //Signature 24 | virtual void driveToPoint(const float ix, const float iy, const bool ibackwards = false, const float ioffset = 0) = 0 25 | ``` 26 | 27 | Parameter | Description 28 | ----------|------------ 29 | ix | X coordinate of destination 30 | iy | Y coordinate of destination 31 | ibackwards | Whether to drive to the destination backwards (default false) 32 | ioffset | How far back from the destination to stop (default 0) 33 | 34 | Drive to the point (`ix`, `iy`) in the field frame. If required, the robot will first turn to face the destination point. 35 | 36 | ### turnToAngle 37 | 38 | ```c++ 39 | //Signature 40 | virtual void turnToAngle(const float iangle) = 0 41 | ``` 42 | 43 | Parameter | Description 44 | ----------|------------ 45 | iangle | Angle to face 46 | 47 | Turn to the angle `iangle` in the field frame. 48 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisController/odomChassisController/odomChassisControllerPID.md: -------------------------------------------------------------------------------- 1 | ## OdomChassisControllerPid 2 | 3 | The `OdomChassisControllerPid` class inherits from `OdomChassisController` and from `ChassisControllerPid`. It implements the `OdomChassisController` interface using PID control. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | OdomChassisControllerPid(const OdomParams& params, const PidParams& idistanceParams, const PidParams& iangleParams) 10 | 11 | //Make a new OdomChassisControllerPid using a skid steer model with two motors per side 12 | OdomChassisControllerPid foo( 13 | OdomParams( 14 | SkidSteerModelParams<2>({1,3,2,4}, //The four motor ports 15 | encoderInit(1,2,false), //Left encoder 16 | encoderInit(3,4,true)), //Right encoder 17 | 1.345, //Distance scale (encoder ticks to mm) 18 | 12.88361), //Turn scale (encoder ticks to deg) 19 | PidParams(0,0,0), //Distance PID controller 20 | PidParams(0,0,0)); //Angle PID controller 21 | ``` 22 | 23 | Parameter | Description 24 | ----------|------------ 25 | params | `OdomParams` (used to make a new `Odometry`) 26 | idistanceParams | `PidParams` for the distance PID controller 27 | iangleParams | `PidParams` for the angle PID controller 28 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisModel/chassisModel.md: -------------------------------------------------------------------------------- 1 | ## ChassisModel (abstract) 2 | 3 | The `ChassisModel` class is an interface to a robot's chassis: it provides methods to control the chassis and to read from standard sensors placed on most chassis (i.e., quadrature encoders). 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | ChassisModel() 10 | ``` 11 | 12 | The constructor does not take any parameters. 13 | 14 | ### driveForward 15 | 16 | ```c++ 17 | //Signature 18 | virtual void driveForward(const int power) = 0 19 | ``` 20 | 21 | Drives the chassis forwards by setting all motors to the input power. A positive value for `power` should cause all chassis wheels to move the robot forward in a straight line. Uses truespeed. 22 | 23 | Parameter | Description 24 | ----------|------------ 25 | power | The raw motor power sent directly to the chassis' motors 26 | 27 | ### turnClockwise 28 | 29 | ```c++ 30 | //Signature 31 | virtual void turnClockwise(const int power) = 0 32 | ``` 33 | 34 | Turns the robot clockwise by setting the left side motors to the input power and the right side motors to the negative of the input power. A positive value for `power` should cause all chassis wheels to turn the robot clockwise on a point. Uses truespeed. 35 | 36 | Parameter | Description 37 | ----------|------------ 38 | power | The raw motor power sent directly to the chassis' motors 39 | 40 | ### driveVector 41 | 42 | ```c++ 43 | //Signature 44 | virtual void driveVector(const int distPower, const int anglePower) = 0 45 | 46 | driveVector(127, 0) //Same as driveForward(127) 47 | driveVector(0, 127) //Same as turnClockwise(127) 48 | 49 | //Make a moderate swing turn clockwise 50 | //left motors get 110 power, right motors get 70 power 51 | driveVector(90, 20) 52 | ``` 53 | 54 | Drive the chassis along a curved path. Calling `driveVector(127, 0)` should be equivalent to calling `driveForward(127)`; calling `driveVector(0, 127)` should be equivalent to calling `turnClockwise(127)`. A mix between the two will cause the robot to make a swing turn. Uses truespeed. 55 | 56 | Parameter | Description 57 | ----------|------------ 58 | distPower | The motor power making up the "straight" component of the final motor power 59 | anglePower | The motor power making up the "turn" component of the final motor power 60 | 61 | ### tank 62 | 63 | ```c++ 64 | //Signature 65 | virtual void tank(const int leftVal, const int rightVal, const int threshold = 0) = 0; 66 | ``` 67 | 68 | Power the motors like tank drive. 69 | 70 | Parameter | Description 71 | ----------|------------ 72 | leftVal | Motor power for the left side motors 73 | rightVal | Motor power for the right side motors 74 | threshold | Motor power below this threshold will become zero 75 | 76 | ### arcade 77 | 78 | ```c++ 79 | //Signature 80 | virtual void arcade(int verticalVal, int horizontalVal, const int threshold = 0) = 0; 81 | ``` 82 | 83 | Power the motors like arcade drive. 84 | 85 | Parameter | Description 86 | ----------|------------ 87 | verticalVal | Motor power for the vertical component of movement 88 | horizontalVal | Motor power for the horizontal component of movement 89 | threshold | Motor power below this threshold will become zero 90 | 91 | ### left 92 | 93 | ```c++ 94 | //Signature 95 | virtual void left(const int val) = 0; 96 | ``` 97 | 98 | Power the left side motors. 99 | 100 | Parameter | Description 101 | ----------|------------ 102 | val | Motor power 103 | 104 | ### leftTS 105 | 106 | ```c++ 107 | //Signature 108 | virtual void leftTS(const int val) = 0; 109 | ``` 110 | 111 | Power the left side motors using truespeed. 112 | 113 | Parameter | Description 114 | ----------|------------ 115 | val | Motor power 116 | 117 | ### right 118 | 119 | ```c++ 120 | //Signature 121 | virtual void right(const int val) = 0; 122 | ``` 123 | 124 | Power the right side motors. 125 | 126 | Parameter | Description 127 | ----------|------------ 128 | val | Motor power 129 | 130 | ### rightTS 131 | 132 | ```c++ 133 | //Signature 134 | virtual void rightTS(const int val) = 0; 135 | ``` 136 | 137 | Power the right side motors using truespeed. 138 | 139 | Parameter | Description 140 | ----------|------------ 141 | val | Motor power 142 | 143 | ### getEncoderVals 144 | 145 | ```c++ 146 | //Signature 147 | virtual std::valarray getSensorVals() = 0 148 | ``` 149 | 150 | Reads the sensors given to the chassis model at construction time and returns them in the format `{left sensor value, right sensor value}`. Return type is a `std::valarray` because it features operator overrides for common math operations making encoder math easy. 151 | 152 | ### resetSensors 153 | 154 | ```c++ 155 | //Signature 156 | virtual void resetSensors() = 0 157 | ``` 158 | 159 | Reset the sensors to zero. 160 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisModel/chassisModelParams.md: -------------------------------------------------------------------------------- 1 | ## ChassisModelParams (Abstract) 2 | 3 | The `ChassisModelParams` class encapsulates the parameters a `ChassisModel` takes. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | ChassisModelParams() 10 | ``` 11 | 12 | The constructor does not take any parameters. 13 | 14 | ### make 15 | 16 | Allocate a new `ChassisModel` and return a `std::shared_ptr` to it. Most users will not have to call this, classes that take a `ChassisModel` will figure out the memory model themselves. 17 | 18 | ```c++ 19 | //Signature 20 | virtual std::shared_ptr make() const = 0 21 | ``` 22 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisModel/skidSteerModel/skidSteerModel.md: -------------------------------------------------------------------------------- 1 | ## SkidSteerModel 2 | 3 | The `SkidSteerModel` class inherits from `ChassisModel` and takes a template parameter `size_t motorsPerSide` (the number of motors per each of the two sides of the chassis). It is a model for a skid steer drive (also called a tank drive). 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | SkidSteerModel(const std::array& imotorList, const QuadEncoder& ileftEnc, const QuadEncoder& irightEnc) 10 | SkidSteerModel(const std::array& imotorList, const IME& ileftIME, const IME& irightIME) 11 | SkidSteerModel(const SkidSteerModelParams& iparams) 12 | SkidSteerModel(const SkidSteerModel& other) 13 | 14 | //Construct a SkidSteerModel with four motors (two per side) and two encoders 15 | //Left side motors are ports 1 and 3 16 | //Right side motors are ports 2 and 4 17 | //Right side encoder is reversed because it is a mirror of the left side 18 | SkidSteerModel<2> foo({1, 3, 2, 4}, QuadEncoder(1, 2, false), QuadEncoder(3, 4, true)); 19 | ``` 20 | 21 | Parameter | Description 22 | ----------|------------ 23 | imotorList | The left and right side motors for the drive in the format, `{left motors, right motors}` 24 | ileftEnc | The quadrature encoder for the left side 25 | irightEnc | The quadrature encoder for the right side 26 | ileftIME | The IME for the left side 27 | irightIME | The IME for the right side 28 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisModel/skidSteerModel/skidSteerModelParams.md: -------------------------------------------------------------------------------- 1 | ## SkidSteerModelParams 2 | 3 | The `SkidSteerModelParams` class inherits from `ChassisModelParams`. It encapsulates the parameters a `SkidSteerModel` takes. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | SkidSteerModelParams(const std::array& imotorList, const QuadEncoder& ileftEnc, const QuadEncoder& irightEnc): 10 | SkidSteerModelParams(const std::array& imotorList, const IME& ileftIME, const IME& irightIME) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | imotorList | The left and right side motors for the drive in the format, `{left motors, right motors}` 16 | ileftEnc | The quadrature encoder for the left side 17 | irightEnc | The quadrature encoder for the right side 18 | ileftIME | The IME for the left side 19 | irightIME | The IME for the right side 20 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisModel/xDriveModel/xDriveModel.md: -------------------------------------------------------------------------------- 1 | ## XDriveModel 2 | 3 | The `XDriveModel` class inherits from `ChassisModel` and takes a template parameter `size_t motorsPerCorner` (the number of motors per each of the four corners of the chassis). It is a model for an x-drive. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | XDriveModelParams(const std::array& imotorList, const QuadEncoder& ileftEnc, const QuadEncoder& irightEnc): 10 | XDriveModelParams(const std::array& imotorList, const IME& ileftIME, const IME& irightIME) 11 | XDriveModel(const XDriveModelParams& iparams) 12 | XDriveModel(const XDriveModel& other) 13 | 14 | //Construct an XDriveModel with four motors (one per corner) and two encoders 15 | //Top left motor is port 1, top right motor is port 2 16 | //Bottom right motor is port 3, bottom left motor is port 4 17 | //Right side encoder is reversed because it is a mirror of the left side 18 | XDriveModel<1> foo({1, 2, 3, 4}, QuadEncoder(1, 2, false), QuadEncoder(3, 4, true)); 19 | 20 | //Construct an XDriveModel with eight motors (two per corner) and two encoders 21 | //Top left motors are ports 1 and 2, top right motors are ports 3 and 4 22 | //Bottom right motors are ports 5 and 6, bottom left motors are ports 7 and 8 23 | //Right side encoder is reversed because it is a mirror of the left side 24 | XDriveModel<2> foo({1, 2, 3, 4, 5, 6, 7, 8}, QuadEncoder(1, 2, false), QuadEncoder(3, 4, true)); 25 | ``` 26 | 27 | Parameter | Description 28 | ----------|------------ 29 | imotorList | The chassis motors for the drive in the clockwise format, `{top left motors, top right motors, bottom right motors, bottom left motors}` 30 | ileftEnc | The quadrature encoder for the left side 31 | irightEnc | The quadrature encoder for the right side 32 | ileftIME | The IME for the left side 33 | irightIME | The IME for the right side 34 | 35 | ### xArcade 36 | 37 | ```c++ 38 | //Signature 39 | void xArcade(const int verticalVal, const int horizontalVal, const int rotateVal) 40 | ``` 41 | 42 | Specifically for an x-drive, power the motors like arcade drive with a channel for rotation. 43 | 44 | Parameter | Description 45 | ----------|------------ 46 | verticalVal | Motor power for the vertical component of movement 47 | horizontalVal | Motor power for the horizontal component of movement 48 | rotateVal | Motor power for rotation 49 | -------------------------------------------------------------------------------- /docs-dev/content/api/chassisModel/xDriveModel/xDriveModelParams.md: -------------------------------------------------------------------------------- 1 | ## XDriveModelParams 2 | 3 | The `XDriveModelParams` class inherits from `ChassisModelParams`. It encapsulates the parameters an `XDriveModel` takes. 4 | 5 | ### Constructor 6 | ```c++ 7 | //Signature 8 | XDriveModelParams(const std::array& imotorList, const QuadEncoder& ileftEnc, const QuadEncoder& irightEnc): 9 | XDriveModelParams(const std::array& imotorList, const IME& ileftIME, const IME& irightIME) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | imotorList | The chassis motors for the drive in the clockwise format, `{top left motors, top right motors, bottom right motors, bottom left motors}` 15 | ileftEnc | The quadrature encoder for the left side 16 | irightEnc | The quadrature encoder for the right side 17 | ileftIME | The IME for the left side 18 | irightIME | The IME for the right side 19 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/controlObject.md: -------------------------------------------------------------------------------- 1 | ## ControlObject (abstract) 2 | 3 | The `ControlObject` class is an interface to closed-loop controllers. It requires implementation of step, target, and output functions. 4 | 5 | ### step 6 | 7 | ```c++ 8 | //Signature 9 | virtual float step(const float ireading) = 0 10 | ``` 11 | 12 | Do one iteration of the control math to compute a new motor power. Normally called in a loop. 13 | 14 | Parameter | Description 15 | ----------|------------ 16 | ireading | New sensor reading 17 | 18 | ### setTarget 19 | 20 | ```c++ 21 | //Signature 22 | virtual void setTarget(const float itarget) = 0 23 | ``` 24 | 25 | Set the target value. 26 | 27 | Parameter | Description 28 | ----------|------------ 29 | itarget | New target value 30 | 31 | ### getOutput 32 | 33 | ```c++ 34 | //Signature 35 | virtual float getOutput() const = 0 36 | ``` 37 | 38 | Return the most recent controller output. 39 | 40 | ### getError 41 | 42 | ```c++ 43 | //Signature 44 | virtual float getError() const = 0 45 | ``` 46 | 47 | Return the most recent controller error. 48 | 49 | ### setSampleTime 50 | 51 | ```c++ 52 | //Signature 53 | virtual void setSampleTime(const int isampleTime) 54 | ``` 55 | 56 | Set the timestep (in ms) between calls to `step`. 57 | 58 | Parameter | Description 59 | ----------|------------ 60 | isampleTime | Timestep between calls to `step` in ms 61 | 62 | ### setOutputLimits 63 | 64 | ```c++ 65 | //Signature 66 | virtual void setOutputLimits(float imax, float imin) 67 | ``` 68 | 69 | Set the max and min value for the controller output. 70 | 71 | Parameter | Description 72 | ----------|------------ 73 | imax | Max output 74 | imin | Min output 75 | 76 | ### reset 77 | 78 | ```c++ 79 | //Signature 80 | virtual void reset() 81 | ``` 82 | 83 | Reset the controller so it will start from zero again. 84 | 85 | ### flipDisable 86 | 87 | ```c++ 88 | //Signature 89 | virtual void flipDisable() 90 | ``` 91 | 92 | Change whether the controller is on or off. A controller which is off will output 0. 93 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/genericController.md: -------------------------------------------------------------------------------- 1 | ## GenericController 2 | 3 | The `GenericController` class combines motors and a `ControlObject` into one package that uses the controller to control the motors as a group (all motors get the same controller output). 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | GenericController(const std::array &imotorList, const std::shared_ptr &iptr) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | imotorList | `std::array` of `Motor` that will be controlled 15 | iptr | `ControlObject` used to control the motors 16 | 17 | ### step 18 | 19 | ```c++ 20 | //Signature 21 | void step(const float ireading) 22 | ``` 23 | 24 | Have the `ControlObject` do one iteration and then power the motors with the output. This needs to be called every so many milliseconds (15 ms works fine). 25 | 26 | Parameter | Description 27 | ----------|------------ 28 | ireading | New sensor reading 29 | 30 | ### setTarget 31 | 32 | ```c++ 33 | //Signature 34 | void setTarget(const float itarget) 35 | ``` 36 | 37 | Set the target value. 38 | 39 | Parameter | Description 40 | ----------|------------ 41 | itarget | New target value 42 | 43 | ### getOutput 44 | 45 | ```c++ 46 | //Signature 47 | void getOutput() const 48 | ``` 49 | 50 | Return the most recent controller output. 51 | 52 | ### setSampleTime 53 | 54 | ```c++ 55 | //Signature 56 | void setSampleTime(const int isampleTime) 57 | ``` 58 | 59 | Set the timestep (in ms) between calls to `step`. 60 | 61 | Parameter | Description 62 | ----------|------------ 63 | isampleTime | Timestep between calls to `step` in ms 64 | 65 | ### setOutputLimits 66 | 67 | ```c++ 68 | //Signature 69 | void setOutputLimits(float imax, float imin) 70 | ``` 71 | 72 | Set the max and min value for the controller output. 73 | 74 | Parameter | Description 75 | ----------|------------ 76 | imax | Max output 77 | imin | Min output 78 | 79 | ### reset 80 | 81 | ```c++ 82 | //Signature 83 | void reset() 84 | ``` 85 | 86 | Reset the controller so it will start from zero again. 87 | 88 | ### flipDisable 89 | 90 | ```c++ 91 | //Signature 92 | void flipDisable() 93 | ``` 94 | 95 | Change whether the controller is on or off. A controller which is off will output 0. 96 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/pid/nsPid.md: -------------------------------------------------------------------------------- 1 | ## NsPid 2 | 3 | ### Constructor 4 | 5 | ```c++ 6 | //Signature 7 | NsPid(const PidParams& iparams, const VelMathParams& ivelParams, const float iminVel, const float iscale = 0.1) 8 | ``` 9 | 10 | Parameter | Description 11 | ----------|------------ 12 | iparams | `PidParams` to make the internal PID controller 13 | ivelParams | `VelMathParams` for the velocity calculations 14 | iminVel | Minimum velocity at which the controller will start reducing the output power 15 | iscale | Scale to reduce the output power by 16 | 17 | ### step 18 | 19 | ```c++ 20 | //Signature 21 | virtual float step(const float inewReading) override 22 | ``` 23 | 24 | Do one iteration of Pid math to compute a new motor power. This needs to be called every so many milliseconds (15 ms works fine). 25 | 26 | Calls `step` from class `Pid`, and may return a reduced power if the velocity of the process is sufficiently low. The purpose of a low power mode is to prevent motors from stalling once they have reached their target (or if they can't quite reach their target). 27 | 28 | Parameter | Description 29 | ----------|------------ 30 | inewReading | New sensor reading 31 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/pid/pid.md: -------------------------------------------------------------------------------- 1 | ## Pid 2 | 3 | The `Pid` class implements the Pid algorithm, with some quality-of-life changes to support online tuning. Inherits from `ControlObject`. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | Pid(const float ikP, const float ikI, const float ikD, const float ikBias = 0) 10 | Pid(const PidParams& params) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | ikP | Proportional gain 16 | ikI | Integral gain 17 | ikD | Derivative gain 18 | ikBias | Controller bias (this value added to output, default 0) 19 | params | `PidParams` 20 | 21 | ### step 22 | 23 | ```c++ 24 | //Signature 25 | virtual float step(const float inewReading) override 26 | ``` 27 | 28 | Do one iteration of Pid math to compute a new motor power. This needs to be called every so many milliseconds (15 ms works fine). 29 | 30 | Parameter | Description 31 | ----------|------------ 32 | inewReading | New sensor reading 33 | 34 | ### setTarget 35 | 36 | ```c++ 37 | //Signature 38 | void setTarget(const float itarget) override 39 | ``` 40 | 41 | Set the target value. 42 | 43 | Parameter | Description 44 | ----------|------------ 45 | itarget | New target value 46 | 47 | ### getOutput 48 | 49 | ```c++ 50 | //Signature 51 | float getOutput() const 52 | ``` 53 | 54 | Return the most recent controller output. 55 | 56 | ### getError 57 | 58 | ```c++ 59 | //Signature 60 | virtual float getError() const = 0 61 | ``` 62 | 63 | Return the most recent controller error. 64 | 65 | ### setGains 66 | 67 | ```c++ 68 | //Signature 69 | void setGains(const float ikP, const float ikI, const float ikD, const float ikBias = 0) 70 | ``` 71 | 72 | Set new controller gains and bias. 73 | 74 | Parameter | Description 75 | ----------|------------ 76 | ikP | Proportional gain 77 | ikI | Integral gain 78 | ikD | Derivative gain 79 | ikBias | Controller bias (this value added to output, default 0) 80 | 81 | ### setSampleTime 82 | 83 | ```c++ 84 | //Signature 85 | void setSampleTime(const int isampleTime) override 86 | ``` 87 | 88 | Set the timestep (in ms) between calls to `step`. 89 | 90 | Parameter | Description 91 | ----------|------------ 92 | isampleTime | Timestep between calls to `step` in ms 93 | 94 | ### setOutputLimits 95 | 96 | ```c++ 97 | //Signature 98 | void setOutputLimits(float imax, float imin) override 99 | ``` 100 | 101 | Set the max and min value for the controller output. 102 | 103 | Parameter | Description 104 | ----------|------------ 105 | imax | Max output 106 | imin | Min output 107 | 108 | ### setIntegralLimits 109 | 110 | ```c++ 111 | //Signature 112 | void setIntegralLimits(float imax, float imin) 113 | ``` 114 | 115 | Set the max and min value for the integrator sum. 116 | 117 | Parameter | Description 118 | ----------|------------ 119 | imax | Max integrator value 120 | imin | Min integrator value 121 | 122 | ### reset 123 | 124 | ```c++ 125 | //Signature 126 | void reset() override 127 | ``` 128 | 129 | Reset the controller so it will start from zero again. 130 | 131 | ### setIntegratorReset 132 | 133 | ```c++ 134 | //Signature 135 | void setIntegratorReset(bool iresetOnZero) 136 | ``` 137 | 138 | Set whether the integrator should be cleared when the controller's error is zero or changes sign. 139 | 140 | 141 | Parameter | Description 142 | ----------|------------ 143 | iresetOnZero | Whether the integrator should be cleared when the controller's error is zero or changes sign 144 | 145 | ### flipDisable 146 | 147 | ```c++ 148 | //Signature 149 | void flipDisable() override 150 | ``` 151 | 152 | Change whether the controller is on or off. A controller which is off will output 0. 153 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/pid/pidParams.md: -------------------------------------------------------------------------------- 1 | ## PidParams 2 | 3 | The `PidParams` class encapsulates the parameters a `Pid` takes. 4 | 5 | Parameter | Description 6 | ----------|------------ 7 | kP | Proportional gain 8 | kI | Integral gain 9 | kD | Derivative gain 10 | kBias | Controller bias (this value added to output) 11 | 12 | ### Constructor 13 | 14 | ```c++ 15 | //Signature 16 | PidParams(const float ikP, const float ikI, const float ikD, const float ikBias = 0) 17 | ``` 18 | 19 | Parameter | Description 20 | ----------|------------ 21 | ikP | Proportional gain 22 | ikI | Integral gain 23 | ikD | Derivative gain 24 | ikBias | Controller bias (this value added to output, default 0) 25 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/pid/velPid.md: -------------------------------------------------------------------------------- 1 | ## VelPid 2 | 3 | The `VelPid` class implements the Pid algorithm for the velocity domain, with some quality-of-life changes to support online tuning. Inherits from `ControlObject`. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | VelPid(const float ikP, const float ikD) 10 | VelPid(const VelPidParams& params) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | ikP | Proportional gain 16 | ikI | Integral gain 17 | ikD | Derivative gain 18 | ikBias | Controller bias (this value added to output, default 0) 19 | params | `VelPidParams` 20 | 21 | ### stepVel 22 | 23 | ```c++ 24 | //Signature 25 | virtual float stepVel(const float inewReading) 26 | ``` 27 | 28 | Do one iteration of velocity math to compute a new filtered velocity. This is only meant to be used separately from `step` if you only want to compute a new velocity. Don't call `stepVel` if you are already calling `step` because `step` will call `stepVel` on its own. 29 | 30 | Parameter | Description 31 | ----------|------------ 32 | inewReading | New sensor reading 33 | 34 | ### step 35 | 36 | ```c++ 37 | //Signature 38 | virtual float step(const float inewReading) 39 | ``` 40 | 41 | Do one iteration of Pid math to compute a new motor power. This needs to be called every so many milliseconds (15 ms works fine). 42 | 43 | Parameter | Description 44 | ----------|------------ 45 | inewReading | New sensor reading 46 | 47 | ### setTarget 48 | 49 | ```c++ 50 | //Signature 51 | void setTarget(const float itarget) 52 | ``` 53 | 54 | Set the target value. 55 | 56 | Parameter | Description 57 | ----------|------------ 58 | itarget | New target value 59 | 60 | ### getOutput 61 | 62 | ```c++ 63 | //Signature 64 | float getOutput() const 65 | ``` 66 | 67 | Return the most recent controller output. 68 | 69 | ### getError 70 | 71 | ```c++ 72 | //Signature 73 | virtual float getError() const = 0 74 | ``` 75 | 76 | Return the most recent controller error. 77 | 78 | ### setSampleTime 79 | 80 | ```c++ 81 | //Signature 82 | void setSampleTime(const int isampleTime) 83 | ``` 84 | 85 | Set the timestep (in ms) between calls to `step`. 86 | 87 | Parameter | Description 88 | ----------|------------ 89 | isampleTime | Timestep between calls to `step` in ms 90 | 91 | ### setOutputLimits 92 | 93 | ```c++ 94 | //Signature 95 | void setOutputLimits(float imax, float imin) 96 | ``` 97 | 98 | Set the max and min value for the controller output. 99 | 100 | Parameter | Description 101 | ----------|------------ 102 | imax | Max output 103 | imin | Min output 104 | 105 | ### reset 106 | 107 | ```c++ 108 | //Signature 109 | void reset() 110 | ``` 111 | 112 | Reset the controller so it will start from zero again. 113 | 114 | ### flipDisable 115 | 116 | ```c++ 117 | //Signature 118 | void flipDisable() 119 | ``` 120 | 121 | Change whether the controller is on or off. A controller which is off will output 0. 122 | 123 | ### setGains 124 | 125 | ```c++ 126 | //Signature 127 | void setGains(const float ikP, const float ikD) 128 | ``` 129 | 130 | Set new controller gains and bias. 131 | 132 | Parameter | Description 133 | ----------|------------ 134 | ikP | Proportional gain 135 | ikD | Derivative gain 136 | 137 | ### setFilterGains 138 | 139 | ```c++ 140 | //Signature 141 | void setFilterGains(const float alpha, const float beta) 142 | ``` 143 | 144 | Set new gains for the `DemaFilter` 145 | 146 | Parameter | Description 147 | ----------|------------ 148 | alpha | Alpha gain 149 | beta | Beta gain 150 | 151 | ### setTicksPerRev 152 | 153 | ```c++ 154 | //Signature 155 | void setTicksPerRev(const float tpr) 156 | ``` 157 | 158 | Set the number of measurement units per revolution. Default is 360 (quadrature encoder). 159 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/pid/velPidParams.md: -------------------------------------------------------------------------------- 1 | ## VelPidParams 2 | 3 | The `VelPidParams` class encapsulates the parameters a `VelPid` takes. 4 | 5 | Parameter | Description 6 | ----------|------------ 7 | kP | Proportional gain 8 | kD | Derivative gain 9 | 10 | ### Constructor 11 | 12 | ```c++ 13 | //Signature 14 | VelPidParams(const float ikP, const float ikD) 15 | ``` 16 | 17 | Parameter | Description 18 | ----------|------------ 19 | ikP | Proportional gain 20 | ikD | Derivative gain 21 | -------------------------------------------------------------------------------- /docs-dev/content/api/control/velMath.md: -------------------------------------------------------------------------------- 1 | ## VelMath 2 | 3 | ### Constructor 4 | 5 | ```c++ 6 | //Signature 7 | VelMath(const float iticksPerRev, const float ialpha = 0.19, const float ibeta = 0.041) 8 | VelMath(const VelMathParams& iparams) 9 | ``` 10 | 11 | Parameter | Description 12 | ----------|------------ 13 | iticksPerRev | Encoder ticks per one revolution 14 | ialpha | `DemaFilter` alpha gain 15 | ibeta | `DemaFilter` beta gain 16 | 17 | ### step 18 | 19 | ```c++ 20 | //Signature 21 | float step(const float inewPos) 22 | ``` 23 | 24 | Calculate, filter, and return a new velocity. This need to be called every so many milliseconds (not any faster than 15 ms). 25 | 26 | ### setGains 27 | 28 | ```c++ 29 | //Signature 30 | void setGains(const float ialpha, const float ibeta) 31 | ``` 32 | 33 | Set new filter gains. 34 | 35 | Parameter | Description 36 | ----------|------------ 37 | ialpha | Alpha gain 38 | ibeta | Beta gain 39 | 40 | ### setTicksPerRev 41 | 42 | 43 | ```c++ 44 | //Signature 45 | void setTicksPerRev(const float iTPR) 46 | ``` 47 | 48 | Set a new ticks per rev value. 49 | 50 | Parameter | Description 51 | ----------|------------ 52 | iTPR | Encoder ticks per one revolution 53 | 54 | ### getOutput 55 | 56 | ```c++ 57 | //Signature 58 | float getOutput() const 59 | ``` 60 | 61 | Return the most recent velocity. 62 | 63 | ### getDiff 64 | 65 | ```c++ 66 | //Signature 67 | float getDiff() const 68 | ``` 69 | 70 | Return the difference between the last and second to last velocity. Dividing this value by the sample time would give an acceleration. 71 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/button.md: -------------------------------------------------------------------------------- 1 | ## Button 2 | 3 | The `Button` class is a sample wrapper around a digital input port that represents a button. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | explicit constexpr Button() 10 | explicit constexpr Button(const unsigned char iport, const bool iinverted = false) 11 | explicit constexpr Button(const unsigned char ijoystick, const unsigned char ibuttonGroup, const unsigned char ibutton, const bool iinverted = false) 12 | explicit constexpr Button(PROS_FILE* ilcdPort, const unsigned char ilcdButton, const bool iinverted = false) 13 | ``` 14 | 15 | Button or limit switch constructor: 16 | 17 | Parameter | Description 18 | ----------|------------ 19 | iport | Digital port 20 | iinverted | Whether the button is inverted (default open vs. default closed) 21 | 22 | Joystick button constructor: 23 | 24 | Parameter | Description 25 | ----------|------------ 26 | ijoystick | Joystick number (primary (1) or partner (2)) 27 | ibuttonGroup | Joystick button group 28 | ibutton | Button in button group 29 | iinverted | Whether the button is inverted (default open vs. default closed) 30 | 31 | LCD button constructor: 32 | 33 | Parameter | Description 34 | ----------|------------ 35 | ilcdPort | LCD port (uart1 or uart2) 36 | ilcdbutton | LCD button mask 37 | iinverted | Whether the button is inverted (default open vs. default closed) 38 | 39 | This class also has literals available: 40 | 41 | Literal | Button Value 42 | --------|------------- 43 | `n_b` | `Button(n, false)` 44 | `n_ib` | `Button(n, true)` 45 | 46 | ### isPressed 47 | 48 | ```c++ 49 | //Signature 50 | bool isPressed() const 51 | ``` 52 | 53 | Return whether this button is pressed or not. This takes into account whether the button is inverted or not. 54 | 55 | ### edge 56 | 57 | ```c++ 58 | //Signature 59 | bool edge() 60 | ``` 61 | 62 | Return `true` if a rising or falling edge is detected. This takes into account whether the button is inverted or not. 63 | 64 | ### risingEdge 65 | 66 | ```c++ 67 | //Signature 68 | bool risingEdge() 69 | ``` 70 | 71 | Return `true` if a rising edge is detected. This takes into account whether the button is inverted or not. 72 | 73 | ### fallingEdge 74 | 75 | ```c++ 76 | //Signature 77 | bool fallingEdge() 78 | ``` 79 | 80 | Return `true` if a falling edge is detected. This takes into account whether the button is inverted or not. 81 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/cubicMotor.md: -------------------------------------------------------------------------------- 1 | ## CubicMotor 2 | 3 | The `CubicMotor` class provides a cubic-control based implementation of the `set` function `Motor` defines. This means that the motor power from `set` follows a cubic curve instead of the default identity function. The `setTS` function is not overridden and so provides the same behavior as in `Motor`. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | explicit constexpr CubicMotor(const unsigned char iport, const int *its) 10 | explicit constexpr CubicMotor(const unsigned char iport, const int isign = 1, const int *its = motor::trueSpeed) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | iport | Motor port 16 | isign | `1` for forward, `-1` for reversed 17 | its | TrueSpeed array to linearize the motor controller 18 | 19 | This class also has literals available: 20 | 21 | Literal | Motor Value 22 | --------|------------ 23 | `n_m3` | `CubicMotor(m, 1)` 24 | `n_rm3` | `CubicMotor(m, -1)` 25 | 26 | ### set 27 | 28 | ```c++ 29 | //Signature 30 | virtual void set(const int val) const 31 | ``` 32 | 33 | Set the power of this motor using a cubic function. The exact math for the output of this function is `(val * val * val) / (127 * 127)`. 34 | 35 | Parameter | Description 36 | ----------|------------ 37 | val | Motor power 38 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/cubicSlewMotor.md: -------------------------------------------------------------------------------- 1 | ## CubicSlewMotor 2 | 3 | The `CubicSlewMotor` class adds a slew rate to the `CubicMotor` class. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | CubicSlewMotor(const CubicMotor& imotor, const float islewRate) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | imotor | Motor to slew 15 | islewRate | Slew rate 16 | 17 | ### set 18 | 19 | ```c++ 20 | //Signature 21 | virtual void set(const int val) const 22 | ``` 23 | 24 | Slew the power of this motor up to `val`. 25 | 26 | Parameter | Description 27 | ----------|------------ 28 | val | Target motor power 29 | 30 | ### setTS 31 | 32 | ```c++ 33 | //Signature 34 | virtual void set(const int val) const 35 | ``` 36 | 37 | Slew the power of this motor up to `val` using trueSpeed. 38 | 39 | Parameter | Description 40 | ----------|------------ 41 | val | Target motor power 42 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/ime.md: -------------------------------------------------------------------------------- 1 | ## IME 2 | 3 | The `IME` class is a simple container for an IME. Inherits from `RotarySensor`. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | IME(const unsigned int iindex) 10 | IME(const unsigned int iindex, const bool ireversed) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | iindex | IME index in the chain 16 | ireversed | Whether the IME is reversed or not (clockwise turn increases vs. decreases ticks) 17 | 18 | This class also has literals available: 19 | 20 | Literal | IME Value 21 | --------|------------- 22 | `n_ime` | `IME(n, false)` 23 | `n_rime` | `IME(n, true)` 24 | 25 | ### get 26 | 27 | ```c++ 28 | //Signature 29 | int get() override 30 | ``` 31 | 32 | Return the current tick count. 33 | 34 | ### reset 35 | 36 | ```c++ 37 | //Signature 38 | void reset() override 39 | ``` 40 | 41 | Reset the tick count to zero. 42 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/motor.md: -------------------------------------------------------------------------------- 1 | ## Motor 2 | 3 | The `Motor` class provides a wrapper around the default motor utilities. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | explicit constexpr Motor(const unsigned char iport, const int *its) 10 | explicit constexpr Motor(const unsigned char iport, const int isign = 1, const int *its = motor::trueSpeed) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | iport | Motor port 16 | isign | `1` for forward, `-1` for reversed 17 | its | TrueSpeed array to linearize the motor controller 18 | 19 | This class also has literals available: 20 | 21 | Literal | Motor Value 22 | --------|------------ 23 | `n_m` | `Motor(m, 1)` 24 | `n_rm` | `Motor(m, -1)` 25 | 26 | ### set 27 | 28 | ```c++ 29 | //Signature 30 | virtual void set(const int val) const 31 | ``` 32 | 33 | Set the power of this motor. 34 | 35 | Parameter | Description 36 | ----------|------------ 37 | val | Motor power 38 | 39 | ### setTS 40 | 41 | ```c++ 42 | //Signature 43 | virtual void set(const int val) const 44 | ``` 45 | 46 | Set the power of this motor using trueSpeed. 47 | 48 | Parameter | Description 49 | ----------|------------ 50 | val | Motor power 51 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/potentiometer.md: -------------------------------------------------------------------------------- 1 | ## Potentiometer 2 | 3 | ### Constructor 4 | 5 | ```c++ 6 | //Signature 7 | explicit constexpr Potentiometer() 8 | explicit constexpr Potentiometer(const unsigned char iport) 9 | explicit constexpr Potentiometer(const unsigned char iport, const bool iinverted) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | iport | Analog input port 15 | iinverted | Whether the potentiometer is inverted (range is 0->4095 or 4095->0) 16 | 17 | This class also has literals available: 18 | 19 | Literal | Potentiometer Value 20 | --------|-------------------- 21 | `n_p` | `Potentiometer(n, false)` 22 | `n_ip` | `Potentiometer(n, true)` 23 | 24 | ### get 25 | 26 | ```c++ 27 | //Signature 28 | int get() const 29 | ``` 30 | 31 | Return the value of this potentiometer. 32 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/quadEncoder.md: -------------------------------------------------------------------------------- 1 | ## QuadEncoder 2 | 3 | The `QuadEncoder` class is a simple container for an encoder. Inherits from `RotarySensor`. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | QuadEncoder(const unsigned char iportTop, const unsigned char iportBottom) 10 | QuadEncoder(const unsigned char iportTop, const unsigned char iportBottom, const bool ireversed) 11 | ``` 12 | 13 | Parameter | Description 14 | ----------|------------ 15 | iportTop | Top digital in port 16 | iportBottom | Bottom digital in port 17 | ireversed | Whether the encoder is reversed or not (clockwise turn increases vs. decreases ticks) 18 | 19 | ### get 20 | 21 | ```c++ 22 | //Signature 23 | int get() override 24 | ``` 25 | 26 | Return the current tick count. 27 | 28 | ### reset 29 | 30 | ```c++ 31 | //Signature 32 | void reset() override 33 | ``` 34 | 35 | Reset the tick count to zero. 36 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/rangeFinder.md: -------------------------------------------------------------------------------- 1 | ## RangeFinder 2 | 3 | ### Constructor 4 | 5 | ```c++ 6 | //Signature 7 | RangeFinder(const unsigned char iportTop, const unsigned char iportBottom) 8 | ``` 9 | 10 | Parameter | Description 11 | ----------|------------ 12 | iportTop | Top digital port 13 | iportBottom | Bottom digital port 14 | 15 | ### get 16 | 17 | ```c++ 18 | //Signature 19 | int get() 20 | ``` 21 | 22 | Return the current measured range in centimeters. 23 | 24 | ### getFiltered 25 | 26 | ```c++ 27 | //Signature 28 | int getFiltered() 29 | ``` 30 | 31 | Return the median measured range in centimeters. The median is measured across the previous five measurements. 32 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/rotarySensor.md: -------------------------------------------------------------------------------- 1 | ## RotarySensor (abstract) 2 | 3 | The `RotarySensor` class is a simple container for a sensor which spins indefinitely to measure rotation, like a `QuadEncoder` or an `IME`. 4 | 5 | ### get 6 | 7 | ```c++ 8 | //Signature 9 | virtual int get() = 0 10 | ``` 11 | 12 | Return the current tick count. 13 | 14 | ### reset 15 | 16 | ```c++ 17 | //Signature 18 | virtual void reset() = 0 19 | ``` 20 | 21 | Reset the tick count to zero. 22 | -------------------------------------------------------------------------------- /docs-dev/content/api/device/slewMotor.md: -------------------------------------------------------------------------------- 1 | ## SlewMotor 2 | 3 | The `SlewMotor` class adds a slew rate to the `Motor` class. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | SlewMotor(const Motor& imotor, const float islewRate) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | imotor | Motor to slew 15 | islewRate | Slew rate 16 | 17 | ### set 18 | 19 | ```c++ 20 | //Signature 21 | virtual void set(const int val) const 22 | ``` 23 | 24 | Slew the power of this motor up to `val`. 25 | 26 | Parameter | Description 27 | ----------|------------ 28 | val | Target motor power 29 | 30 | ### setTS 31 | 32 | ```c++ 33 | //Signature 34 | virtual void set(const int val) const 35 | ``` 36 | 37 | Slew the power of this motor up to `val` using trueSpeed. 38 | 39 | Parameter | Description 40 | ----------|------------ 41 | val | Target motor power 42 | -------------------------------------------------------------------------------- /docs-dev/content/api/filter/avgFilter.md: -------------------------------------------------------------------------------- 1 | ## AvgFilter 2 | 3 | The `AvgFilter` class inherits from `Filter` and takes a template parameter `std::size_t n>` (the number of inputs to average). It is a finite impulse response (FIR) filter that averages the last `n` inputs. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | AvgFilter() 10 | ``` 11 | 12 | The constructor does not take any parameters. 13 | -------------------------------------------------------------------------------- /docs-dev/content/api/filter/demaFilter.md: -------------------------------------------------------------------------------- 1 | ## DemaFilter 2 | 3 | The `DemaFilter` class inherits from `Filter`. It is an infinite impulse response (IIR) filter that implements the double exponential moving average algorithm (EMA). This is very similar to the normal EMA, except it can pick up on trends in data and follow the current trend until a new trend starts. This filter performs better than a single EMA when data frequently follows a trend. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | DemaFilter(const float ialpha, const float ibeta) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | ialpha | Alpha gain 15 | ibeta | Beta gain 16 | 17 | ### setGains 18 | 19 | ```c++ 20 | //Signature 21 | void setGains(const float ialpha, const float ibeta) 22 | ``` 23 | 24 | Set new gains for this filter 25 | 26 | Parameter | Description 27 | ----------|------------ 28 | ialpha | New alpha gain 29 | ibeta | New beta gain 30 | -------------------------------------------------------------------------------- /docs-dev/content/api/filter/emaFilter.md: -------------------------------------------------------------------------------- 1 | ## EmaFilter 2 | 3 | The `EmaFilter` class inherits from `Filter`. It is an infinite impulse response (IIR) filter that implements the exponential moving average algorithm (EMA). 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | EmaFilter(const float ialpha, const float ibeta) 10 | ``` 11 | 12 | Parameter | Description 13 | ----------|------------ 14 | ialpha | Alpha gain 15 | ibeta | Beta gain 16 | 17 | ### setGains 18 | 19 | ```c++ 20 | //Signature 21 | void setGains(const float ialpha, const float ibeta) 22 | ``` 23 | 24 | Set new gains for this filter 25 | 26 | Parameter | Description 27 | ----------|------------ 28 | ialpha | New alpha gain 29 | ibeta | New beta gain 30 | -------------------------------------------------------------------------------- /docs-dev/content/api/filter/filter.md: -------------------------------------------------------------------------------- 1 | ## Filter (abstract) 2 | 3 | The `Filter` class is an interface for data filtering. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | Filter() 10 | ``` 11 | 12 | The constructor does not take any parameters. 13 | 14 | ### filter 15 | 16 | ```c++ 17 | //Signature 18 | virtual float filter(const float ireading) = 0; 19 | ``` 20 | 21 | Filter an input and return the filtered output. 22 | 23 | 24 | ### getOutput 25 | 26 | ```c++ 27 | //Signature 28 | virtual float getOutput() const = 0; 29 | ``` 30 | 31 | Return the previous output. 32 | -------------------------------------------------------------------------------- /docs-dev/content/api/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Reference 3 | type: index 4 | --- 5 | 6 | This section is meant to be a quick reference for Okapi's entire API, including methods the user may not normally interact with. This reference is broken into sections, covering one class per section. Subclasses are placed below the base class, but in different sections. If a class is marked (abstract) then it contains one or more pure virtual functions, and cannot be instantiated (it is designed only to be an interface). 7 | 8 | {{< note title="Note" >}} 9 | Remember that derived classes inherit the interface of their base class; therefore, derived classes will not have their base class' functions documented (you can safely assume that all functions from the base class are implemented). 10 | {{< /note >}} 11 | 12 | {{< readfile file="content/api/filter/avgFilter.md" markdown="true" >}} 13 | {{< readfile file="content/api/device/button.md" markdown="true" >}} 14 | {{< readfile file="content/api/chassisController/chassisController.md" markdown="true" >}} 15 | {{< warning title="Careful" >}} 16 | Most users should not call this constructor with a std::shared_ptr<ChassisModel>. Instead, pass a ChassisModelParams and Okapi will figure out what to do. 17 | {{< /warning >}} 18 | {{< readfile file="content/api/chassisController/chassisControllerPID.md" markdown="true" >}} 19 | {{< warning title="Careful" >}} 20 | Most users should not call this constructor with a std::shared_ptr<ChassisModel>. Instead, pass a ChassisModelParams and Okapi will figure out what to do. 21 | {{< /warning >}} 22 | {{< readfile file="content/api/chassisModel/chassisModel.md" markdown="true" >}} 23 | {{< readfile file="content/api/chassisModel/chassisModelParams.md" markdown="true" >}} 24 | {{< readfile file="content/api/control/controlObject.md" markdown="true" >}} 25 | {{< readfile file="content/api/device/cubicMotor.md" markdown="true" >}} 26 | {{< readfile file="content/api/device/cubicSlewMotor.md" markdown="true" >}} 27 | {{< readfile file="content/api/filter/demaFilter.md" markdown="true" >}} 28 | {{< readfile file="content/api/odometry/distanceAndAngle.md" markdown="true" >}} 29 | {{< readfile file="content/api/filter/emaFilter.md" markdown="true" >}} 30 | {{< readfile file="content/api/filter/filter.md" markdown="true" >}} 31 | {{< readfile file="content/api/control/genericController.md" markdown="true" >}} 32 | {{< readfile file="content/api/device/ime.md" markdown="true" >}} 33 | {{< readfile file="content/api/util/mathUtil.md" markdown="true" >}} 34 | {{< readfile file="content/api/device/motor.md" markdown="true" >}} 35 | {{< readfile file="content/api/control/pid/nsPid.md" markdown="true" >}} 36 | {{< readfile file="content/api/chassisController/odomChassisController/odomChassisController.md" markdown="true" >}} 37 | {{< readfile file="content/api/chassisController/odomChassisController/odomChassisControllerPID.md" markdown="true" >}} 38 | {{< readfile file="content/api/odometry/odometry.md" markdown="true" >}} 39 | {{< readfile file="content/api/odometry/odomMath.md" markdown="true" >}} 40 | {{< readfile file="content/api/control/pid/pid.md" markdown="true" >}} 41 | {{< readfile file="content/api/control/pid/pidParams.md" markdown="true" >}} 42 | {{< readfile file="content/api/device/potentiometer.md" markdown="true" >}} 43 | {{< readfile file="content/api/device/quadEncoder.md" markdown="true" >}} 44 | {{< readfile file="content/api/device/rangeFinder.md" markdown="true" >}} 45 | {{< readfile file="content/api/device/rotarySensor.md" markdown="true" >}} 46 | {{< readfile file="content/api/chassisModel/skidSteerModel/skidSteerModel.md" markdown="true" >}} 47 | {{< readfile file="content/api/chassisModel/skidSteerModel/skidSteerModelParams.md" markdown="true" >}} 48 | {{< readfile file="content/api/device/slewMotor.md" markdown="true" >}} 49 | {{< readfile file="content/api/util/timer.md" markdown="true" >}} 50 | {{< readfile file="content/api/control/velMath.md" markdown="true" >}} 51 | {{< readfile file="content/api/control/pid/velPid.md" markdown="true" >}} 52 | {{< readfile file="content/api/control/pid/velPidParams.md" markdown="true" >}} 53 | {{< readfile file="content/api/chassisModel/xDriveModel/xDriveModel.md" markdown="true" >}} 54 | {{< readfile file="content/api/chassisModel/xDriveModel/xDriveModelParams.md" markdown="true" >}} 55 | -------------------------------------------------------------------------------- /docs-dev/content/api/odometry/distanceAndAngle.md: -------------------------------------------------------------------------------- 1 | ## DistanceAndAngle 2 | 3 | The `DistanceAndAngle` class is a simple container for the two parameters returned by `OdomMath::computeDistanceAndAngleToPoint`. 4 | 5 | Member | Description 6 | -------|------------ 7 | length | Distance to point 8 | theta | Angle to point 9 | 10 | ### Constructor 11 | 12 | ```c++ 13 | //Signature 14 | DistanceAndAngle(const float ilength, const float itheta) 15 | DistanceAndAngle() 16 | ``` 17 | 18 | Parameter | Description 19 | ----------|------------ 20 | ilength | Distance to point 21 | itheta | Angle to point 22 | -------------------------------------------------------------------------------- /docs-dev/content/api/odometry/odomMath.md: -------------------------------------------------------------------------------- 1 | ## OdomMath 2 | 3 | The `OdomMath` class provides static implementations for common odometry operations. 4 | 5 | ### computeDistanceToPoint 6 | 7 | ```c++ 8 | //Signature 9 | static float computeDistanceToPoint(const float ix, const float iy, const OdomState& istate) 10 | ``` 11 | 12 | Calculate the distance from the robot to a point, (`ix`, `iy`). 13 | 14 | Parameter | Description 15 | ----------|------------ 16 | ix | X coordinate 17 | iy | Y coordinate 18 | istate | Odometry state 19 | 20 | ### computeAngleToPoint 21 | 22 | ```c++ 23 | //Signature 24 | static float computeAngleToPoint(const float ix, const float iy, const OdomState& istate) 25 | ``` 26 | 27 | Calculate the angle from the robot to a point, (`ix`, `iy`). 28 | 29 | Parameter | Description 30 | ----------|------------ 31 | ix | X coordinate 32 | iy | Y coordinate 33 | istate | Odometry state 34 | 35 | ### computeDistanceAndAngleToPoint 36 | 37 | ```c++ 38 | //Signature 39 | static DistanceAndAngle computeDistanceAndAngleToPoint(const float ix, const float iy, const OdomState& istate) 40 | ``` 41 | 42 | Calculate the distance and the angle from the robot to a point, (`ix`, `iy`). 43 | 44 | Parameter | Description 45 | ----------|------------ 46 | ix | X coordinate 47 | iy | Y coordinate 48 | istate | Odometry state 49 | -------------------------------------------------------------------------------- /docs-dev/content/api/odometry/odometry.md: -------------------------------------------------------------------------------- 1 | ## Odometry 2 | 3 | The `Odometry` class tracks the robot as it moves, computing its position in the field frame. It is a singleton so its main method, `step`, can be called in a task. 4 | 5 | ### setParams 6 | 7 | ```c++ 8 | //Signature 9 | static void setParams(OdomParams& iparams) 10 | ``` 11 | 12 | Set the model, scale, and turnScale parameters. 13 | 14 | Parameter | Description 15 | ----------|------------ 16 | iparams | `OdomParams` 17 | 18 | ### setScales 19 | 20 | ```c++ 21 | //Signature 22 | static void setScales(const float iscale, const float iturnScale) 23 | ``` 24 | 25 | Set the scale and turnScale parameters. 26 | 27 | Parameter | Description 28 | ----------|------------ 29 | iscale | Driving scale (encoder ticks to mm) 30 | iturnScale | Turning scale (encoder ticks to degrees) 31 | 32 | ### guessScales 33 | 34 | ```c++ 35 | //Signature 36 | static void guessScales(const float chassisDiam, const float wheelDiam, const float ticksPerRev = 360.0) 37 | ``` 38 | 39 | Attempt to guess the two odometry scales from chassis and wheel diameter. This might get you close, but it serves only as a quick and temporary fix. The two odometry scales must be found experimentally for your specific robot. 40 | 41 | Parameter | Description 42 | ----------|------------ 43 | chassisDiam | Center-to-center wheel base in inches 44 | wheelDiam | Edge-to-edge wheel diameter in inches 45 | ticksPerRev | Quadrate encoder ticks per one wheel revolution (default 360) 46 | 47 | ### step 48 | 49 | ```c++ 50 | //Signature 51 | static OdomState step() 52 | ``` 53 | 54 | Do one iteration of odometry math to compute the new position of the robot. This needs to be called every so many milliseconds (15 ms seems to work fine). 55 | 56 | ### getState 57 | 58 | ```c++ 59 | //Signature 60 | static OdomState getState() 61 | ``` 62 | 63 | Return the last calculated position of the robot. 64 | 65 | ## OdomParams 66 | 67 | The `OdomParams` class encapsulates the parameters an `Odometry` takes. 68 | 69 | Member | Description 70 | -------|------------ 71 | model | `ChassisModel` 72 | scale | Driving scale (encoder ticks to mm) 73 | turnScale | Turning scale (encoder ticks to degrees) 74 | 75 | ### Constructor 76 | 77 | ```c++ 78 | //Signature 79 | OdomParams(const ChassisModelParams& iparams, const float iscale, const float iturnScale) 80 | ``` 81 | 82 | Parameter | Description 83 | ----------|------------ 84 | iparams | `ChassisModelParams` (used to make a new `ChassisModel`) 85 | iscale | Driving scale (encoder ticks to mm) 86 | iturnScale | Turning scale (encoder ticks to degrees) 87 | 88 | ## OdomState 89 | 90 | The `OdomState` class is a simple container for the position of the robot tracked by `Odometry`. 91 | 92 | Member | Description 93 | -------|------------ 94 | x | X coordinate of robot 95 | y | Y coordinate of robot 96 | theta | Theta of robot 97 | 98 | ### Constructor 99 | 100 | ```c++ 101 | //Signature 102 | OdomState(const float ix, const float iy, const float itheta) 103 | OdomState() 104 | ``` 105 | 106 | Parameter | Description 107 | ----------|------------ 108 | ix | X coordinate of robot 109 | iy | Y coordinate of robot 110 | itheta | Theta of robot 111 | -------------------------------------------------------------------------------- /docs-dev/content/api/util/mathUtil.md: -------------------------------------------------------------------------------- 1 | ## MathUtil 2 | 3 | The `MathUtil` class provides `static constexpr` definitions for commonly used numbers, measurements, and conversion rates. 4 | 5 | Name | Value | Description 6 | -----|-------|------------ 7 | analogInToV | 286.0 | Converts an analog reading to a battery voltage measurement in Volts. 8 | inchToMM | 25.4 | Converts one inch to millimeters. 9 | degreeToRadian | 0.01745 | Converts one degree to radians. 10 | radianToDegree | 57.2958 | Converts one radian to degrees. 11 | imeHighTorTPR | 627.2 | The number of ticks an IME returns for one revolution of a 369 motor with high torque gearing. 12 | imeHighStrTPR | 392.0 | The number of ticks an IME returns for one revolution of a 369 motor with high speed gearing. 13 | imeTurboTPR | 261.333 | The number of ticks an IME returns for one revolution of a 369 motor with turbo gearing. 14 | ime269TPR | 240.448 | The number of ticks an IME returns for one revolution of a 269 motor. 15 | quadEncoderTPR | 360.0 | The number of ticks a quadrature encoder returns per revolution. 16 | pi | 3.14159265358979323846 | The value of pi from GCC's math header (redefined here for convenience) 17 | -------------------------------------------------------------------------------- /docs-dev/content/api/util/timer.md: -------------------------------------------------------------------------------- 1 | ## Timer 2 | 3 | The `Timer` class has timing-related utilities to make measuring time differences and writing non-blocking code in loops easier. 4 | 5 | ### Constructor 6 | 7 | ```c++ 8 | //Signature 9 | Timer() 10 | ``` 11 | 12 | The constructor does not take any parameters. 13 | 14 | ### getDt 15 | 16 | ```c++ 17 | //Signature 18 | unsigned long getDt() 19 | ``` 20 | 21 | Return the time passed in ms since the last time this function was called. 22 | 23 | ### getStartingTime 24 | 25 | ```c++ 26 | //Signature 27 | unsigned long getStartingTime() const 28 | ``` 29 | 30 | Return the time in ms the timer was constructed. 31 | 32 | ### getDtFromStart 33 | 34 | ```c++ 35 | //Signature 36 | unsigned long getDtFromStart() const 37 | ``` 38 | 39 | Return the time passed in ms since the timer was constructed. 40 | 41 | ### placeMark 42 | 43 | ```c++ 44 | //Signature 45 | void placeMark() 46 | ``` 47 | 48 | Place a time marker. Placing another marker will overwrite the previous one. 49 | 50 | ### placeHardMark 51 | 52 | ```c++ 53 | //Signature 54 | void placeHardMark() 55 | ``` 56 | 57 | Place a hard time marker. Placing another hard marker will not overwrite the previous one; instead, `clearHardMark()` must be called before another can be placed. 58 | 59 | ### clearHardMark 60 | 61 | ```c++ 62 | //Signature 63 | unsigned long clearHardMark() 64 | ``` 65 | 66 | Clear and return the current hard marker. 67 | 68 | ### getDtFromMark 69 | 70 | ```c++ 71 | //Signature 72 | unsigned long getDtFromMark() 73 | ``` 74 | 75 | Return the time in ms since the marker was placed. 76 | 77 | ### getDtFromHardMark 78 | 79 | ```c++ 80 | //Signature 81 | unsigned long getDtFromHardMark() 82 | ``` 83 | 84 | Return the time in ms since the hard marker was placed. 85 | 86 | ### repeat 87 | 88 | ```c++ 89 | //Signature 90 | bool repeat(unsigned long ms) 91 | ``` 92 | 93 | Return true when the input time period `ms` has passed, and then reset. Meant to be used in loops to execute a block of code every so many ms without blocking the loop. 94 | 95 | Parameter | Description 96 | ----------|------------ 97 | ms | Number of milliseconds between calls of `repeat` that return true 98 | -------------------------------------------------------------------------------- /docs-dev/content/home/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Okapi Documentation 3 | type: index 4 | weight: 0 5 | --- 6 | 7 | ## Primary Objective 8 | 9 | Welcome to Okapi! This library is designed to make modeling and programming complex robot behavior easy, efficient, and maintainable. This library is targeted at PROS users looking to take their competition robot to the next level, whether that means starting to use motion profiles instead of PID or designing an autonomous robot from the ground up. Okapi also comes with an optional cross-platform client that lets you interact with your robot in real time as a graphical interface to Okapi's modules. 10 | 11 | This is the documentation website for both Okapi's PROS library and optional client. 12 | 13 | ## Target Audience 14 | 15 | Okapi is targeted at users of PROS that are familiar with C++ programming. If you are not comfortable with PROS, there are tutorials on the [PROS website](https://pros.cs.purdue.edu), and those still learning C++ should look towards [tutorialspoint](https://www.tutorialspoint.com/cplusplus/) and [Washington University](http://www.cs.wustl.edu/~schmidt/C++/). 16 | -------------------------------------------------------------------------------- /docs-dev/content/images/okapi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs-dev/content/images/okapi.jpg -------------------------------------------------------------------------------- /docs-dev/content/images/skillsRobotPicture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs-dev/content/images/skillsRobotPicture.jpg -------------------------------------------------------------------------------- /docs-dev/content/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Okapi Documentation 3 | type: page 4 | weight: 0 5 | --- 6 | 7 | ## Primary Objective 8 | 9 | Welcome to Okapi! This library is designed to make modeling and programming complex robot behavior easy, efficient, and maintainable. This library is targeted at PROS users looking to take their competition robot to the next level, whether that means starting to use motion profiles instead of PID or designing an autonomous robot from the ground up. Okapi also comes with an optional cross-platform client that lets you interact with your robot in real time as a graphical interface to Okapi's modules. 10 | 11 | This is the documentation website for both Okapi's PROS library and optional client. 12 | 13 | ## Target Audience 14 | 15 | Okapi is targeted at users of PROS that are familiar with C++ programming. If you are not comfortable with PROS, there are tutorials on the [PROS website](https://pros.cs.purdue.edu), and those still learning C++ should look towards [tutorialspoint](https://www.tutorialspoint.com/cplusplus/) and [Washington University](http://www.cs.wustl.edu/~schmidt/C++/). 16 | -------------------------------------------------------------------------------- /docs-dev/content/tutorials/buttonTutorial.md: -------------------------------------------------------------------------------- 1 | ## Buttons 2 | 3 | The Vex EDR system has three kinds of buttons in it: push buttons & limit switches, joystick buttons, and LCD module buttons. Okapi provides a class to interact with all three. 4 | 5 | Say you have a button on your robot you want to use to control something. This is the simplest use, so Okapi makes this easy: 6 | 7 | ```c++ 8 | #include 9 | 10 | Button foo = 1_b; //literal for Button(1, false) 11 | ``` 12 | 13 | `foo` is now a non-inverted button in digital port 1. For reference, an inverted button returns true when it isn't pressed, and false when it is (opposite of a normal button). 14 | 15 | Now that we have our button, we can check various things: 16 | 17 | ```c++ 18 | foo.isPressed(); //Returns true when the button is pressed (or false when pressed if inverted) 19 | foo.edge(); //Returns true when the button changes from pressed to not pressed, or vice versa 20 | foo.risingEdge(); //Returns true when the button changes from not pressed to pressed 21 | foo.fallingEdge(); //Returns true when the button changes from pressed to not pressed 22 | ``` 23 | 24 | For example, say we wanted to do something whenever the button was pressed inside of our control loop: 25 | 26 | ```c++ 27 | while (1) { //Placeholder for the actual control loop 28 | //Trigger whenever we press the button (but not when we release it) 29 | if (foo.risingEdge()) { 30 | doSomething(); 31 | } 32 | 33 | //Trigger whenever we release the button (but not when we press it) 34 | if (foo.fallingEdge()) { 35 | doSomethingElse(); 36 | } 37 | } 38 | ``` 39 | 40 | We use all the same exact code with the other two kinds of buttons, joystick & LCD: 41 | 42 | ```c++ 43 | Button foo(1, 8, JOY_DOWN); //Joystic button for the bottom of the right d-pad 44 | Button foo(uart1, LCD_BTN_CENTER); //LCD center button in port uart1 45 | ``` 46 | -------------------------------------------------------------------------------- /docs-dev/content/tutorials/chassisControllerTutorial.md: -------------------------------------------------------------------------------- 1 | ## Chassis Controller 2 | 3 | Okapi provides a way to control a `ChassisModel` using closed-loop control, like PID, so you don't have to rewrite a driveStraight() function every year. Rather than making a model directly, we can instead give `ChassisModelParams` to a `ChassisController`, which will instantiate the model for itself: 4 | 5 | ```c++ 6 | #include 7 | ChassisControllerPid controller(SkidSteerModelParams<2>({2_m, 3_m, 4_m, 5_m}, //Skid steer chassis with two motors per side 8 | QuadEncoder(1, 2, true), //Left encoder (reversed) 9 | QuadEncoder(3, 4)), //Right encoder 10 | PidParams(0.15, 0.05, 0.07), //Distance PID controller 11 | PidParams(0.02, 0.01, 0)); //Angle PID controller 12 | ``` 13 | 14 | A `ChassisControllerPid` implements the `ChassisController` interface using PID control. It takes two `PidParams` to describe the controller gains for both controllers. The first controls distance to the target, but the second keeps the robot on a straight path while it drives to its target. Often times the second controller's gains will have lower kP, lower or no kD, and moderate kI because this controller just needs to make slight adjustments to the power the motors on each side of the chassis get. 15 | 16 | Once we have our controller, we can control the robot more accurately than with just a model: 17 | 18 | ```c++ 19 | controller.driveStraight(100); //Drive in a straight line for 100 encoder ticks 20 | controller.pointTurn(100); //Turn clockwise in place for 100 encoder ticks 21 | ``` 22 | -------------------------------------------------------------------------------- /docs-dev/content/tutorials/chassisModelTutorial.md: -------------------------------------------------------------------------------- 1 | ## Chassis Model 2 | 3 | Okapi has a way to represent the most common robot chassis, skid steer and x-drive. With this model we can tell the robot how to move around in a general sense. 4 | 5 | For example, a skid steer chassis with two motors per side and two quad encoders: 6 | 7 | ```c++ 8 | #include 9 | 10 | SkidSteerModel<2> model({2_m, 3_m, 4_m, 5_m}, //Left motors: 2 & 3, right motors: 4 & 5 11 | QuadEncoder(1, 2, true), //Left encoder (reversed) 12 | QuadEncoder(3, 4)); //Right encoder 13 | ``` 14 | 15 | Or you can have an x-drive with one motor per corner and two quad encoders: 16 | 17 | ```c++ 18 | #include 19 | 20 | XDriveModel<1> model({2_m, 3_m, 4_m, 5_m}, //Motors are ordered counter-clockwise from the top left 21 | QuadEncoder(1, 2, true), //Top left encoder (reversed) 22 | QuadEncoder(3, 4)); //Top right encoder 23 | ``` 24 | 25 | Then once we have a model, we can do everything a generic `ChassisModel` can do: 26 | 27 | ```c++ 28 | model.driveForward(100); //Drive forward at 100 power 29 | model.turnClockwise(90); //Turn clockwise at 90 power 30 | model.tank(joystickGetAnalog(1, 4), joystickGetAnalog(1, 3)); //Tank drive on the vertical channels 31 | model.stop(); //Set all motors to 0 32 | ``` 33 | 34 | If we wanted to use some sort of closed-loop control, we could either do it ourselves or use one of Okapi's structures instead, covered in the `ChassisController` or `OdomChassisController` tutorials. 35 | -------------------------------------------------------------------------------- /docs-dev/content/tutorials/genContTutorial.md: -------------------------------------------------------------------------------- 1 | ## Generic Controller 2 | 3 | Often times, you have a closed-loop controller, sensor, and a few motors acting together as a system, and you wind up with code that powers each motor individually like this: 4 | 5 | ```c++ 6 | #include 7 | 8 | int port1 = 1, port2 = 2; //Motor ports 9 | int pot = 1; //Potentiometer 10 | Pid controller(1, 0.2, 0.3); //PID controller with kP = 1, kI = 0.2, kD = 0.3 11 | controller.setTarget(1500); //Set the target to 1500 on the potentiometer 12 | 13 | while (1) { 14 | controller.step(analogRead(pot)); //Loop the controller with the new pot reading 15 | //Power the motors with the output of the controller 16 | motorSet(port1, controller.getOutput()); 17 | motorSet(port2, controller.getOutput()); 18 | taskDelay(15); 19 | ``` 20 | 21 | The more motors and control structure we have, the messier this becomes. So instead, Okapi provides a way to do this in a cleaner fashion: 22 | 23 | ```c++ 24 | #include 25 | #include 26 | 27 | int pot = 1; 28 | //Two motors in ports 1 and 2 like before 29 | //Use make_shared to give GenericController the instance of your ControlObject 30 | GenericController<2> liftController({1_m, 2_m}, std::make_shared(Pid(1, 0.2, 0.3))); 31 | liftController.setTarget(1500); 32 | 33 | while (1) { 34 | controller.step(analogRead(pot)); //Loop the controller and power the motors 35 | taskDelay(15); 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /docs-dev/content/tutorials/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tutorials 3 | type: index 4 | --- 5 | 6 | ## Tutorials 7 | 8 | This section contains various tutorials for the different parts of OkapiLib. Scroll down or view the menus on the left to pick a tutorial. 9 | 10 | {{< readfile file="content/tutorials/motorTutorial.md" markdown="true" >}} 11 | {{< readfile file="content/tutorials/buttonTutorial.md" markdown="true" >}} 12 | {{< readfile file="content/tutorials/pidTutorial.md" markdown="true" >}} 13 | {{< readfile file="content/tutorials/genContTutorial.md" markdown="true" >}} 14 | {{< readfile file="content/tutorials/chassisModelTutorial.md" markdown="true" >}} 15 | {{< readfile file="content/tutorials/chassisControllerTutorial.md" markdown="true" >}} 16 | -------------------------------------------------------------------------------- /docs-dev/content/tutorials/motorTutorial.md: -------------------------------------------------------------------------------- 1 | ## Motor 2 | 3 | Writing the full `Motor` constructor any time you want to specify a motor gets quite tedious, so Okapi has some literals that make specifying motors much easier: 4 | 5 | ```c++ 6 | Motor foo(2); //Motor on port 2 7 | Motor foo = 2_m; //Equivalent literal 8 | 9 | Motor foo(2, true); //Reversed motor on port 2 10 | Motor foo = 2_rm; //Equivalent literal 11 | ``` 12 | 13 | Okapi also provides cubic control if you prefer to drive that way: 14 | 15 | ```c++ 16 | CubicMotor foo(2); //Motor on port 2 17 | CubicMotor foo = 2_3m; //Equivalent literal 18 | 19 | CubicMotor foo(2, true); //Reversed motor on port 2 20 | CubicMotor foo = 2_3rm; //Equivalent literal 21 | ``` 22 | 23 | Both `Motor` and `CubicMotor` can be given to a `ChassisModel`, and the behavior of `tank` and `arcade` will change accordingly. 24 | -------------------------------------------------------------------------------- /docs-dev/content/tutorials/pidTutorial.md: -------------------------------------------------------------------------------- 1 | ## PID 2 | 3 | Proportional-Integral-Derivative (PID) control is a simple and useful closed-loop controller. Say you have a subsystem with a motor and a potentiometer: 4 | 5 | ```c++ 6 | #include 7 | 8 | int port = 1; //Motor port 9 | int pot = 1; //Potentiometer 10 | Pid controller(1, 0.2, 0.3); //PID controller with kP = 1, kI = 0.2, kD = 0.3 11 | controller.setTarget(1500); //Set the target to 1500 on the potentiometer 12 | 13 | while (1) { 14 | controller.step(analogRead(pot)); //Loop the controller with the new pot reading 15 | motorSet(port, controller.getOutput()); //Power the motor with the output of the controller 16 | taskDelay(15); 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /docs-dev/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs-dev/data/.gitkeep -------------------------------------------------------------------------------- /docs-dev/layouts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs-dev/layouts/.gitkeep -------------------------------------------------------------------------------- /docs-dev/layouts/shortcodes/importPartial.html: -------------------------------------------------------------------------------- 1 | {{ partial (.Get 0) .Page }} -------------------------------------------------------------------------------- /docs-dev/layouts/shortcodes/insert_file.html: -------------------------------------------------------------------------------- 1 | {{ $file := .Get "file" | readFile }} 2 | {{ print $file | markdownify }} -------------------------------------------------------------------------------- /docs-dev/layouts/shortcodes/readfile.html: -------------------------------------------------------------------------------- 1 | {{$file := .Get "file"}} 2 | {{- if eq (.Get "markdown") "true" -}} 3 | {{- $file | readFile | markdownify -}} 4 | {{- else -}} 5 | {{ $file | readFile | safeHTML }} 6 | {{- end -}} -------------------------------------------------------------------------------- /docs-dev/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs-dev/static/.gitkeep -------------------------------------------------------------------------------- /docs-dev/static/css/imageAlign.css: -------------------------------------------------------------------------------- 1 | img[src$='#center'] 2 | { 3 | display: block; 4 | margin: 0.7rem auto; /* you can replace the vertical '0.7rem' by 5 | whatever floats your boat, but keep the 6 | horizontal 'auto' for this to work */ 7 | /* whatever else styles you fancy here */ 8 | } 9 | 10 | img[src$='#floatleft'] 11 | { 12 | float:left; 13 | margin: 0.7rem; /* this margin is totally up to you */ 14 | /* whatever else styles you fancy here */ 15 | } 16 | 17 | img[src$='#floatright'] 18 | { 19 | float:right; 20 | margin: 0.7rem; /* this margin is totally up to you */ 21 | /* whatever else styles you fancy here */ 22 | } -------------------------------------------------------------------------------- /docs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/.gitkeep -------------------------------------------------------------------------------- /docs/categories/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Categories on Okapi Docs 5 | https://okapilib.github.io/OkapiLib/categories/ 6 | Recent content in Categories on Okapi Docs 7 | Hugo -- gohugo.io 8 | en-us 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/css/imageAlign.css: -------------------------------------------------------------------------------- 1 | img[src$='#center'] 2 | { 3 | display: block; 4 | margin: 0.7rem auto; /* you can replace the vertical '0.7rem' by 5 | whatever floats your boat, but keep the 6 | horizontal 'auto' for this to work */ 7 | /* whatever else styles you fancy here */ 8 | } 9 | 10 | img[src$='#floatleft'] 11 | { 12 | float:left; 13 | margin: 0.7rem; /* this margin is totally up to you */ 14 | /* whatever else styles you fancy here */ 15 | } 16 | 17 | img[src$='#floatright'] 18 | { 19 | float:right; 20 | margin: 0.7rem; /* this margin is totally up to you */ 21 | /* whatever else styles you fancy here */ 22 | } -------------------------------------------------------------------------------- /docs/fonts/icon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/fonts/icon.eot -------------------------------------------------------------------------------- /docs/fonts/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/fonts/icon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/fonts/icon.ttf -------------------------------------------------------------------------------- /docs/fonts/icon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/fonts/icon.woff -------------------------------------------------------------------------------- /docs/getting-started/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Getting-starteds on Okapi Docs 5 | https://okapilib.github.io/OkapiLib/getting-started/ 6 | Recent content in Getting-starteds on Okapi Docs 7 | Hugo -- gohugo.io 8 | en-us 9 | 10 | 11 | 12 | 13 | 14 | Getting started 15 | https://okapilib.github.io/OkapiLib/getting-started/ 16 | Mon, 01 Jan 0001 00:00:00 +0000 17 | 18 | https://okapilib.github.io/OkapiLib/getting-started/ 19 | Programming a Skills Robot This tutorial is a step-by-step guide to programming this simple skills robot: 20 | This robot has motors and sensors plugged into the following ports: 21 | Motor Port Description Motor Port Description 1 6 Right middle motor 2 Left front motor 7 Right bottom motor 3 Left middle motor 8 Lift left motor 4 Left bottom motor 9 Lift right motor 5 Right top motor 10 Digital Port Description Digital Port Description 1 Left encoder top wire 7 2 Left encoder bottom wire 8 3 Right encoder top wire 9 4 Right encoder bottom wire 10 5 11 6 12 Analog Port Description Analog Port Description 1 Lift potentiometer 5 2 6 3 7 4 8 Project Configuration If you are creating a new project, the easiest way to get up to speed is to download Okapi&rsquo;s provided starter project, which comes pre-configured with everything you need to start coding. 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/home/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Homes on Okapi Docs 5 | https://okapilib.github.io/OkapiLib/home/ 6 | Recent content in Homes on Okapi Docs 7 | Hugo -- gohugo.io 8 | en-us 9 | 10 | 11 | 12 | 13 | 14 | Okapi Documentation 15 | https://okapilib.github.io/OkapiLib/home/ 16 | Mon, 01 Jan 0001 00:00:00 +0000 17 | 18 | https://okapilib.github.io/OkapiLib/home/ 19 | Primary Objective Welcome to Okapi! This library is designed to make modeling and programming complex robot behavior easy, efficient, and maintainable. This library is targeted at PROS users looking to take their competition robot to the next level, whether that means starting to use motion profiles instead of PID or designing an autonomous robot from the ground up. Okapi also comes with an optional cross-platform client that lets you interact with your robot in real time as a graphical interface to Okapi&rsquo;s modules. 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/images/colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/images/colors.png -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/images/logo.png -------------------------------------------------------------------------------- /docs/images/okapi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/images/okapi.jpg -------------------------------------------------------------------------------- /docs/images/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/images/screen.png -------------------------------------------------------------------------------- /docs/images/skillsRobotPicture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/docs/images/skillsRobotPicture.jpg -------------------------------------------------------------------------------- /docs/license/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Licenses on Okapi Docs 5 | https://okapilib.github.io/OkapiLib/license/ 6 | Recent content in Licenses on Okapi Docs 7 | Hugo -- gohugo.io 8 | en-us 9 | 10 | 11 | 12 | 13 | 14 | License 15 | https://okapilib.github.io/OkapiLib/license/ 16 | Mon, 01 Jan 0001 00:00:00 +0000 17 | 18 | https://okapilib.github.io/OkapiLib/license/ 19 | Mozilla Public License Version 2.0 Definitions &mdash;&mdash;&mdash;&mdash;&ndash; 1.1. &ldquo;Contributor&rdquo; means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 20 | 1.2. &ldquo;Contributor Version&rdquo; means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor&rsquo;s Contribution. 21 | 1.3. &ldquo;Contribution&rdquo; means Covered Software of a particular Contributor. 22 | 1.4. &ldquo;Covered Software&rdquo; means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/stylesheets/highlight/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | * overwrite the current primary color of the 3 | * theme that is used as fallback in codeblocks 4 | */ 5 | .article pre code { 6 | color: rgba(0, 0, 0, 0.8) !important; 7 | } 8 | 9 | 10 | /* 11 | HIGHLIGHT.JS THEME 12 | 13 | tweaked version of the Github theme 14 | */ 15 | 16 | .hljs { 17 | display:block; 18 | overflow-x:auto; 19 | } 20 | 21 | .hljs-comment, 22 | .hljs-quote { 23 | color:#998; 24 | font-style:italic; 25 | } 26 | 27 | .hljs-keyword, 28 | .hljs-selector-tag, 29 | .hljs-subst { 30 | color:#333; 31 | font-weight:700; 32 | } 33 | 34 | .hljs-number, 35 | .hljs-literal, 36 | .hljs-variable, 37 | .hljs-template-variable, 38 | .hljs-tag .hljs-attr { 39 | color:teal; 40 | } 41 | 42 | .hljs-string, 43 | .hljs-doctag { 44 | color:#d14; 45 | } 46 | 47 | .hljs-title, 48 | .hljs-section, 49 | .hljs-selector-id { 50 | color:#900; 51 | font-weight:700; 52 | } 53 | 54 | .hljs-subst { 55 | font-weight:400; 56 | } 57 | 58 | .hljs-type, 59 | .hljs-class .hljs-title { 60 | color:#458; 61 | font-weight:700; 62 | } 63 | 64 | .hljs-tag, 65 | .hljs-name, 66 | .hljs-attribute { 67 | color:navy; 68 | font-weight:400; 69 | } 70 | 71 | .hljs-regexp, 72 | .hljs-link { 73 | color:#009926; 74 | } 75 | 76 | .hljs-symbol, 77 | .hljs-bullet { 78 | color:#990073; 79 | } 80 | 81 | .hljs-built_in, 82 | .hljs-builtin-name { 83 | color:#0086b3; 84 | } 85 | 86 | .hljs-meta { 87 | color:#999; 88 | font-weight:700; 89 | } 90 | 91 | .hljs-deletion { 92 | background:#fdd; 93 | } 94 | 95 | .hljs-addition { 96 | background:#dfd; 97 | } 98 | 99 | .hljs-emphasis { 100 | font-style:italic; 101 | } 102 | 103 | .hljs-strong { 104 | font-weight:700; 105 | } 106 | -------------------------------------------------------------------------------- /docs/stylesheets/temporary.css: -------------------------------------------------------------------------------- 1 | /* This file only exists (temporarily) until the 2 | custom styling can be replaced with the 3 | implementation of the upstream project. 4 | */ 5 | 6 | blockquote { 7 | padding: 0 20px; 8 | margin: 0 0 20px; 9 | font-size: inherit; 10 | border-left: 5px solid #eee; 11 | } 12 | -------------------------------------------------------------------------------- /docs/tags/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tags on Okapi Docs 5 | https://okapilib.github.io/OkapiLib/tags/ 6 | Recent content in Tags on Okapi Docs 7 | Hugo -- gohugo.io 8 | en-us 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /firmware/STM32F10x.ld: -------------------------------------------------------------------------------- 1 | /* Memory space definitions */ 2 | MEMORY { 3 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K 4 | FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 384K 5 | } 6 | 7 | /* Higher address of the user mode stack */ 8 | EXTERN ( _estack ); 9 | PROVIDE ( _estack = ORIGIN(RAM) + LENGTH(RAM) ); 10 | 11 | /* This sends all unreferenced IRQHandlers to reset. */ 12 | PROVIDE ( ISR_SWI = 0 ); 13 | PROVIDE ( ISR_IRQ = 0 ); 14 | PROVIDE ( ISR_Prefetch = 0 ); 15 | PROVIDE ( ISR_Abort = 0 ); 16 | PROVIDE ( ISR_FIQ = 0 ); 17 | 18 | PROVIDE ( ISR_NMI = 0 ); 19 | PROVIDE ( ISR_HardFault = 0 ); 20 | PROVIDE ( ISR_MemManage = 0 ); 21 | PROVIDE ( ISR_BusFault = 0 ); 22 | PROVIDE ( ISR_UsageFault = 0 ); 23 | 24 | PROVIDE ( ISR_SVC = 0 ); 25 | PROVIDE ( ISR_DebugMon = 0 ); 26 | PROVIDE ( ISR_PendSV = 0 ); 27 | PROVIDE ( ISR_SysTick = 0 ); 28 | 29 | PROVIDE ( ISR_WWDG = 0 ); 30 | PROVIDE ( ISR_PVD = 0 ); 31 | PROVIDE ( ISR_TAMPER = 0 ); 32 | PROVIDE ( ISR_RTC = 0 ); 33 | PROVIDE ( ISR_FLASH = 0 ); 34 | PROVIDE ( ISR_RCC = 0 ); 35 | PROVIDE ( ISR_EXTI0 = 0 ); 36 | PROVIDE ( ISR_EXTI1 = 0 ); 37 | PROVIDE ( ISR_EXTI2 = 0 ); 38 | PROVIDE ( ISR_EXTI3 = 0 ); 39 | PROVIDE ( ISR_EXTI4 = 0 ); 40 | PROVIDE ( ISR_DMAChannel1 = 0 ); 41 | PROVIDE ( ISR_DMAChannel2 = 0 ); 42 | PROVIDE ( ISR_DMAChannel3 = 0 ); 43 | PROVIDE ( ISR_DMAChannel4 = 0 ); 44 | PROVIDE ( ISR_DMAChannel5 = 0 ); 45 | PROVIDE ( ISR_DMAChannel6 = 0 ); 46 | PROVIDE ( ISR_DMAChannel7 = 0 ); 47 | PROVIDE ( ISR_DMA1_Channel1 = 0 ); 48 | PROVIDE ( ISR_DMA1_Channel2 = 0 ); 49 | PROVIDE ( ISR_DMA1_Channel3 = 0 ); 50 | PROVIDE ( ISR_DMA1_Channel4 = 0 ); 51 | PROVIDE ( ISR_DMA1_Channel5 = 0 ); 52 | PROVIDE ( ISR_DMA1_Channel6 = 0 ); 53 | PROVIDE ( ISR_DMA1_Channel7 = 0 ); 54 | PROVIDE ( ISR_ADC = 0 ); 55 | PROVIDE ( ISR_ADC1_2 = 0 ); 56 | PROVIDE ( ISR_USB_HP_CAN_TX = 0 ); 57 | PROVIDE ( ISR_USB_HP_CAN1_TX = 0 ); 58 | PROVIDE ( ISR_USB_LP_CAN_RX0 = 0 ); 59 | PROVIDE ( ISR_USB_LP_CAN1_RX0 = 0 ); 60 | PROVIDE ( ISR_CAN_RX1 = 0 ); 61 | PROVIDE ( ISR_CAN1_RX1 = 0 ); 62 | PROVIDE ( ISR_CAN_SCE = 0 ); 63 | PROVIDE ( ISR_CAN1_SCE = 0 ); 64 | PROVIDE ( ISR_EXTI9_5 = 0 ); 65 | PROVIDE ( ISR_TIM1_BRK = 0 ); 66 | PROVIDE ( ISR_TIM1_UP = 0 ); 67 | PROVIDE ( ISR_TIM1_TRG_COM = 0 ); 68 | PROVIDE ( ISR_TIM1_CC = 0 ); 69 | PROVIDE ( ISR_TIM2 = 0 ); 70 | PROVIDE ( ISR_TIM3 = 0 ); 71 | PROVIDE ( ISR_TIM4 = 0 ); 72 | PROVIDE ( ISR_I2C1_EV = 0 ); 73 | PROVIDE ( ISR_I2C1_ER = 0 ); 74 | PROVIDE ( ISR_I2C2_EV = 0 ); 75 | PROVIDE ( ISR_I2C2_ER = 0 ); 76 | PROVIDE ( ISR_SPI1 = 0 ); 77 | PROVIDE ( ISR_SPI2 = 0 ); 78 | PROVIDE ( ISR_USART1 = 0 ); 79 | PROVIDE ( ISR_USART2 = 0 ); 80 | PROVIDE ( ISR_USART3 = 0 ); 81 | PROVIDE ( ISR_EXTI15_10 = 0 ); 82 | PROVIDE ( ISR_RTCAlarm = 0 ); 83 | PROVIDE ( ISR_USBWakeUp = 0 ); 84 | PROVIDE ( ISR_TIM8_BRK = 0 ); 85 | PROVIDE ( ISR_TIM8_UP = 0 ); 86 | PROVIDE ( ISR_TIM8_TRG_COM = 0 ); 87 | PROVIDE ( ISR_TIM8_CC = 0 ); 88 | PROVIDE ( ISR_ADC3 = 0 ); 89 | PROVIDE ( ISR_FSMC = 0 ); 90 | PROVIDE ( ISR_SDIO = 0 ); 91 | PROVIDE ( ISR_TIM5 = 0 ); 92 | PROVIDE ( ISR_SPI3 = 0 ); 93 | PROVIDE ( ISR_UART4 = 0 ); 94 | PROVIDE ( ISR_UART5 = 0 ); 95 | PROVIDE ( ISR_TIM6 = 0 ); 96 | PROVIDE ( ISR_TIM7 = 0 ); 97 | PROVIDE ( ISR_DMA2_Channel1 = 0 ); 98 | PROVIDE ( ISR_DMA2_Channel2 = 0 ); 99 | PROVIDE ( ISR_DMA2_Channel3 = 0 ); 100 | PROVIDE ( ISR_DMA2_Channel4_5 = 0 ); 101 | -------------------------------------------------------------------------------- /firmware/cortex.ld: -------------------------------------------------------------------------------- 1 | /* Include STM32F10X linker scripts */ 2 | INCLUDE "STM32F10x.ld" 3 | 4 | EXTERN ( _heapbegin ); 5 | 6 | /* Section definitions for Cortex firmware flashing */ 7 | SECTIONS { 8 | .isr_vector : { 9 | /* startup code, prevents garbage collection from eating everything */ 10 | KEEP(*(.isr_vector)) 11 | . = ALIGN(4); 12 | } >FLASH 13 | .text : { 14 | . = ALIGN(4); 15 | *(.text) 16 | *(.text.*) 17 | /* Preinit array of functions */ 18 | __preinit_array_start = .; 19 | KEEP (*(.preinit_array)) 20 | __preinit_array_end = .; 21 | . = ALIGN(4); 22 | /* Init array of functions */ 23 | KEEP(*(.init)) 24 | . = ALIGN(4); 25 | __init_array_start = .; 26 | KEEP (*(SORT(.init_array.*))) 27 | KEEP (*(.init_array)) 28 | __init_array_end = .; 29 | . = ALIGN(4); 30 | /* C++ constructors */ 31 | KEEP (*crtbegin.o(.ctors)) 32 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 33 | KEEP (*(SORT(.ctors.*))) 34 | KEEP (*crtend.o(.ctors)) 35 | . = ALIGN(4); 36 | /* Finalizer array of functions */ 37 | KEEP(*(.fini)) 38 | . = ALIGN(4); 39 | __fini_array_start = .; 40 | KEEP (*(.fini_array)) 41 | KEEP (*(SORT(.fini_array.*))) 42 | __fini_array_end = .; 43 | . = ALIGN(4); 44 | /* C++ destructors */ 45 | KEEP (*crtbegin.o(.dtors)) 46 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 47 | KEEP (*(SORT(.dtors.*))) 48 | KEEP (*crtend.o(.dtors)) 49 | _etext = .; 50 | _srdata = .; 51 | . = ALIGN(4); 52 | *(.rodata) 53 | *(.rodata*) 54 | *(.glue_7) 55 | *(.glue_7t) 56 | . = ALIGN(4); 57 | _erdata = .; 58 | _sidata = .; 59 | } >FLASH 60 | /* The program executes knowing that the data is in the RAM, but the loader puts the 61 | * initial values in the FLASH (inidata). The startup copies the initial values over */ 62 | .data : AT ( _sidata ) { 63 | . = ALIGN(4); 64 | _sdata = .; 65 | *(.data) 66 | *(.data.*) 67 | *(.RAMtext) 68 | . = ALIGN(4); 69 | _edata = .; 70 | } >RAM 71 | /* Uninitialized data (zero-fill) section */ 72 | .bss : { 73 | . = ALIGN(4); 74 | _sbss = .; 75 | *(.bss) 76 | *(COMMON) 77 | . = ALIGN(4); 78 | _ebss = .; 79 | . = ALIGN(8); 80 | _heapbegin = .; 81 | } >RAM 82 | 83 | /DISCARD/ : { 84 | libc.a ( * ) 85 | libg.a ( * ) 86 | libm.a ( * ) 87 | libgcc.a ( * ) 88 | libstdc++.a ( * ) 89 | libsupc++.a ( * ) 90 | } 91 | /* ARM exception unwinding, mandated by ARM EABI C++ standard (with -fno-exceptions?) */ 92 | /*.ARM.exidx 0 : { *(.ARM.exidx*) }*/ 93 | .ARM.exidx : { 94 | __exidx_start = .; 95 | *(.ARM.exidx*) 96 | __exidx_end = .; 97 | } 98 | /* Stabs debugging sections */ 99 | .stab 0 : { *(.stab) } 100 | .stabstr 0 : { *(.stabstr) } 101 | .stab.excl 0 : { *(.stab.excl) } 102 | .stab.exclstr 0 : { *(.stab.exclstr) } 103 | .stab.index 0 : { *(.stab.index) } 104 | .stab.indexstr 0 : { *(.stab.indexstr) } 105 | .comment 0 : { *(.comment) } 106 | /* DWARF 1 */ 107 | .debug 0 : { *(.debug) } 108 | .line 0 : { *(.line) } 109 | /* GNU DWARF 1 extensions */ 110 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 111 | .debug_sfnames 0 : { *(.debug_sfnames) } 112 | /* DWARF 1.1 and DWARF 2 */ 113 | .debug_aranges 0 : { *(.debug_aranges) } 114 | .debug_pubnames 0 : { *(.debug_pubnames) } 115 | /* DWARF 2 */ 116 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 117 | .debug_abbrev 0 : { *(.debug_abbrev) } 118 | .debug_line 0 : { *(.debug_line) } 119 | .debug_frame 0 : { *(.debug_frame) } 120 | .debug_str 0 : { *(.debug_str) } 121 | .debug_loc 0 : { *(.debug_loc) } 122 | .debug_macinfo 0 : { *(.debug_macinfo) } 123 | /* SGI/MIPS DWARF 2 extensions */ 124 | .debug_weaknames 0 : { *(.debug_weaknames) } 125 | .debug_funcnames 0 : { *(.debug_funcnames) } 126 | .debug_typenames 0 : { *(.debug_typenames) } 127 | .debug_varnames 0 : { *(.debug_varnames) } 128 | } 129 | -------------------------------------------------------------------------------- /firmware/libpros.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/firmware/libpros.a -------------------------------------------------------------------------------- /firmware/uniflash.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/firmware/uniflash.jar -------------------------------------------------------------------------------- /include/chassis/chassisController.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_CHASSISCONTROLLER 2 | #define OKAPI_CHASSISCONTROLLER 3 | 4 | #include "chassis/chassisModel.h" 5 | #include "control/pid.h" 6 | #include "odometry/odometry.h" 7 | #include 8 | 9 | namespace okapi { 10 | class ChassisController { 11 | public: 12 | ChassisController(const ChassisModelParams& imodelParams): 13 | model(imodelParams.make()) {} 14 | 15 | ChassisController(const std::shared_ptr& imodel): 16 | model(imodel) {} 17 | 18 | virtual ~ChassisController() = default; 19 | 20 | /** 21 | * Drives the robot straight 22 | * @param itarget Distance to travel 23 | */ 24 | virtual void driveStraight(const int itarget) = 0; 25 | 26 | /** 27 | * Turns the robot clockwise in place 28 | * @param idegTarget Degrees to turn for 29 | */ 30 | virtual void pointTurn(const float idegTarget) = 0; 31 | 32 | //Passed through to internal ChassisModel 33 | void driveForward(const int power) { model->driveForward(power); } 34 | void driveVector(const int distPower, const int anglePower) { model->driveVector(distPower, anglePower); } 35 | void turnClockwise(const int power) { model->turnClockwise(power); } 36 | void stop() { model->stop(); } 37 | void tank(const int leftVal, const int rightVal, const int threshold = 0) { model->tank(leftVal, rightVal, threshold); } 38 | void arcade(int verticalVal, int horizontalVal, const int threshold = 0) { model->arcade(verticalVal, horizontalVal, threshold); } 39 | void left(const int val) { model->left(val); } 40 | void leftTS(const int val) { model->leftTS(val); } 41 | void right(const int val) { model->right(val); } 42 | void rightTS(const int val) { model->rightTS(val); } 43 | std::valarray getSensorVals() { return model->getSensorVals(); } 44 | protected: 45 | std::shared_ptr model; 46 | }; 47 | 48 | class ChassisControllerPid : public virtual ChassisController { 49 | public: 50 | ChassisControllerPid(const ChassisModelParams& imodelParams, const PidParams& idistanceParams, const PidParams& iangleParams): 51 | ChassisController(imodelParams), 52 | distancePid(idistanceParams), 53 | anglePid(iangleParams) {} 54 | 55 | ChassisControllerPid(const std::shared_ptr& imodel, const PidParams& idistanceParams, const PidParams& iangleParams): 56 | ChassisController(imodel), 57 | distancePid(idistanceParams), 58 | anglePid(iangleParams) {} 59 | 60 | virtual ~ChassisControllerPid() { 61 | delete &distancePid; 62 | delete &anglePid; 63 | } 64 | 65 | /** 66 | * Drives the robot straight 67 | * @param itarget Distance to travel 68 | */ 69 | void driveStraight(const int itarget) override; 70 | 71 | /** 72 | * Turns the robot clockwise in place 73 | * @param idegTarget Degrees to turn for 74 | */ 75 | void pointTurn(float idegTarget) override; 76 | protected: 77 | Pid distancePid, anglePid; 78 | }; 79 | } 80 | 81 | #endif /* end of include guard: OKAPI_CHASSISCONTROLLER */ 82 | -------------------------------------------------------------------------------- /include/chassis/odomChassisController.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ODOMCHASSISCONTROLLER 2 | #define OKAPI_ODOMCHASSISCONTROLLER 3 | 4 | #include "odometry/odometry.h" 5 | #include "chassis/chassisController.h" 6 | 7 | namespace okapi { 8 | class OdomChassisController : public virtual ChassisController { 9 | public: 10 | /** 11 | * Odometry based chassis controller. Spins up a task at the default 12 | * priority plus 1 for odometry when constructed 13 | * @param iparams Odometry parameters for the internal odometry math 14 | */ 15 | OdomChassisController(const OdomParams& iparams): 16 | ChassisController(iparams.model), 17 | odom(iparams) { 18 | taskCreate((TaskCode)Odometry::trampoline, TASK_DEFAULT_STACK_SIZE, &odom, TASK_PRIORITY_DEFAULT + 1); 19 | } 20 | 21 | virtual ~OdomChassisController() = default; 22 | 23 | /** 24 | * Drives the robot straight to a point in the odom frame 25 | * @param ix X coordinate 26 | * @param iy Y coordinate 27 | */ 28 | virtual void driveToPoint(const float ix, const float iy, const bool ibackwards = false, const float ioffset = 0) = 0; 29 | 30 | /** 31 | * Turns the robot to face an angle in the odom frame 32 | * @param iangle Angle to turn to 33 | */ 34 | virtual void turnToAngle(const float iangle) = 0; 35 | 36 | /** 37 | * Passthrough to internal Odometry object 38 | * @return State from internal Odometry object 39 | */ 40 | OdomState getState() { return odom.getState(); } 41 | protected: 42 | static constexpr int moveThreshold = 10; //Minimum length movement 43 | Odometry odom; 44 | }; 45 | 46 | class OdomChassisControllerPid : public OdomChassisController, public ChassisControllerPid { 47 | public: 48 | OdomChassisControllerPid(const OdomParams& params, const PidParams& idistanceParams, const PidParams& iangleParams): 49 | ChassisController(params.model), 50 | OdomChassisController(params), 51 | ChassisControllerPid(params.model, idistanceParams, iangleParams) {} 52 | 53 | virtual ~OdomChassisControllerPid() = default; 54 | 55 | /** 56 | * Drives the robot straight to a point in the odom frame 57 | * @param ix X coordinate 58 | * @param iy Y coordinate 59 | */ 60 | void driveToPoint(const float ix, const float iy, const bool ibackwards = false, const float ioffset = 0) override; 61 | 62 | /** 63 | * Turns the robot to face an angle in the odom frame 64 | * @param iangle Angle to turn to 65 | */ 66 | void turnToAngle(const float iangle) override; 67 | }; 68 | } 69 | 70 | #endif /* end of include guard: OKAPI_ODOMCHASSISCONTROLLER */ 71 | -------------------------------------------------------------------------------- /include/control/controlObject.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_CONTORLOBJECT 2 | #define OKAPI_CONTORLOBJECT 3 | 4 | namespace okapi { 5 | class ControlObjectParams {}; 6 | 7 | class ControlObject { 8 | public: 9 | virtual ~ControlObject() = default; 10 | 11 | /** 12 | * Do one iteration of the controller 13 | * @param inewReading New measurement 14 | * @return Controller output 15 | */ 16 | virtual float step(const float ireading) = 0; 17 | 18 | /** 19 | * Sets the target for the controller 20 | */ 21 | virtual void setTarget(const float itarget) = 0; 22 | 23 | /** 24 | * Returns the last calculated output of the controller 25 | */ 26 | virtual float getOutput() const = 0; 27 | 28 | /** 29 | * Returns the last error of the controller 30 | */ 31 | virtual float getError() const = 0; 32 | 33 | /** 34 | * Set time between loops in ms 35 | * @param isampleTime Time between loops in ms 36 | */ 37 | virtual void setSampleTime(const int isampleTime); 38 | 39 | /** 40 | * Set controller output bounds 41 | * @param imax Max output 42 | * @param imin Min output 43 | */ 44 | virtual void setOutputLimits(float imax, float imin); 45 | 46 | /** 47 | * Resets the controller so it can start from 0 again properly. Keeps 48 | * configuration from before 49 | */ 50 | virtual void reset(); 51 | 52 | /** 53 | * Turns the controller on or off 54 | */ 55 | virtual void flipDisable(); 56 | }; 57 | } 58 | 59 | #endif /* OKAPI_CONTROLOBJECT */ 60 | -------------------------------------------------------------------------------- /include/control/genericController.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_GENERICCONTROLLER 2 | #define OKAPI_GENERICCONTROLLER 3 | 4 | #include 5 | #include 6 | #include "control/controlObject.h" 7 | #include "device/motor.h" 8 | 9 | namespace okapi { 10 | template 11 | class GenericController { 12 | public: 13 | GenericController(const std::array &imotorList, const std::shared_ptr &iptr): 14 | motors(imotorList), 15 | controller(iptr) {} 16 | 17 | void step(const float ireading) { 18 | controller->step(ireading); 19 | for (size_t i = 0; i < motors.size(); i++) 20 | motors[i].setTS(static_cast(controller->getOutput())); 21 | } 22 | 23 | void setTarget(const float itarget) { controller->setTarget(itarget); } 24 | 25 | void getOutput() const { return controller->getOutput(); } 26 | 27 | void setSampleTime(const int isampleTime) { controller->setSampleTime(isampleTime); } 28 | 29 | void setOutputLimits(float imax, float imin) { controller->setOutputLimits(imax, imin); } 30 | 31 | void reset() { controller->reset(); } 32 | 33 | void flipDisable() { controller->flipDisable(); } 34 | private: 35 | std::array motors; 36 | std::shared_ptr controller; 37 | }; 38 | } 39 | 40 | #endif /* OKAPI_GENERICCONTROLLER */ 41 | -------------------------------------------------------------------------------- /include/control/nsPid.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_NSPID 2 | #define OKAPI_NSPID 3 | 4 | #include "control/pid.h" 5 | #include "control/velMath.h" 6 | 7 | namespace okapi { 8 | class NsPid : public Pid { 9 | public: 10 | NsPid(const PidParams& iparams, const VelMathParams& ivelParams, const float iminVel, const float iscale = 0.1): 11 | Pid::Pid(iparams), 12 | velMath(ivelParams), 13 | minVel(iminVel), 14 | scale(iscale) {} 15 | 16 | /** 17 | * Do one iteration of the controller 18 | * @param inewReading New measurement 19 | * @return Controller output 20 | */ 21 | virtual float step(const float inewReading) override; 22 | protected: 23 | VelMath velMath; 24 | float minVel, scale; 25 | }; 26 | } 27 | 28 | #endif /* end of include guard: OKAPI_NSPID */ 29 | -------------------------------------------------------------------------------- /include/control/pid.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_PID 2 | #define OKAPI_PID 3 | 4 | #include "control/controlObject.h" 5 | 6 | namespace okapi { 7 | class PidParams : public ControlObjectParams { 8 | public: 9 | PidParams(const float ikP, const float ikI, const float ikD, const float ikBias = 0): 10 | kP(ikP), 11 | kI(ikI), 12 | kD(ikD), 13 | kBias(ikBias) {} 14 | 15 | float kP, kI, kD, kBias; 16 | }; 17 | 18 | class Pid : public ControlObject { 19 | public: 20 | /** 21 | * PID controller 22 | * @param ikP Proportional gain 23 | * @param ikI Integral gain 24 | * @param ikD Derivative gain 25 | * @param ikBias Controller bias (added to final output) 26 | */ 27 | Pid(const float ikP, const float ikI, const float ikD, const float ikBias = 0): 28 | lastTime(0), 29 | sampleTime(15), 30 | error(0), 31 | lastError(0), 32 | target(0), 33 | lastReading(0), 34 | integral(0), 35 | integralMax(127), 36 | integralMin(-127), 37 | output(0), 38 | outputMax(127), 39 | outputMin(-127), 40 | shouldResetOnCross(true), 41 | isOn(true) { 42 | setGains(ikP, ikI, ikD, ikBias); 43 | } 44 | 45 | /** 46 | * PID controller 47 | * @param params Params (see PidParams docs) 48 | */ 49 | Pid(const PidParams& params): 50 | lastTime(0), 51 | sampleTime(15), 52 | error(0), 53 | lastError(0), 54 | target(0), 55 | lastReading(0), 56 | integral(0), 57 | integralMax(127), 58 | integralMin(-127), 59 | output(0), 60 | outputMax(127), 61 | outputMin(-127), 62 | shouldResetOnCross(true), 63 | isOn(true) { 64 | setGains(params.kP, params.kI, params.kD, params.kBias); 65 | } 66 | 67 | virtual ~Pid() = default; 68 | 69 | /** 70 | * Do one iteration of the controller 71 | * @param inewReading New measurement 72 | * @return Controller output 73 | */ 74 | virtual float step(const float inewReading) override; 75 | 76 | void setTarget(const float itarget) override { target = itarget; } 77 | 78 | float getOutput() const override { return output; } 79 | 80 | float getError() const override { return error; } 81 | 82 | /** 83 | * Set controller gains 84 | * @param ikP Proportional gain 85 | * @param ikI Integral gain 86 | * @param ikD Derivative gain 87 | * @param ikBias Controller bias 88 | */ 89 | void setGains(const float ikP, const float ikI, const float ikD, const float ikBias = 0); 90 | 91 | /** 92 | * Set time between loops in ms 93 | * @param isampleTime Time between loops in ms 94 | */ 95 | void setSampleTime(const int isampleTime) override; 96 | 97 | /** 98 | * Set controller output bounds 99 | * @param imax Max output 100 | * @param imin Min output 101 | */ 102 | void setOutputLimits(float imax, float imin) override; 103 | 104 | /** 105 | * Set integrator bounds 106 | * @param imax Max integrator value 107 | * @param imin Min integrator value 108 | */ 109 | void setIntegralLimits(float imax, float imin); 110 | 111 | /** 112 | * Resets the controller so it can start from 0 again properly. Keeps gains 113 | * and limits from before 114 | */ 115 | void reset() override; 116 | 117 | /** 118 | * Set whether the integrator should be reset when error is 0 or changes sign 119 | * @param iresetOnZero True to reset 120 | */ 121 | void setIntegratorReset(bool iresetOnZero) { shouldResetOnCross = iresetOnZero; } 122 | 123 | void flipDisable() override { isOn = !isOn; } 124 | protected: 125 | float kP, kI, kD, kBias; 126 | long lastTime, sampleTime; 127 | float error, lastError; 128 | float target, lastReading; 129 | float integral, integralMax, integralMin; 130 | float output, outputMax, outputMin; 131 | bool shouldResetOnCross, isOn; 132 | }; 133 | } 134 | 135 | #endif /* end of include guard: OKAPI_PID */ 136 | -------------------------------------------------------------------------------- /include/control/velMath.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_VELOCITY 2 | #define OKAPI_VELOCITY 3 | 4 | #include "filter/demaFilter.h" 5 | 6 | namespace okapi { 7 | class VelMathParams { 8 | public: 9 | VelMathParams(const float iticksPerRev, const float ialpha = 0.19, const float ibeta = 0.041): 10 | ticksPerRev(iticksPerRev), 11 | alpha(ialpha), 12 | beta(ibeta) {} 13 | 14 | float ticksPerRev, alpha, beta; 15 | }; 16 | 17 | class VelMath { 18 | public: 19 | VelMath(const float iticksPerRev, const float ialpha = 0.19, const float ibeta = 0.041): 20 | lastTime(0), 21 | vel(0), 22 | lastVel(0), 23 | lastPos(0), 24 | ticksPerRev(iticksPerRev), 25 | filter(ialpha, ibeta) {} 26 | 27 | VelMath(const VelMathParams& iparams): 28 | lastTime(0), 29 | vel(0), 30 | lastVel(0), 31 | lastPos(0), 32 | ticksPerRev(iparams.ticksPerRev), 33 | filter(iparams.alpha, iparams.beta) {} 34 | 35 | /** 36 | * Calculate new velocity 37 | * @param inewPos New position 38 | * @return New velocity 39 | */ 40 | float step(const float inewPos); 41 | 42 | void setGains(const float ialpha, const float ibeta) { filter.setGains(ialpha, ibeta); } 43 | 44 | void setTicksPerRev(const float iTPR) { ticksPerRev = iTPR; } 45 | 46 | float getOutput() const { return vel; } 47 | 48 | float getDiff() const { return vel - lastVel; } 49 | private: 50 | long lastTime; 51 | float vel, lastVel, lastPos, ticksPerRev; 52 | DemaFilter filter; 53 | }; 54 | } 55 | 56 | #endif /* end of include guard: OKAPI_VELOCITY */ 57 | -------------------------------------------------------------------------------- /include/control/velPid.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_VELPID 2 | #define OKAPI_VELPID 3 | 4 | #include "control/velMath.h" 5 | #include "control/controlObject.h" 6 | 7 | namespace okapi { 8 | class VelPidParams : public ControlObjectParams { 9 | public: 10 | VelPidParams(const float ikP, const float ikD): 11 | kP(ikP), 12 | kD(ikD) {} 13 | 14 | float kP, kD; 15 | }; 16 | 17 | class VelPid : public ControlObject { 18 | public: 19 | /** 20 | * Velocity PID controller 21 | * @param ikP Proportional gain 22 | * @param ikD Derivative gain 23 | */ 24 | VelPid(const float ikP, const float ikD): 25 | lastTime(0), 26 | sampleTime(15), 27 | error(0), 28 | lastError(0), 29 | target(0), 30 | output(0), 31 | outputMax(127), 32 | outputMin(-127), 33 | isOn(true), 34 | velMath(360) { 35 | setGains(ikP, ikD); 36 | } 37 | 38 | /** 39 | * Velocity PID controller 40 | * @param params Params (see VelPidParams docs) 41 | */ 42 | VelPid(const VelPidParams& params): 43 | lastTime(0), 44 | sampleTime(15), 45 | error(0), 46 | lastError(0), 47 | target(0), 48 | output(0), 49 | outputMax(127), 50 | outputMin(-127), 51 | isOn(true), 52 | velMath(360) { 53 | setGains(params.kP, params.kD); 54 | } 55 | 56 | virtual ~VelPid() = default; 57 | 58 | /** 59 | * Do one iteration of velocity calculation 60 | * @param inewReading New measurement 61 | * @return Filtered velocity 62 | */ 63 | virtual float stepVel(const float inewReading); 64 | 65 | /** 66 | * Do one iteration of the controller 67 | * @param inewReading New measurement 68 | * @return Controller output 69 | */ 70 | virtual float step(const float inewReading) override; 71 | 72 | void setTarget(const float itarget) override { target = itarget; } 73 | 74 | float getOutput() const override { return isOn ? output : 0; } 75 | 76 | float getError() const override { return error; } 77 | 78 | /** 79 | * Set time between loops in ms 80 | * @param isampleTime Time between loops in ms 81 | */ 82 | void setSampleTime(const int isampleTime) override; 83 | 84 | /** 85 | * Set controller output bounds 86 | * @param imax Max output 87 | * @param imin Min output 88 | */ 89 | void setOutputLimits(float imax, float imin) override; 90 | 91 | void reset() override; 92 | 93 | void flipDisable() override { isOn = !isOn; } 94 | 95 | /** 96 | * Set controller gains 97 | * @param ikP Proportional gain 98 | * @param ikD Derivative gain 99 | * @param ikBias Controller bias 100 | */ 101 | void setGains(const float ikP, const float ikD); 102 | 103 | /** 104 | * Set the gains for the double moving average filter. Defaults are 0.19 and 0.0526, respectively 105 | * @param alpha Alpha gain 106 | * @param beta Beta gain 107 | */ 108 | void setFilterGains(const float alpha, const float beta) { velMath.setGains(alpha, beta); } 109 | 110 | /** 111 | * Set the number of measurements per revolution. Default is 360 112 | * @param tpr Number of measured units per revolution 113 | */ 114 | void setTicksPerRev(const float tpr) { velMath.setTicksPerRev(tpr); } 115 | 116 | float getVel() const { return velMath.getOutput(); } 117 | 118 | private: 119 | float kP, kD; 120 | long lastTime, sampleTime; 121 | float error, lastError; 122 | float target; 123 | float output, outputMax, outputMin; 124 | bool isOn; 125 | VelMath velMath; 126 | }; 127 | } 128 | 129 | #endif /* end of include guard: OKAPI_VELPID */ 130 | -------------------------------------------------------------------------------- /include/device/button.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_BUTTON 2 | #define OKAPI_BUTTON 3 | 4 | #include "PAL/PAL.h" 5 | 6 | namespace okapi { 7 | class Button { 8 | public: 9 | explicit constexpr Button(const unsigned char iport, const bool iinverted = false): 10 | joystick(1), 11 | buttonGroup(8), 12 | port(iport), 13 | lcd(uart1), 14 | inverted(iinverted), 15 | isJoystick(false), 16 | isLCD(false), 17 | wasPressedLast(iinverted) {} 18 | 19 | explicit constexpr Button(const unsigned char ijoystick, const unsigned char ibuttonGroup, const unsigned char ibutton, const bool iinverted = false): 20 | joystick(ijoystick), 21 | buttonGroup(ibuttonGroup), 22 | port(ibutton), 23 | lcd(uart1), 24 | inverted(iinverted), 25 | isJoystick(true), 26 | isLCD(false), 27 | wasPressedLast(iinverted) {} 28 | 29 | explicit constexpr Button(PROS_FILE* ilcdPort, const unsigned char ilcdButton, const bool iinverted = false): 30 | joystick(1), 31 | buttonGroup(8), 32 | port(ilcdButton), 33 | lcd(ilcdPort), 34 | inverted(iinverted), 35 | isJoystick(false), 36 | isLCD(true), 37 | wasPressedLast(iinverted) {} 38 | 39 | bool isPressed() const { 40 | if (isJoystick) 41 | return inverted ? !PAL::joystickGetDigital(joystick, buttonGroup, port) : PAL::joystickGetDigital(joystick, buttonGroup, port); 42 | else if (isLCD) 43 | return inverted ? !(PAL::lcdReadButtons(lcd) == port) : (PAL::lcdReadButtons(lcd) == port); 44 | else 45 | return inverted ? !PAL::digitalRead(port) : PAL::digitalRead(port); 46 | } 47 | 48 | bool edge() { 49 | const bool pressed = isPressed(); 50 | const bool out = pressed ^ wasPressedLast; 51 | wasPressedLast = pressed; 52 | return out; 53 | } 54 | 55 | bool risingEdge() { return edge() && wasPressedLast; } //Remember edge sets wasPressedLast 56 | 57 | bool fallingEdge() { return edge() && !wasPressedLast; } //Remember edge sets wasPressedLast 58 | private: 59 | const unsigned char joystick, buttonGroup, port; 60 | PROS_FILE *lcd; 61 | const bool inverted, isJoystick, isLCD; 62 | bool wasPressedLast; 63 | }; 64 | 65 | inline namespace literals { 66 | constexpr Button operator"" _b(const unsigned long long int p) { return Button(static_cast(p), false); } 67 | constexpr Button operator"" _ib(const unsigned long long int p) { return Button(static_cast(p), true); } 68 | } 69 | } 70 | 71 | #endif /* end of include guard: OKAPI_BUTTON */ 72 | -------------------------------------------------------------------------------- /include/device/ime.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_IME 2 | #define OKAPI_IME 3 | 4 | #include "device/rotarySensor.h" 5 | #include "PAL/PAL.h" 6 | 7 | namespace okapi { 8 | class IME : public RotarySensor { 9 | public: 10 | explicit constexpr IME(const unsigned char iindex): 11 | index(iindex), 12 | reversed(1), 13 | val(0) {} 14 | 15 | explicit constexpr IME(const unsigned char iindex, const bool ireversed): 16 | index(iindex), 17 | reversed(ireversed ? -1 : 1), 18 | val(0) {} 19 | 20 | int get() override { PAL::imeGet(index, &val); return reversed * val; } 21 | void reset() override { PAL::imeReset(index); } 22 | private: 23 | unsigned char index; 24 | const int reversed; 25 | int val; 26 | }; 27 | 28 | inline namespace literals { 29 | constexpr IME operator"" _ime(const unsigned long long int p) { return IME(static_cast(p), false); } 30 | constexpr IME operator"" _rime(const unsigned long long int p) { return IME(static_cast(p), true); } 31 | } 32 | } 33 | 34 | #endif /* end of include guard: OKAPI_IME */ 35 | -------------------------------------------------------------------------------- /include/device/potentiometer.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_POTENTIOMETER 2 | #define OKAPI_POTENTIOMETER 3 | 4 | #include "PAL/PAL.h" 5 | 6 | namespace okapi { 7 | class Potentiometer { 8 | public: 9 | explicit constexpr Potentiometer(const unsigned char iport, const bool iinverted = false): 10 | port(iport), 11 | inverted(iinverted) {} 12 | 13 | int get() const { return inverted ? 4095 - PAL::analogRead(port) : PAL::analogRead(port); } 14 | private: 15 | const unsigned char port; 16 | const bool inverted; 17 | }; 18 | 19 | inline namespace literals { 20 | constexpr Potentiometer operator"" _p(const unsigned long long int p) { return Potentiometer(static_cast(p), false); } 21 | constexpr Potentiometer operator"" _ip(const unsigned long long int p) { return Potentiometer(static_cast(p), true); } 22 | } 23 | } 24 | 25 | #endif /* end of include guard: OKAPI_POTENTIOMETER */ -------------------------------------------------------------------------------- /include/device/quadEncoder.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_QUADENCODER 2 | #define OKAPI_QUADENCODER 3 | 4 | #include "device/rotarySensor.h" 5 | #include "PAL/PAL.h" 6 | 7 | namespace okapi { 8 | class QuadEncoder : public RotarySensor { 9 | public: 10 | QuadEncoder(const unsigned char iportTop, const unsigned char iportBottom, const bool ireversed = false): 11 | enc(encoderInit(iportTop, iportBottom, ireversed)) {} 12 | 13 | int get() override { return PAL::encoderGet(enc); } 14 | void reset() override { PAL::encoderReset(enc); } 15 | private: 16 | const Encoder enc; 17 | }; 18 | } 19 | 20 | #endif /* end of include guard: OKAPI_QUADENCODER */ 21 | -------------------------------------------------------------------------------- /include/device/rangeFinder.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_RANGEFINDER 2 | #define OKAPI_RANGEFINDER 3 | 4 | #include 5 | #include "PAL/PAL.h" 6 | 7 | namespace okapi { 8 | class RangeFinder { 9 | public: 10 | RangeFinder(const unsigned char iportTop, const unsigned char iportBottom): 11 | ultra(ultrasonicInit(iportTop, iportBottom)), 12 | vals{0}, 13 | index(0) {} 14 | 15 | int get() { 16 | const int val = PAL::ultrasonicGet(ultra); 17 | vals[index++ % len] = val; 18 | return val; 19 | } 20 | 21 | int getFiltered() { 22 | const int val = PAL::ultrasonicGet(ultra); 23 | vals[index++ % len] = val; 24 | 25 | sort(0, 1, index); 26 | sort(3, 4, index); 27 | sort(0, 3, index); 28 | sort(1, 4, index); 29 | sort(1, 2, index); 30 | sort(2, 3, index); 31 | sort(1, 2, index); 32 | 33 | return vals[2]; 34 | } 35 | private: 36 | const Ultrasonic ultra; 37 | static constexpr size_t len = 5; 38 | std::array vals; 39 | size_t index; 40 | 41 | void sort(const size_t a, const size_t b, size_t& index) { 42 | if (vals[a] > vals[b]) { 43 | if (index % len == a) 44 | index = a; 45 | 46 | const int temp = vals[a]; 47 | vals[a] = vals[b]; 48 | vals[b] = temp; 49 | } 50 | } 51 | }; 52 | } 53 | 54 | #endif /* end of include guard: OKAPI_RANGEFINDER */ 55 | -------------------------------------------------------------------------------- /include/device/rotarySensor.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ROTARYSENSOR 2 | #define OKAPI_ROTARYSENSOR 3 | 4 | namespace okapi { 5 | class RotarySensor { 6 | public: 7 | /** 8 | * Return the current sensor value 9 | */ 10 | virtual int get() = 0; 11 | 12 | /** 13 | * Reset the sensor value to zero 14 | */ 15 | virtual void reset() = 0; 16 | }; 17 | } 18 | 19 | #endif /* end of include guard: OKAPI_ROTARYSENSOR */ 20 | -------------------------------------------------------------------------------- /include/filter/avgFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_AVGFILTER 2 | #define OKAPI_AVGFILTER 3 | 4 | #include 5 | #include 6 | #include "filter/filter.h" 7 | 8 | namespace okapi { 9 | template 10 | class AvgFilter final : public Filter { 11 | public: 12 | AvgFilter(): 13 | data(), 14 | index(0), 15 | output(0) {} 16 | 17 | virtual ~AvgFilter() { delete &data; } 18 | 19 | float filter(const float ireading) override { 20 | data[index++] = ireading; 21 | if (index > n) 22 | index = 0; 23 | 24 | output = 0.0; 25 | for (size_t i = 0; i < n; i++) 26 | output += data[i]; 27 | output /= (float)n; 28 | 29 | return output; 30 | } 31 | 32 | float getOutput() const override { return output; } 33 | private: 34 | std::array data; 35 | float index, output; 36 | }; 37 | } 38 | 39 | #endif /* end of include guard: OKAPI_AVGFILTER */ 40 | -------------------------------------------------------------------------------- /include/filter/demaFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_DEMAFILTER 2 | #define OKAPI_DEMAFILTER 3 | 4 | #include "filter/filter.h" 5 | 6 | namespace okapi { 7 | class DemaFilter final : public Filter { 8 | public: 9 | DemaFilter(const float ialpha, const float ibeta): 10 | alpha(ialpha), 11 | beta(ibeta), 12 | outputS(0), 13 | lastOutputS(0), 14 | outputB(0), 15 | lastOutputB(0) {} 16 | 17 | virtual ~DemaFilter() = default; 18 | 19 | float filter(const float ireading) override { 20 | outputS = (alpha * ireading) + ((1.0 - alpha) * (lastOutputS + lastOutputB)); 21 | outputB = (beta * (outputS - lastOutputS)) + ((1.0 - beta) * lastOutputB); 22 | lastOutputS = outputS; 23 | lastOutputB = outputB; 24 | return outputS + outputB; 25 | } 26 | 27 | void setGains(const float ialpha, const float ibeta) { 28 | alpha = ialpha; 29 | beta = ibeta; 30 | } 31 | 32 | float getOutput() const override { return outputS + outputB; } 33 | private: 34 | float alpha, beta; 35 | float outputS, lastOutputS; 36 | float outputB, lastOutputB; 37 | }; 38 | } 39 | 40 | #endif /* end of include guard: OKAPI_DEMAFILTER */ 41 | -------------------------------------------------------------------------------- /include/filter/emaFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_EMAFILTER 2 | #define OKAPI_EMAFILTER 3 | 4 | #include "filter/filter.h" 5 | 6 | namespace okapi { 7 | class EmaFilter final : public Filter { 8 | public: 9 | EmaFilter(const float ialpha, const float ibeta): 10 | alpha(ialpha), 11 | beta(ibeta), 12 | output(0), 13 | lastOutput(0) {} 14 | 15 | virtual ~EmaFilter() = default; 16 | 17 | float filter(const float ireading) override { 18 | output = alpha * ireading + (1.0 - alpha) * lastOutput; 19 | lastOutput = output; 20 | return output; 21 | } 22 | 23 | void setGains(const float ialpha, const float ibeta) { 24 | alpha = ialpha; 25 | beta = ibeta; 26 | } 27 | 28 | float getOutput() const override { return output; } 29 | private: 30 | float alpha, beta; 31 | float output, lastOutput; 32 | }; 33 | } 34 | 35 | #endif /* end of include guard: OKAPI_EMAFILTER */ 36 | -------------------------------------------------------------------------------- /include/filter/filter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_FILTER 2 | #define OKAPI_FILTER 3 | 4 | namespace okapi { 5 | class Filter { 6 | public: 7 | Filter() {} 8 | virtual ~Filter() = default; 9 | 10 | /** 11 | * Filters a reading 12 | * @param reading New measurement 13 | * @return Filtered result 14 | */ 15 | virtual float filter(const float ireading) = 0; 16 | 17 | /** 18 | * Returns the previous output from filter 19 | * @return The previous output from filter 20 | */ 21 | virtual float getOutput() const = 0; 22 | }; 23 | } 24 | 25 | #endif /* end of include guard: OKAPI_FILTER */ 26 | -------------------------------------------------------------------------------- /include/main.h: -------------------------------------------------------------------------------- 1 | /** @file main.h 2 | * @brief Header file for global functions 3 | * 4 | * Any experienced C or C++ programmer knows the importance of header files. For those who 5 | * do not, a header file allows multiple files to reference functions in other files without 6 | * necessarily having to see the code (and therefore causing a multiple definition). To make 7 | * a function in "opcontrol.c", "auto.c", "main.c", or any other C file visible to the core 8 | * implementation files, prototype it here. 9 | * 10 | * This file is included by default in the predefined stubs in each VEX Cortex PROS Project. 11 | * 12 | * Copyright (c) 2011-2016, Purdue University ACM SIGBots. 13 | * All rights reserved. 14 | * 15 | * This Source Code Form is subject to the terms of the Mozilla Public 16 | * License, v. 2.0. If a copy of the MPL was not distributed with this 17 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 18 | * 19 | * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be 20 | * obtained from http://sourceforge.net/projects/freertos/files/ or on request. 21 | */ 22 | 23 | #ifndef MAIN_H_ 24 | 25 | // This prevents multiple inclusion, which isn't bad for this file but is good practice 26 | #define MAIN_H_ 27 | 28 | #include 29 | 30 | // Allow usage of this file in C++ programs 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | // A function prototype looks exactly like its declaration, but with a semicolon instead of 36 | // actual code. If a function does not match a prototype, compile errors will occur. 37 | 38 | // Prototypes for initialization, operator control and autonomous 39 | 40 | /** 41 | * Runs the user autonomous code. This function will be started in its own task with the default 42 | * priority and stack size whenever the robot is enabled via the Field Management System or the 43 | * VEX Competition Switch in the autonomous mode. If the robot is disabled or communications is 44 | * lost, the autonomous task will be stopped by the kernel. Re-enabling the robot will restart 45 | * the task, not re-start it from where it left off. 46 | * 47 | * Code running in the autonomous task cannot access information from the VEX Joystick. However, 48 | * the autonomous function can be invoked from another task if a VEX Competition Switch is not 49 | * available, and it can access joystick information if called in this way. 50 | * 51 | * The autonomous task may exit, unlike operatorControl() which should never exit. If it does 52 | * so, the robot will await a switch to another mode or disable/enable cycle. 53 | */ 54 | void autonomous(); 55 | /** 56 | * Runs pre-initialization code. This function will be started in kernel mode one time while the 57 | * VEX Cortex is starting up. As the scheduler is still paused, most API functions will fail. 58 | * 59 | * The purpose of this function is solely to set the default pin modes (pinMode()) and port 60 | * states (digitalWrite()) of limit switches, push buttons, and solenoids. It can also safely 61 | * configure a UART port (usartOpen()) but cannot set up an LCD (lcdInit()). 62 | */ 63 | void initializeIO(); 64 | /** 65 | * Runs user initialization code. This function will be started in its own task with the default 66 | * priority and stack size once when the robot is starting up. It is possible that the VEXnet 67 | * communication link may not be fully established at this time, so reading from the VEX 68 | * Joystick may fail. 69 | * 70 | * This function should initialize most sensors (gyro, encoders, ultrasonics), LCDs, global 71 | * variables, and IMEs. 72 | * 73 | * This function must exit relatively promptly, or the operatorControl() and autonomous() tasks 74 | * will not start. An autonomous mode selection menu like the pre_auton() in other environments 75 | * can be implemented in this task if desired. 76 | */ 77 | void initialize(); 78 | /** 79 | * Runs the user operator control code. This function will be started in its own task with the 80 | * default priority and stack size whenever the robot is enabled via the Field Management System 81 | * or the VEX Competition Switch in the operator control mode. If the robot is disabled or 82 | * communications is lost, the operator control task will be stopped by the kernel. Re-enabling 83 | * the robot will restart the task, not resume it from where it left off. 84 | * 85 | * If no VEX Competition Switch or Field Management system is plugged in, the VEX Cortex will 86 | * run the operator control task. Be warned that this will also occur if the VEX Cortex is 87 | * tethered directly to a computer via the USB A to A cable without any VEX Joystick attached. 88 | * 89 | * Code running in this task can take almost any action, as the VEX Joystick is available and 90 | * the scheduler is operational. However, proper use of delay() or taskDelayUntil() is highly 91 | * recommended to give other tasks (including system tasks such as updating LCDs) time to run. 92 | * 93 | * This task should never exit; it should end with some kind of infinite loop, even if empty. 94 | */ 95 | void operatorControl(); 96 | 97 | // End C++ export structure 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /include/odometry/odomMath.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ODOMMATH 2 | #define OKAPI_ODOMMATH 3 | 4 | #include 5 | #include "odometry/odometry.h" 6 | 7 | namespace okapi { 8 | class DistanceAndAngle { 9 | public: 10 | DistanceAndAngle(const float ilength, const float itheta): 11 | length(ilength), 12 | theta(itheta) {} 13 | 14 | DistanceAndAngle(): 15 | length(0), 16 | theta(0) {} 17 | 18 | virtual ~DistanceAndAngle() = default; 19 | 20 | float length, theta; 21 | }; 22 | 23 | class OdomMath { 24 | public: 25 | /** 26 | * Computes the distance from the given Odometry state to the given point 27 | * @param ix X coordinate 28 | * @param iy Y coordinate 29 | * @param istate Odometry state 30 | * @return Distance between the points 31 | */ 32 | static float computeDistanceToPoint(const float ix, const float iy, const OdomState& istate); 33 | 34 | /** 35 | * Computes the angle from the given Odometry state to the given point 36 | * @param ix X coordinate 37 | * @param iy Y coordinate 38 | * @param istate Odometry state 39 | * @return Angle to the point 40 | */ 41 | static float computeAngleToPoint(const float ix, const float iy, const OdomState& istate); 42 | 43 | /** 44 | * Computes the distance and angle from the given Odometry state to the given point 45 | * @param ix X coordinate 46 | * @param iy Y coordinate 47 | * @param istate Odometry state 48 | * @return Distance and angle to the point 49 | */ 50 | static DistanceAndAngle computeDistanceAndAngleToPoint(const float ix, const float iy, const OdomState& istate); 51 | 52 | /** 53 | * Attempt to guess scales based on robot dimensions 54 | * @param chassisDiam Center-to-center wheelbase diameter in inches 55 | * @param wheelDiam Edge-to-edge wheel diameter in inches 56 | * @param ticksPerRev Quad ticks per revolution (default is 360) 57 | */ 58 | static std::tuple guessScales(const float chassisDiam, const float wheelDiam, const float ticksPerRev = 360.0); 59 | private: 60 | OdomMath() {} 61 | }; 62 | } 63 | 64 | #endif /* end of include guard: OKAPI_ODOMMATH */ 65 | -------------------------------------------------------------------------------- /include/odometry/odometry.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ODOMETRY 2 | #define OKAPI_ODOMETRY 3 | 4 | #include "chassis/chassisModel.h" 5 | #include 6 | #include 7 | 8 | namespace okapi { 9 | class OdomState { 10 | public: 11 | OdomState(const float ix, const float iy, const float itheta): 12 | x(ix), 13 | y(iy), 14 | theta(itheta) {} 15 | 16 | OdomState(): 17 | x(0), 18 | y(0), 19 | theta(0) {} 20 | 21 | virtual ~OdomState() = default; 22 | 23 | float x, y, theta; 24 | }; 25 | 26 | class OdomParams { 27 | public: 28 | OdomParams(const ChassisModelParams& iparams, const float iscale, const float iturnScale): 29 | model(iparams.make()), 30 | scale(iscale), 31 | turnScale(iturnScale) {} 32 | 33 | virtual ~OdomParams() = default; 34 | 35 | std::shared_ptr model; 36 | float scale, turnScale; 37 | }; 38 | 39 | class Odometry { 40 | public: 41 | Odometry(const ChassisModelParams& imodelParams, const float iscale, const float iturnScale): 42 | model(imodelParams.make()), 43 | scale(iscale), 44 | turnScale(iturnScale), 45 | lastTicks{0, 0}, 46 | mm(0) {} 47 | 48 | Odometry(const OdomParams& iparams): 49 | model(iparams.model), 50 | scale(iparams.scale), 51 | turnScale(iparams.turnScale), 52 | lastTicks{0, 0}, 53 | mm(0) {} 54 | 55 | /** 56 | * Sets the parameters for Odometry math 57 | * @param iparams Odometry parameters 58 | */ 59 | void setParams(OdomParams& iparams) { 60 | model = iparams.model; 61 | scale = iparams.scale; 62 | turnScale = iparams.turnScale; 63 | } 64 | 65 | /** 66 | * Set the drive and turn scales 67 | * @param iscale Scale converting encoder ticks to mm 68 | * @param iturnScale Scale converting encoder ticks to radians 69 | */ 70 | void setScales(const float iscale, const float iturnScale) { 71 | scale = iscale; 72 | turnScale = iturnScale; 73 | } 74 | 75 | /** 76 | * Do odom math in an infinite loop 77 | */ 78 | void loop(); 79 | 80 | static void trampoline(void *context) { static_cast(context)->loop(); } 81 | 82 | OdomState getState() { return state; } 83 | private: 84 | std::shared_ptr model; 85 | OdomState state; 86 | float scale, turnScale; 87 | std::valarray lastTicks; 88 | float mm; 89 | }; 90 | } 91 | 92 | #endif /* end of include guard: OKAPI_ODOMETRY */ 93 | -------------------------------------------------------------------------------- /include/util/mathUtil.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_MATHUTIL 2 | #define OKAPI_MATHUTIL 3 | 4 | namespace okapi { 5 | static constexpr float analogInToV = 286.0; 6 | static constexpr float inchToMM = 25.4; 7 | static constexpr float degreeToRadian = 0.01745; 8 | static constexpr float radianToDegree = 57.2958; 9 | static constexpr float imeHighTorTPR = 627.2; 10 | static constexpr float imeHighStrTPR = 392.0; 11 | static constexpr float imeTurboTPR = 261.333; 12 | static constexpr float ime269TPR = 240.448; 13 | static constexpr float quadEncoderTPR = 360.0; 14 | static constexpr float pi = 3.14159265358979323846; 15 | } 16 | 17 | #endif /* end of include guard: OKAPI_MATHUTIL */ 18 | -------------------------------------------------------------------------------- /include/util/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_TIMER 2 | #define OKAPI_TIMER 3 | 4 | #include "PAL/PAL.h" 5 | 6 | namespace okapi { 7 | class Timer { 8 | public: 9 | Timer(): 10 | firstCalled(PAL::millis()), 11 | lastCalled(0), 12 | mark(0), 13 | hardMark(-1), 14 | repeatMark(-1) {} 15 | 16 | /** 17 | * Returns the time passed in ms since the previous call of this function 18 | * @return The time passed in ms since the previous call of this function 19 | */ 20 | unsigned long getDt(); 21 | 22 | /** 23 | * Returns the time the timer was first initialized 24 | * @return The time the timer was first initialized 25 | */ 26 | unsigned long getStartingTime() const; 27 | 28 | /** 29 | * Returns the time since the timer was first initialized 30 | * @return The time since the timer was first initialized 31 | */ 32 | unsigned long getDtFromStart() const; 33 | 34 | /** 35 | * Place a time marker. Placing another marker will overwrite the previous 36 | * one 37 | */ 38 | void placeMark(); 39 | 40 | /** 41 | * Place a hard time marker. Placing another hard marker will not overwrite 42 | * the previous one; instead, call clearHardMark() and then place another 43 | */ 44 | void placeHardMark(); 45 | 46 | /** 47 | * Clears the hard marker 48 | * @return The old hard marker 49 | */ 50 | unsigned long clearHardMark(); 51 | 52 | /** 53 | * Returns the time since the time marker 54 | * @return The time since the time marker 55 | */ 56 | unsigned long getDtFromMark() const; 57 | 58 | /** 59 | * Returns the time since the hard time marker 60 | * @return The time since the hard time marker 61 | */ 62 | unsigned long getDtFromHardMark() const; 63 | 64 | /** 65 | * Returns true when the input time period has passed, then resets. Meant to 66 | * be used in loops to run an action every so many ms without blocking 67 | * @param ms Time period 68 | * @return True when the input time period has passed, false after 69 | * reading true until the period has passed again 70 | */ 71 | bool repeat(unsigned long ms); 72 | private: 73 | long firstCalled, lastCalled, mark, hardMark, repeatMark; //Long so we can use -1 even though millis() returns unsigned long 74 | }; 75 | } 76 | 77 | #endif /* end of include guard: OKAPI_TIMER */ 78 | -------------------------------------------------------------------------------- /okapilib-template/firmware/okapilib.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OkapiLib/OkapiLib-legacy/f2871cb192e99be1ab531178d146fb8723f1a3cb/okapilib-template/firmware/okapilib.a -------------------------------------------------------------------------------- /okapilib-template/include/chassis/chassisController.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_CHASSISCONTROLLER 2 | #define OKAPI_CHASSISCONTROLLER 3 | 4 | #include "chassis/chassisModel.h" 5 | #include "control/pid.h" 6 | #include "odometry/odometry.h" 7 | #include 8 | 9 | namespace okapi { 10 | class ChassisController { 11 | public: 12 | ChassisController(const ChassisModelParams& imodelParams): 13 | model(imodelParams.make()) {} 14 | 15 | ChassisController(const std::shared_ptr& imodel): 16 | model(imodel) {} 17 | 18 | virtual ~ChassisController() = default; 19 | 20 | /** 21 | * Drives the robot straight 22 | * @param itarget Distance to travel 23 | */ 24 | virtual void driveStraight(const int itarget) = 0; 25 | 26 | /** 27 | * Turns the robot clockwise in place 28 | * @param idegTarget Degrees to turn for 29 | */ 30 | virtual void pointTurn(const float idegTarget) = 0; 31 | 32 | //Passed through to internal ChassisModel 33 | void driveForward(const int power) { model->driveForward(power); } 34 | void driveVector(const int distPower, const int anglePower) { model->driveVector(distPower, anglePower); } 35 | void turnClockwise(const int power) { model->turnClockwise(power); } 36 | void stop() { model->stop(); } 37 | void tank(const int leftVal, const int rightVal, const int threshold = 0) { model->tank(leftVal, rightVal, threshold); } 38 | void arcade(int verticalVal, int horizontalVal, const int threshold = 0) { model->arcade(verticalVal, horizontalVal, threshold); } 39 | void left(const int val) { model->left(val); } 40 | void leftTS(const int val) { model->leftTS(val); } 41 | void right(const int val) { model->right(val); } 42 | void rightTS(const int val) { model->rightTS(val); } 43 | std::valarray getSensorVals() { return model->getSensorVals(); } 44 | protected: 45 | std::shared_ptr model; 46 | }; 47 | 48 | class ChassisControllerPid : public virtual ChassisController { 49 | public: 50 | ChassisControllerPid(const ChassisModelParams& imodelParams, const PidParams& idistanceParams, const PidParams& iangleParams): 51 | ChassisController(imodelParams), 52 | distancePid(idistanceParams), 53 | anglePid(iangleParams) {} 54 | 55 | ChassisControllerPid(const std::shared_ptr& imodel, const PidParams& idistanceParams, const PidParams& iangleParams): 56 | ChassisController(imodel), 57 | distancePid(idistanceParams), 58 | anglePid(iangleParams) {} 59 | 60 | virtual ~ChassisControllerPid() { 61 | delete &distancePid; 62 | delete &anglePid; 63 | } 64 | 65 | /** 66 | * Drives the robot straight 67 | * @param itarget Distance to travel 68 | */ 69 | void driveStraight(const int itarget) override; 70 | 71 | /** 72 | * Turns the robot clockwise in place 73 | * @param idegTarget Degrees to turn for 74 | */ 75 | void pointTurn(float idegTarget) override; 76 | protected: 77 | Pid distancePid, anglePid; 78 | }; 79 | } 80 | 81 | #endif /* end of include guard: OKAPI_CHASSISCONTROLLER */ 82 | -------------------------------------------------------------------------------- /okapilib-template/include/chassis/odomChassisController.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ODOMCHASSISCONTROLLER 2 | #define OKAPI_ODOMCHASSISCONTROLLER 3 | 4 | #include "odometry/odometry.h" 5 | #include "chassis/chassisController.h" 6 | 7 | namespace okapi { 8 | class OdomChassisController : public virtual ChassisController { 9 | public: 10 | /** 11 | * Odometry based chassis controller. Spins up a task at the default 12 | * priority plus 1 for odometry when constructed 13 | * @param iparams Odometry parameters for the internal odometry math 14 | */ 15 | OdomChassisController(const OdomParams& iparams): 16 | ChassisController(iparams.model), 17 | odom(iparams) { 18 | taskCreate((TaskCode)Odometry::trampoline, TASK_DEFAULT_STACK_SIZE, &odom, TASK_PRIORITY_DEFAULT + 1); 19 | } 20 | 21 | virtual ~OdomChassisController() = default; 22 | 23 | /** 24 | * Drives the robot straight to a point in the odom frame 25 | * @param ix X coordinate 26 | * @param iy Y coordinate 27 | */ 28 | virtual void driveToPoint(const float ix, const float iy, const bool ibackwards = false, const float ioffset = 0) = 0; 29 | 30 | /** 31 | * Turns the robot to face an angle in the odom frame 32 | * @param iangle Angle to turn to 33 | */ 34 | virtual void turnToAngle(const float iangle) = 0; 35 | 36 | /** 37 | * Passthrough to internal Odometry object 38 | * @return State from internal Odometry object 39 | */ 40 | OdomState getState() { return odom.getState(); } 41 | protected: 42 | static constexpr int moveThreshold = 10; //Minimum length movement 43 | Odometry odom; 44 | }; 45 | 46 | class OdomChassisControllerPid : public OdomChassisController, public ChassisControllerPid { 47 | public: 48 | OdomChassisControllerPid(const OdomParams& params, const PidParams& idistanceParams, const PidParams& iangleParams): 49 | ChassisController(params.model), 50 | OdomChassisController(params), 51 | ChassisControllerPid(params.model, idistanceParams, iangleParams) {} 52 | 53 | virtual ~OdomChassisControllerPid() = default; 54 | 55 | /** 56 | * Drives the robot straight to a point in the odom frame 57 | * @param ix X coordinate 58 | * @param iy Y coordinate 59 | */ 60 | void driveToPoint(const float ix, const float iy, const bool ibackwards = false, const float ioffset = 0) override; 61 | 62 | /** 63 | * Turns the robot to face an angle in the odom frame 64 | * @param iangle Angle to turn to 65 | */ 66 | void turnToAngle(const float iangle) override; 67 | }; 68 | } 69 | 70 | #endif /* end of include guard: OKAPI_ODOMCHASSISCONTROLLER */ 71 | -------------------------------------------------------------------------------- /okapilib-template/include/control/controlObject.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_CONTORLOBJECT 2 | #define OKAPI_CONTORLOBJECT 3 | 4 | namespace okapi { 5 | class ControlObjectParams {}; 6 | 7 | class ControlObject { 8 | public: 9 | virtual ~ControlObject() = default; 10 | 11 | /** 12 | * Do one iteration of the controller 13 | * @param inewReading New measurement 14 | * @return Controller output 15 | */ 16 | virtual float step(const float ireading) = 0; 17 | 18 | /** 19 | * Sets the target for the controller 20 | */ 21 | virtual void setTarget(const float itarget) = 0; 22 | 23 | /** 24 | * Returns the last calculated output of the controller 25 | */ 26 | virtual float getOutput() const = 0; 27 | 28 | /** 29 | * Returns the last error of the controller 30 | */ 31 | virtual float getError() const = 0; 32 | 33 | /** 34 | * Set time between loops in ms 35 | * @param isampleTime Time between loops in ms 36 | */ 37 | virtual void setSampleTime(const int isampleTime); 38 | 39 | /** 40 | * Set controller output bounds 41 | * @param imax Max output 42 | * @param imin Min output 43 | */ 44 | virtual void setOutputLimits(float imax, float imin); 45 | 46 | /** 47 | * Resets the controller so it can start from 0 again properly. Keeps 48 | * configuration from before 49 | */ 50 | virtual void reset(); 51 | 52 | /** 53 | * Turns the controller on or off 54 | */ 55 | virtual void flipDisable(); 56 | }; 57 | } 58 | 59 | #endif /* OKAPI_CONTROLOBJECT */ 60 | -------------------------------------------------------------------------------- /okapilib-template/include/control/genericController.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_GENERICCONTROLLER 2 | #define OKAPI_GENERICCONTROLLER 3 | 4 | #include 5 | #include 6 | #include "control/controlObject.h" 7 | #include "device/motor.h" 8 | 9 | namespace okapi { 10 | template 11 | class GenericController { 12 | public: 13 | GenericController(const std::array &imotorList, const std::shared_ptr &iptr): 14 | motors(imotorList), 15 | controller(iptr) {} 16 | 17 | void step(const float ireading) { 18 | controller->step(ireading); 19 | for (size_t i = 0; i < motors.size(); i++) 20 | motors[i].setTS(static_cast(controller->getOutput())); 21 | } 22 | 23 | void setTarget(const float itarget) { controller->setTarget(itarget); } 24 | 25 | void getOutput() const { return controller->getOutput(); } 26 | 27 | void setSampleTime(const int isampleTime) { controller->setSampleTime(isampleTime); } 28 | 29 | void setOutputLimits(float imax, float imin) { controller->setOutputLimits(imax, imin); } 30 | 31 | void reset() { controller->reset(); } 32 | 33 | void flipDisable() { controller->flipDisable(); } 34 | private: 35 | std::array motors; 36 | std::shared_ptr controller; 37 | }; 38 | } 39 | 40 | #endif /* OKAPI_GENERICCONTROLLER */ 41 | -------------------------------------------------------------------------------- /okapilib-template/include/control/nsPid.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_NSPID 2 | #define OKAPI_NSPID 3 | 4 | #include "control/pid.h" 5 | #include "control/velMath.h" 6 | 7 | namespace okapi { 8 | class NsPid : public Pid { 9 | public: 10 | NsPid(const PidParams& iparams, const VelMathParams& ivelParams, const float iminVel, const float iscale = 0.1): 11 | Pid::Pid(iparams), 12 | velMath(ivelParams), 13 | minVel(iminVel), 14 | scale(iscale) {} 15 | 16 | /** 17 | * Do one iteration of the controller 18 | * @param inewReading New measurement 19 | * @return Controller output 20 | */ 21 | virtual float step(const float inewReading) override; 22 | protected: 23 | VelMath velMath; 24 | float minVel, scale; 25 | }; 26 | } 27 | 28 | #endif /* end of include guard: OKAPI_NSPID */ 29 | -------------------------------------------------------------------------------- /okapilib-template/include/control/pid.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_PID 2 | #define OKAPI_PID 3 | 4 | #include "control/controlObject.h" 5 | 6 | namespace okapi { 7 | class PidParams : public ControlObjectParams { 8 | public: 9 | PidParams(const float ikP, const float ikI, const float ikD, const float ikBias = 0): 10 | kP(ikP), 11 | kI(ikI), 12 | kD(ikD), 13 | kBias(ikBias) {} 14 | 15 | float kP, kI, kD, kBias; 16 | }; 17 | 18 | class Pid : public ControlObject { 19 | public: 20 | /** 21 | * PID controller 22 | * @param ikP Proportional gain 23 | * @param ikI Integral gain 24 | * @param ikD Derivative gain 25 | * @param ikBias Controller bias (added to final output) 26 | */ 27 | Pid(const float ikP, const float ikI, const float ikD, const float ikBias = 0): 28 | lastTime(0), 29 | sampleTime(15), 30 | error(0), 31 | lastError(0), 32 | target(0), 33 | lastReading(0), 34 | integral(0), 35 | integralMax(127), 36 | integralMin(-127), 37 | output(0), 38 | outputMax(127), 39 | outputMin(-127), 40 | shouldResetOnCross(true), 41 | isOn(true) { 42 | setGains(ikP, ikI, ikD, ikBias); 43 | } 44 | 45 | /** 46 | * PID controller 47 | * @param params Params (see PidParams docs) 48 | */ 49 | Pid(const PidParams& params): 50 | lastTime(0), 51 | sampleTime(15), 52 | error(0), 53 | lastError(0), 54 | target(0), 55 | lastReading(0), 56 | integral(0), 57 | integralMax(127), 58 | integralMin(-127), 59 | output(0), 60 | outputMax(127), 61 | outputMin(-127), 62 | shouldResetOnCross(true), 63 | isOn(true) { 64 | setGains(params.kP, params.kI, params.kD, params.kBias); 65 | } 66 | 67 | virtual ~Pid() = default; 68 | 69 | /** 70 | * Do one iteration of the controller 71 | * @param inewReading New measurement 72 | * @return Controller output 73 | */ 74 | virtual float step(const float inewReading) override; 75 | 76 | void setTarget(const float itarget) override { target = itarget; } 77 | 78 | float getOutput() const override { return output; } 79 | 80 | float getError() const override { return error; } 81 | 82 | /** 83 | * Set controller gains 84 | * @param ikP Proportional gain 85 | * @param ikI Integral gain 86 | * @param ikD Derivative gain 87 | * @param ikBias Controller bias 88 | */ 89 | void setGains(const float ikP, const float ikI, const float ikD, const float ikBias = 0); 90 | 91 | /** 92 | * Set time between loops in ms 93 | * @param isampleTime Time between loops in ms 94 | */ 95 | void setSampleTime(const int isampleTime) override; 96 | 97 | /** 98 | * Set controller output bounds 99 | * @param imax Max output 100 | * @param imin Min output 101 | */ 102 | void setOutputLimits(float imax, float imin) override; 103 | 104 | /** 105 | * Set integrator bounds 106 | * @param imax Max integrator value 107 | * @param imin Min integrator value 108 | */ 109 | void setIntegralLimits(float imax, float imin); 110 | 111 | /** 112 | * Resets the controller so it can start from 0 again properly. Keeps gains 113 | * and limits from before 114 | */ 115 | void reset() override; 116 | 117 | /** 118 | * Set whether the integrator should be reset when error is 0 or changes sign 119 | * @param iresetOnZero True to reset 120 | */ 121 | void setIntegratorReset(bool iresetOnZero) { shouldResetOnCross = iresetOnZero; } 122 | 123 | void flipDisable() override { isOn = !isOn; } 124 | protected: 125 | float kP, kI, kD, kBias; 126 | long lastTime, sampleTime; 127 | float error, lastError; 128 | float target, lastReading; 129 | float integral, integralMax, integralMin; 130 | float output, outputMax, outputMin; 131 | bool shouldResetOnCross, isOn; 132 | }; 133 | } 134 | 135 | #endif /* end of include guard: OKAPI_PID */ 136 | -------------------------------------------------------------------------------- /okapilib-template/include/control/velMath.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_VELOCITY 2 | #define OKAPI_VELOCITY 3 | 4 | #include "filter/demaFilter.h" 5 | 6 | namespace okapi { 7 | class VelMathParams { 8 | public: 9 | VelMathParams(const float iticksPerRev, const float ialpha = 0.19, const float ibeta = 0.041): 10 | ticksPerRev(iticksPerRev), 11 | alpha(ialpha), 12 | beta(ibeta) {} 13 | 14 | float ticksPerRev, alpha, beta; 15 | }; 16 | 17 | class VelMath { 18 | public: 19 | VelMath(const float iticksPerRev, const float ialpha = 0.19, const float ibeta = 0.041): 20 | lastTime(0), 21 | vel(0), 22 | lastVel(0), 23 | lastPos(0), 24 | ticksPerRev(iticksPerRev), 25 | filter(ialpha, ibeta) {} 26 | 27 | VelMath(const VelMathParams& iparams): 28 | lastTime(0), 29 | vel(0), 30 | lastVel(0), 31 | lastPos(0), 32 | ticksPerRev(iparams.ticksPerRev), 33 | filter(iparams.alpha, iparams.beta) {} 34 | 35 | /** 36 | * Calculate new velocity 37 | * @param inewPos New position 38 | * @return New velocity 39 | */ 40 | float step(const float inewPos); 41 | 42 | void setGains(const float ialpha, const float ibeta) { filter.setGains(ialpha, ibeta); } 43 | 44 | void setTicksPerRev(const float iTPR) { ticksPerRev = iTPR; } 45 | 46 | float getOutput() const { return vel; } 47 | 48 | float getDiff() const { return vel - lastVel; } 49 | private: 50 | long lastTime; 51 | float vel, lastVel, lastPos, ticksPerRev; 52 | DemaFilter filter; 53 | }; 54 | } 55 | 56 | #endif /* end of include guard: OKAPI_VELOCITY */ 57 | -------------------------------------------------------------------------------- /okapilib-template/include/control/velPid.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_VELPID 2 | #define OKAPI_VELPID 3 | 4 | #include "control/velMath.h" 5 | #include "control/controlObject.h" 6 | 7 | namespace okapi { 8 | class VelPidParams : public ControlObjectParams { 9 | public: 10 | VelPidParams(const float ikP, const float ikD): 11 | kP(ikP), 12 | kD(ikD) {} 13 | 14 | float kP, kD; 15 | }; 16 | 17 | class VelPid : public ControlObject { 18 | public: 19 | /** 20 | * Velocity PID controller 21 | * @param ikP Proportional gain 22 | * @param ikD Derivative gain 23 | */ 24 | VelPid(const float ikP, const float ikD): 25 | lastTime(0), 26 | sampleTime(15), 27 | error(0), 28 | lastError(0), 29 | target(0), 30 | output(0), 31 | outputMax(127), 32 | outputMin(-127), 33 | isOn(true), 34 | velMath(360) { 35 | setGains(ikP, ikD); 36 | } 37 | 38 | /** 39 | * Velocity PID controller 40 | * @param params Params (see VelPidParams docs) 41 | */ 42 | VelPid(const VelPidParams& params): 43 | lastTime(0), 44 | sampleTime(15), 45 | error(0), 46 | lastError(0), 47 | target(0), 48 | output(0), 49 | outputMax(127), 50 | outputMin(-127), 51 | isOn(true), 52 | velMath(360) { 53 | setGains(params.kP, params.kD); 54 | } 55 | 56 | virtual ~VelPid() = default; 57 | 58 | /** 59 | * Do one iteration of velocity calculation 60 | * @param inewReading New measurement 61 | * @return Filtered velocity 62 | */ 63 | virtual float stepVel(const float inewReading); 64 | 65 | /** 66 | * Do one iteration of the controller 67 | * @param inewReading New measurement 68 | * @return Controller output 69 | */ 70 | virtual float step(const float inewReading) override; 71 | 72 | void setTarget(const float itarget) override { target = itarget; } 73 | 74 | float getOutput() const override { return isOn ? output : 0; } 75 | 76 | float getError() const override { return error; } 77 | 78 | /** 79 | * Set time between loops in ms 80 | * @param isampleTime Time between loops in ms 81 | */ 82 | void setSampleTime(const int isampleTime) override; 83 | 84 | /** 85 | * Set controller output bounds 86 | * @param imax Max output 87 | * @param imin Min output 88 | */ 89 | void setOutputLimits(float imax, float imin) override; 90 | 91 | void reset() override; 92 | 93 | void flipDisable() override { isOn = !isOn; } 94 | 95 | /** 96 | * Set controller gains 97 | * @param ikP Proportional gain 98 | * @param ikD Derivative gain 99 | * @param ikBias Controller bias 100 | */ 101 | void setGains(const float ikP, const float ikD); 102 | 103 | /** 104 | * Set the gains for the double moving average filter. Defaults are 0.19 and 0.0526, respectively 105 | * @param alpha Alpha gain 106 | * @param beta Beta gain 107 | */ 108 | void setFilterGains(const float alpha, const float beta) { velMath.setGains(alpha, beta); } 109 | 110 | /** 111 | * Set the number of measurements per revolution. Default is 360 112 | * @param tpr Number of measured units per revolution 113 | */ 114 | void setTicksPerRev(const float tpr) { velMath.setTicksPerRev(tpr); } 115 | 116 | float getVel() const { return velMath.getOutput(); } 117 | 118 | private: 119 | float kP, kD; 120 | long lastTime, sampleTime; 121 | float error, lastError; 122 | float target; 123 | float output, outputMax, outputMin; 124 | bool isOn; 125 | VelMath velMath; 126 | }; 127 | } 128 | 129 | #endif /* end of include guard: OKAPI_VELPID */ 130 | -------------------------------------------------------------------------------- /okapilib-template/include/device/button.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_BUTTON 2 | #define OKAPI_BUTTON 3 | 4 | #include "PAL/PAL.h" 5 | 6 | namespace okapi { 7 | class Button { 8 | public: 9 | explicit constexpr Button(const unsigned char iport, const bool iinverted = false): 10 | joystick(1), 11 | buttonGroup(8), 12 | port(iport), 13 | lcd(uart1), 14 | inverted(iinverted), 15 | isJoystick(false), 16 | isLCD(false), 17 | wasPressedLast(iinverted) {} 18 | 19 | explicit constexpr Button(const unsigned char ijoystick, const unsigned char ibuttonGroup, const unsigned char ibutton, const bool iinverted = false): 20 | joystick(ijoystick), 21 | buttonGroup(ibuttonGroup), 22 | port(ibutton), 23 | lcd(uart1), 24 | inverted(iinverted), 25 | isJoystick(true), 26 | isLCD(false), 27 | wasPressedLast(iinverted) {} 28 | 29 | explicit constexpr Button(PROS_FILE* ilcdPort, const unsigned char ilcdButton, const bool iinverted = false): 30 | joystick(1), 31 | buttonGroup(8), 32 | port(ilcdButton), 33 | lcd(ilcdPort), 34 | inverted(iinverted), 35 | isJoystick(false), 36 | isLCD(true), 37 | wasPressedLast(iinverted) {} 38 | 39 | bool isPressed() const { 40 | if (isJoystick) 41 | return inverted ? !PAL::joystickGetDigital(joystick, buttonGroup, port) : PAL::joystickGetDigital(joystick, buttonGroup, port); 42 | else if (isLCD) 43 | return inverted ? !(PAL::lcdReadButtons(lcd) == port) : (PAL::lcdReadButtons(lcd) == port); 44 | else 45 | return inverted ? !PAL::digitalRead(port) : PAL::digitalRead(port); 46 | } 47 | 48 | bool edge() { 49 | const bool pressed = isPressed(); 50 | const bool out = pressed ^ wasPressedLast; 51 | wasPressedLast = pressed; 52 | return out; 53 | } 54 | 55 | bool risingEdge() { return edge() && wasPressedLast; } //Remember edge sets wasPressedLast 56 | 57 | bool fallingEdge() { return edge() && !wasPressedLast; } //Remember edge sets wasPressedLast 58 | private: 59 | const unsigned char joystick, buttonGroup, port; 60 | PROS_FILE *lcd; 61 | const bool inverted, isJoystick, isLCD; 62 | bool wasPressedLast; 63 | }; 64 | 65 | inline namespace literals { 66 | constexpr Button operator"" _b(const unsigned long long int p) { return Button(static_cast(p), false); } 67 | constexpr Button operator"" _ib(const unsigned long long int p) { return Button(static_cast(p), true); } 68 | } 69 | } 70 | 71 | #endif /* end of include guard: OKAPI_BUTTON */ 72 | -------------------------------------------------------------------------------- /okapilib-template/include/device/ime.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_IME 2 | #define OKAPI_IME 3 | 4 | #include "device/rotarySensor.h" 5 | #include "PAL/PAL.h" 6 | 7 | namespace okapi { 8 | class IME : public RotarySensor { 9 | public: 10 | explicit constexpr IME(const unsigned char iindex): 11 | index(iindex), 12 | reversed(1), 13 | val(0) {} 14 | 15 | explicit constexpr IME(const unsigned char iindex, const bool ireversed): 16 | index(iindex), 17 | reversed(ireversed ? -1 : 1), 18 | val(0) {} 19 | 20 | int get() override { PAL::imeGet(index, &val); return reversed * val; } 21 | void reset() override { PAL::imeReset(index); } 22 | private: 23 | unsigned char index; 24 | const int reversed; 25 | int val; 26 | }; 27 | 28 | inline namespace literals { 29 | constexpr IME operator"" _ime(const unsigned long long int p) { return IME(static_cast(p), false); } 30 | constexpr IME operator"" _rime(const unsigned long long int p) { return IME(static_cast(p), true); } 31 | } 32 | } 33 | 34 | #endif /* end of include guard: OKAPI_IME */ 35 | -------------------------------------------------------------------------------- /okapilib-template/include/device/potentiometer.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_POTENTIOMETER 2 | #define OKAPI_POTENTIOMETER 3 | 4 | #include "PAL/PAL.h" 5 | 6 | namespace okapi { 7 | class Potentiometer { 8 | public: 9 | explicit constexpr Potentiometer(const unsigned char iport, const bool iinverted = false): 10 | port(iport), 11 | inverted(iinverted) {} 12 | 13 | int get() const { return inverted ? 4095 - PAL::analogRead(port) : PAL::analogRead(port); } 14 | private: 15 | const unsigned char port; 16 | const bool inverted; 17 | }; 18 | 19 | inline namespace literals { 20 | constexpr Potentiometer operator"" _p(const unsigned long long int p) { return Potentiometer(static_cast(p), false); } 21 | constexpr Potentiometer operator"" _ip(const unsigned long long int p) { return Potentiometer(static_cast(p), true); } 22 | } 23 | } 24 | 25 | #endif /* end of include guard: OKAPI_POTENTIOMETER */ -------------------------------------------------------------------------------- /okapilib-template/include/device/quadEncoder.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_QUADENCODER 2 | #define OKAPI_QUADENCODER 3 | 4 | #include "device/rotarySensor.h" 5 | #include "PAL/PAL.h" 6 | 7 | namespace okapi { 8 | class QuadEncoder : public RotarySensor { 9 | public: 10 | QuadEncoder(const unsigned char iportTop, const unsigned char iportBottom, const bool ireversed = false): 11 | enc(encoderInit(iportTop, iportBottom, ireversed)) {} 12 | 13 | int get() override { return PAL::encoderGet(enc); } 14 | void reset() override { PAL::encoderReset(enc); } 15 | private: 16 | const Encoder enc; 17 | }; 18 | } 19 | 20 | #endif /* end of include guard: OKAPI_QUADENCODER */ 21 | -------------------------------------------------------------------------------- /okapilib-template/include/device/rangeFinder.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_RANGEFINDER 2 | #define OKAPI_RANGEFINDER 3 | 4 | #include 5 | #include "PAL/PAL.h" 6 | 7 | namespace okapi { 8 | class RangeFinder { 9 | public: 10 | RangeFinder(const unsigned char iportTop, const unsigned char iportBottom): 11 | ultra(ultrasonicInit(iportTop, iportBottom)), 12 | vals{0}, 13 | index(0) {} 14 | 15 | int get() { 16 | const int val = PAL::ultrasonicGet(ultra); 17 | vals[index++ % len] = val; 18 | return val; 19 | } 20 | 21 | int getFiltered() { 22 | const int val = PAL::ultrasonicGet(ultra); 23 | vals[index++ % len] = val; 24 | 25 | sort(0, 1, index); 26 | sort(3, 4, index); 27 | sort(0, 3, index); 28 | sort(1, 4, index); 29 | sort(1, 2, index); 30 | sort(2, 3, index); 31 | sort(1, 2, index); 32 | 33 | return vals[2]; 34 | } 35 | private: 36 | const Ultrasonic ultra; 37 | static constexpr size_t len = 5; 38 | std::array vals; 39 | size_t index; 40 | 41 | void sort(const size_t a, const size_t b, size_t& index) { 42 | if (vals[a] > vals[b]) { 43 | if (index % len == a) 44 | index = a; 45 | 46 | const int temp = vals[a]; 47 | vals[a] = vals[b]; 48 | vals[b] = temp; 49 | } 50 | } 51 | }; 52 | } 53 | 54 | #endif /* end of include guard: OKAPI_RANGEFINDER */ 55 | -------------------------------------------------------------------------------- /okapilib-template/include/device/rotarySensor.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ROTARYSENSOR 2 | #define OKAPI_ROTARYSENSOR 3 | 4 | namespace okapi { 5 | class RotarySensor { 6 | public: 7 | /** 8 | * Return the current sensor value 9 | */ 10 | virtual int get() = 0; 11 | 12 | /** 13 | * Reset the sensor value to zero 14 | */ 15 | virtual void reset() = 0; 16 | }; 17 | } 18 | 19 | #endif /* end of include guard: OKAPI_ROTARYSENSOR */ 20 | -------------------------------------------------------------------------------- /okapilib-template/include/filter/avgFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_AVGFILTER 2 | #define OKAPI_AVGFILTER 3 | 4 | #include 5 | #include 6 | #include "filter/filter.h" 7 | 8 | namespace okapi { 9 | template 10 | class AvgFilter final : public Filter { 11 | public: 12 | AvgFilter(): 13 | data(), 14 | index(0), 15 | output(0) {} 16 | 17 | virtual ~AvgFilter() { delete &data; } 18 | 19 | float filter(const float ireading) override { 20 | data[index++] = ireading; 21 | if (index > n) 22 | index = 0; 23 | 24 | output = 0.0; 25 | for (size_t i = 0; i < n; i++) 26 | output += data[i]; 27 | output /= (float)n; 28 | 29 | return output; 30 | } 31 | 32 | float getOutput() const override { return output; } 33 | private: 34 | std::array data; 35 | float index, output; 36 | }; 37 | } 38 | 39 | #endif /* end of include guard: OKAPI_AVGFILTER */ 40 | -------------------------------------------------------------------------------- /okapilib-template/include/filter/demaFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_DEMAFILTER 2 | #define OKAPI_DEMAFILTER 3 | 4 | #include "filter/filter.h" 5 | 6 | namespace okapi { 7 | class DemaFilter final : public Filter { 8 | public: 9 | DemaFilter(const float ialpha, const float ibeta): 10 | alpha(ialpha), 11 | beta(ibeta), 12 | outputS(0), 13 | lastOutputS(0), 14 | outputB(0), 15 | lastOutputB(0) {} 16 | 17 | virtual ~DemaFilter() = default; 18 | 19 | float filter(const float ireading) override { 20 | outputS = (alpha * ireading) + ((1.0 - alpha) * (lastOutputS + lastOutputB)); 21 | outputB = (beta * (outputS - lastOutputS)) + ((1.0 - beta) * lastOutputB); 22 | lastOutputS = outputS; 23 | lastOutputB = outputB; 24 | return outputS + outputB; 25 | } 26 | 27 | void setGains(const float ialpha, const float ibeta) { 28 | alpha = ialpha; 29 | beta = ibeta; 30 | } 31 | 32 | float getOutput() const override { return outputS + outputB; } 33 | private: 34 | float alpha, beta; 35 | float outputS, lastOutputS; 36 | float outputB, lastOutputB; 37 | }; 38 | } 39 | 40 | #endif /* end of include guard: OKAPI_DEMAFILTER */ 41 | -------------------------------------------------------------------------------- /okapilib-template/include/filter/emaFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_EMAFILTER 2 | #define OKAPI_EMAFILTER 3 | 4 | #include "filter/filter.h" 5 | 6 | namespace okapi { 7 | class EmaFilter final : public Filter { 8 | public: 9 | EmaFilter(const float ialpha, const float ibeta): 10 | alpha(ialpha), 11 | beta(ibeta), 12 | output(0), 13 | lastOutput(0) {} 14 | 15 | virtual ~EmaFilter() = default; 16 | 17 | float filter(const float ireading) override { 18 | output = alpha * ireading + (1.0 - alpha) * lastOutput; 19 | lastOutput = output; 20 | return output; 21 | } 22 | 23 | void setGains(const float ialpha, const float ibeta) { 24 | alpha = ialpha; 25 | beta = ibeta; 26 | } 27 | 28 | float getOutput() const override { return output; } 29 | private: 30 | float alpha, beta; 31 | float output, lastOutput; 32 | }; 33 | } 34 | 35 | #endif /* end of include guard: OKAPI_EMAFILTER */ 36 | -------------------------------------------------------------------------------- /okapilib-template/include/filter/filter.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_FILTER 2 | #define OKAPI_FILTER 3 | 4 | namespace okapi { 5 | class Filter { 6 | public: 7 | Filter() {} 8 | virtual ~Filter() = default; 9 | 10 | /** 11 | * Filters a reading 12 | * @param reading New measurement 13 | * @return Filtered result 14 | */ 15 | virtual float filter(const float ireading) = 0; 16 | 17 | /** 18 | * Returns the previous output from filter 19 | * @return The previous output from filter 20 | */ 21 | virtual float getOutput() const = 0; 22 | }; 23 | } 24 | 25 | #endif /* end of include guard: OKAPI_FILTER */ 26 | -------------------------------------------------------------------------------- /okapilib-template/include/odometry/odomMath.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ODOMMATH 2 | #define OKAPI_ODOMMATH 3 | 4 | #include 5 | #include "odometry/odometry.h" 6 | 7 | namespace okapi { 8 | class DistanceAndAngle { 9 | public: 10 | DistanceAndAngle(const float ilength, const float itheta): 11 | length(ilength), 12 | theta(itheta) {} 13 | 14 | DistanceAndAngle(): 15 | length(0), 16 | theta(0) {} 17 | 18 | virtual ~DistanceAndAngle() = default; 19 | 20 | float length, theta; 21 | }; 22 | 23 | class OdomMath { 24 | public: 25 | /** 26 | * Computes the distance from the given Odometry state to the given point 27 | * @param ix X coordinate 28 | * @param iy Y coordinate 29 | * @param istate Odometry state 30 | * @return Distance between the points 31 | */ 32 | static float computeDistanceToPoint(const float ix, const float iy, const OdomState& istate); 33 | 34 | /** 35 | * Computes the angle from the given Odometry state to the given point 36 | * @param ix X coordinate 37 | * @param iy Y coordinate 38 | * @param istate Odometry state 39 | * @return Angle to the point 40 | */ 41 | static float computeAngleToPoint(const float ix, const float iy, const OdomState& istate); 42 | 43 | /** 44 | * Computes the distance and angle from the given Odometry state to the given point 45 | * @param ix X coordinate 46 | * @param iy Y coordinate 47 | * @param istate Odometry state 48 | * @return Distance and angle to the point 49 | */ 50 | static DistanceAndAngle computeDistanceAndAngleToPoint(const float ix, const float iy, const OdomState& istate); 51 | 52 | /** 53 | * Attempt to guess scales based on robot dimensions 54 | * @param chassisDiam Center-to-center wheelbase diameter in inches 55 | * @param wheelDiam Edge-to-edge wheel diameter in inches 56 | * @param ticksPerRev Quad ticks per revolution (default is 360) 57 | */ 58 | static std::tuple guessScales(const float chassisDiam, const float wheelDiam, const float ticksPerRev = 360.0); 59 | private: 60 | OdomMath() {} 61 | }; 62 | } 63 | 64 | #endif /* end of include guard: OKAPI_ODOMMATH */ 65 | -------------------------------------------------------------------------------- /okapilib-template/include/odometry/odometry.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_ODOMETRY 2 | #define OKAPI_ODOMETRY 3 | 4 | #include "chassis/chassisModel.h" 5 | #include 6 | #include 7 | 8 | namespace okapi { 9 | class OdomState { 10 | public: 11 | OdomState(const float ix, const float iy, const float itheta): 12 | x(ix), 13 | y(iy), 14 | theta(itheta) {} 15 | 16 | OdomState(): 17 | x(0), 18 | y(0), 19 | theta(0) {} 20 | 21 | virtual ~OdomState() = default; 22 | 23 | float x, y, theta; 24 | }; 25 | 26 | class OdomParams { 27 | public: 28 | OdomParams(const ChassisModelParams& iparams, const float iscale, const float iturnScale): 29 | model(iparams.make()), 30 | scale(iscale), 31 | turnScale(iturnScale) {} 32 | 33 | virtual ~OdomParams() = default; 34 | 35 | std::shared_ptr model; 36 | float scale, turnScale; 37 | }; 38 | 39 | class Odometry { 40 | public: 41 | Odometry(const ChassisModelParams& imodelParams, const float iscale, const float iturnScale): 42 | model(imodelParams.make()), 43 | scale(iscale), 44 | turnScale(iturnScale), 45 | lastTicks{0, 0}, 46 | mm(0) {} 47 | 48 | Odometry(const OdomParams& iparams): 49 | model(iparams.model), 50 | scale(iparams.scale), 51 | turnScale(iparams.turnScale), 52 | lastTicks{0, 0}, 53 | mm(0) {} 54 | 55 | /** 56 | * Sets the parameters for Odometry math 57 | * @param iparams Odometry parameters 58 | */ 59 | void setParams(OdomParams& iparams) { 60 | model = iparams.model; 61 | scale = iparams.scale; 62 | turnScale = iparams.turnScale; 63 | } 64 | 65 | /** 66 | * Set the drive and turn scales 67 | * @param iscale Scale converting encoder ticks to mm 68 | * @param iturnScale Scale converting encoder ticks to radians 69 | */ 70 | void setScales(const float iscale, const float iturnScale) { 71 | scale = iscale; 72 | turnScale = iturnScale; 73 | } 74 | 75 | /** 76 | * Do odom math in an infinite loop 77 | */ 78 | void loop(); 79 | 80 | static void trampoline(void *context) { static_cast(context)->loop(); } 81 | 82 | OdomState getState() { return state; } 83 | private: 84 | std::shared_ptr model; 85 | OdomState state; 86 | float scale, turnScale; 87 | std::valarray lastTicks; 88 | float mm; 89 | }; 90 | } 91 | 92 | #endif /* end of include guard: OKAPI_ODOMETRY */ 93 | -------------------------------------------------------------------------------- /okapilib-template/include/util/mathUtil.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_MATHUTIL 2 | #define OKAPI_MATHUTIL 3 | 4 | namespace okapi { 5 | static constexpr float analogInToV = 286.0; 6 | static constexpr float inchToMM = 25.4; 7 | static constexpr float degreeToRadian = 0.01745; 8 | static constexpr float radianToDegree = 57.2958; 9 | static constexpr float imeHighTorTPR = 627.2; 10 | static constexpr float imeHighStrTPR = 392.0; 11 | static constexpr float imeTurboTPR = 261.333; 12 | static constexpr float ime269TPR = 240.448; 13 | static constexpr float quadEncoderTPR = 360.0; 14 | static constexpr float pi = 3.14159265358979323846; 15 | } 16 | 17 | #endif /* end of include guard: OKAPI_MATHUTIL */ 18 | -------------------------------------------------------------------------------- /okapilib-template/include/util/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef OKAPI_TIMER 2 | #define OKAPI_TIMER 3 | 4 | #include "PAL/PAL.h" 5 | 6 | namespace okapi { 7 | class Timer { 8 | public: 9 | Timer(): 10 | firstCalled(PAL::millis()), 11 | lastCalled(0), 12 | mark(0), 13 | hardMark(-1), 14 | repeatMark(-1) {} 15 | 16 | /** 17 | * Returns the time passed in ms since the previous call of this function 18 | * @return The time passed in ms since the previous call of this function 19 | */ 20 | unsigned long getDt(); 21 | 22 | /** 23 | * Returns the time the timer was first initialized 24 | * @return The time the timer was first initialized 25 | */ 26 | unsigned long getStartingTime() const; 27 | 28 | /** 29 | * Returns the time since the timer was first initialized 30 | * @return The time since the timer was first initialized 31 | */ 32 | unsigned long getDtFromStart() const; 33 | 34 | /** 35 | * Place a time marker. Placing another marker will overwrite the previous 36 | * one 37 | */ 38 | void placeMark(); 39 | 40 | /** 41 | * Place a hard time marker. Placing another hard marker will not overwrite 42 | * the previous one; instead, call clearHardMark() and then place another 43 | */ 44 | void placeHardMark(); 45 | 46 | /** 47 | * Clears the hard marker 48 | * @return The old hard marker 49 | */ 50 | unsigned long clearHardMark(); 51 | 52 | /** 53 | * Returns the time since the time marker 54 | * @return The time since the time marker 55 | */ 56 | unsigned long getDtFromMark() const; 57 | 58 | /** 59 | * Returns the time since the hard time marker 60 | * @return The time since the hard time marker 61 | */ 62 | unsigned long getDtFromHardMark() const; 63 | 64 | /** 65 | * Returns true when the input time period has passed, then resets. Meant to 66 | * be used in loops to run an action every so many ms without blocking 67 | * @param ms Time period 68 | * @return True when the input time period has passed, false after 69 | * reading true until the period has passed again 70 | */ 71 | bool repeat(unsigned long ms); 72 | private: 73 | long firstCalled, lastCalled, mark, hardMark, repeatMark; //Long so we can use -1 even though millis() returns unsigned long 74 | }; 75 | } 76 | 77 | #endif /* end of include guard: OKAPI_TIMER */ 78 | -------------------------------------------------------------------------------- /okapilib-template/template.pros: -------------------------------------------------------------------------------- 1 | {"py/object": "prosconductor.providers.TemplateConfig", "py/state": {"depot": null, "name": "okapilib", "remove_paths": [], "template_ignore": ["template.pros"], "upgrade_paths": ["firmware/okapilib.a", "include/main.h", "include/device/motor.h", "include/device/button.h", "include/device/ime.h", "include/device/potentiometer.h", "include/device/quadEncoder.h", "include/device/rangeFinder.h", "include/device/rotarySensor.h", "include/chassis/chassisModel.h", "include/chassis/odomChassisController.h", "include/chassis/chassisController.h", "include/API.h", "include/util/timer.h", "include/util/mathUtil.h", "include/odometry/odomMath.h", "include/odometry/odometry.h", "include/filter/filter.h", "include/filter/emaFilter.h", "include/filter/avgFilter.h", "include/filter/demaFilter.h", "include/control/pid.h", "include/control/genericController.h", "include/control/velMath.h", "include/control/nsPid.h", "include/control/velPid.h", "include/control/controlObject.h"], "version": "0.5.1"}} -------------------------------------------------------------------------------- /project.pros: -------------------------------------------------------------------------------- 1 | {"py/object": "prosconfig.ProjectConfig", "py/state": {"kernel": "2.12.1", "libraries": [], "output": "bin/output.bin"}} -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for compiling PROS projects 2 | 3 | # Path to project root (NO trailing slash!) 4 | ROOT=.. 5 | # Binary output directory 6 | BINDIR=$(ROOT)/bin 7 | 8 | # Nothing below here needs to be modified by typical users 9 | 10 | # Include common aspects of this project 11 | -include $(ROOT)/common.mk 12 | 13 | ASMSRC:=$(wildcard *.$(ASMEXT)) 14 | ASMOBJ:=$(patsubst %.o,$(BINDIR)/%.o,$(ASMSRC:.$(ASMEXT)=.o)) 15 | HEADERS:=$(wildcard *.$(HEXT)) 16 | ### Special section for Cortex projects ### 17 | HEADERS_2:=$(wildcard ../include/*.$(HEXT)) 18 | ### End special section ### 19 | CSRC=$(wildcard *.$(CEXT)) $(wildcard **/*.$(CEXT)) 20 | COBJ:=$(patsubst %.o,$(BINDIR)/%.o,$(CSRC:.$(CEXT)=.o)) 21 | CPPSRC:=$(wildcard *.$(CPPEXT)) $(wildcard **/*.$(CPPEXT)) 22 | CPPOBJ:=$(patsubst %.o,$(BINDIR)/%.o,$(CPPSRC:.$(CPPEXT)=.o)) 23 | OUT:=$(BINDIR)/$(OUTNAME) 24 | 25 | .PHONY: all 26 | 27 | # By default, compile program 28 | all: . 29 | 30 | # Compiles the program if anything is changed 31 | .: $(ASMOBJ) $(COBJ) $(CPPOBJ) 32 | @touch . 33 | 34 | # Assembly source file management 35 | $(ASMOBJ): $(BINDIR)/%.o: %.$(ASMEXT) 36 | @echo AS $< 37 | @$(AS) $(AFLAGS) -o $@ $< 38 | 39 | ### Special section for Cortex projects ### 40 | 41 | # Object management 42 | $(COBJ): $(BINDIR)/$(subst ..,,$(subst /,_,%.o)): %.$(CEXT) $(HEADERS) $(HEADERS_2) 43 | @echo CC $(INCLUDE) $< 44 | @$(CC) $(INCLUDE) $(CFLAGS) -o $(BINDIR)/$(subst ..,,$(subst /,_,$@)) $< 45 | 46 | KEKSRC:=$(dir $(wildcard **/*/)) 47 | 48 | $(CPPOBJ): $(BINDIR)/$(subst ..,,$(subst /,_,%.o)): %.$(CPPEXT) $(HEADERS) $(HEADERS_2) 49 | @echo CPC $(INCLUDE) $< 50 | $(CPPCC) $(INCLUDE) $(CPPFLAGS) -o $(BINDIR)/$(subst ..,,$(subst /,_,$@)) $< 51 | 52 | ### End special section ### 53 | -------------------------------------------------------------------------------- /src/auto.cpp: -------------------------------------------------------------------------------- 1 | /** @file auto.c 2 | * @brief File for autonomous code 3 | * 4 | * This file should contain the user autonomous() function and any functions related to it. 5 | * 6 | * Any copyright is dedicated to the Public Domain. 7 | * http://creativecommons.org/publicdomain/zero/1.0/ 8 | * 9 | * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be 10 | * obtained from http://sourceforge.net/projects/freertos/files/ or on request. 11 | */ 12 | 13 | #include "main.h" 14 | 15 | void autonomous() { 16 | } 17 | -------------------------------------------------------------------------------- /src/chassis/chassisController.cpp: -------------------------------------------------------------------------------- 1 | #include "chassis/chassisController.h" 2 | #include "util/timer.h" 3 | #include "PAL/PAL.h" 4 | #include 5 | 6 | namespace okapi { 7 | void ChassisControllerPid::driveStraight(const int itarget) { 8 | using namespace std; 9 | 10 | const auto encStartVals = model->getSensorVals(); 11 | float distanceElapsed = 0, angleChange = 0, lastDistance = 0; 12 | unsigned long prevWakeTime = PAL::millis(); 13 | 14 | distancePid.reset(); 15 | anglePid.reset(); 16 | distancePid.setTarget(static_cast(itarget)); 17 | anglePid.setTarget(0); 18 | 19 | bool atTarget = false; 20 | const int atTargetDistance = 15; 21 | const int threshold = 2; 22 | 23 | Timer atTargetTimer; 24 | 25 | const int timeoutPeriod = 250; 26 | 27 | valarray encVals{0, 0}; 28 | float distOutput, angleOutput; 29 | 30 | 31 | while (!atTarget) { 32 | encVals = model->getSensorVals() - encStartVals; 33 | distanceElapsed = static_cast((encVals[0] + encVals[1])) / 2.0; 34 | angleChange = static_cast(encVals[1] - encVals[0]); 35 | 36 | distOutput = distancePid.step(distanceElapsed); 37 | angleOutput = anglePid.step(angleChange); 38 | model->driveVector(static_cast(distOutput), static_cast(angleOutput)); 39 | 40 | if (abs(itarget - static_cast(distanceElapsed)) <= atTargetDistance) 41 | atTargetTimer.placeHardMark(); 42 | else if (abs(static_cast(distanceElapsed) - static_cast(lastDistance)) <= threshold) 43 | atTargetTimer.placeHardMark(); 44 | else 45 | atTargetTimer.clearHardMark(); 46 | 47 | lastDistance = distanceElapsed; 48 | 49 | if (atTargetTimer.getDtFromHardMark() >= timeoutPeriod) 50 | atTarget = true; 51 | 52 | PAL::taskDelayUntil(&prevWakeTime, 15); 53 | } 54 | 55 | model->driveForward(0); 56 | } 57 | 58 | void ChassisControllerPid::pointTurn(float idegTarget) { 59 | using namespace std; 60 | 61 | const auto encStartVals = model->getSensorVals(); 62 | float angleChange = 0, lastAngle = 0; 63 | unsigned long prevWakeTime = PAL::millis(); 64 | 65 | while (idegTarget > 180) 66 | idegTarget -= 360; 67 | while (idegTarget <= -180) 68 | idegTarget += 360; 69 | 70 | anglePid.reset(); 71 | anglePid.setTarget(static_cast(idegTarget)); 72 | 73 | bool atTarget = false; 74 | const int atTargetAngle = 10; 75 | const int threshold = 2; 76 | 77 | Timer atTargetTimer; 78 | 79 | const int timeoutPeriod = 250; 80 | 81 | valarray encVals{0, 0}; 82 | 83 | while (!atTarget) { 84 | encVals = model->getSensorVals() - encStartVals; 85 | angleChange = static_cast(encVals[1] - encVals[0]); 86 | 87 | model->turnClockwise(static_cast(anglePid.step(angleChange))); 88 | 89 | if (fabs(idegTarget - angleChange) <= atTargetAngle) 90 | atTargetTimer.placeHardMark(); 91 | else if (fabs(angleChange - lastAngle) <= threshold) 92 | atTargetTimer.placeHardMark(); 93 | else 94 | atTargetTimer.clearHardMark(); 95 | 96 | lastAngle = angleChange; 97 | 98 | if (atTargetTimer.getDtFromHardMark() >= timeoutPeriod) 99 | atTarget = true; 100 | 101 | PAL::taskDelayUntil(&prevWakeTime, 15); 102 | } 103 | 104 | model->driveForward(0); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/chassis/odomChassisController.cpp: -------------------------------------------------------------------------------- 1 | #include "chassis/odomChassisController.h" 2 | #include "odometry/odomMath.h" 3 | #include 4 | 5 | namespace okapi { 6 | void OdomChassisControllerPid::driveToPoint(const float ix, const float iy, const bool ibackwards, const float ioffset) { 7 | DistanceAndAngle daa = OdomMath::computeDistanceAndAngleToPoint(ix, iy, odom.getState()); 8 | 9 | if (ibackwards) { 10 | daa.theta += 180; 11 | daa.length *= -1; 12 | } 13 | 14 | if (std::abs(daa.theta) > 1) { 15 | ChassisControllerPid::pointTurn(daa.theta); 16 | } 17 | 18 | if (std::abs(daa.length - ioffset) > moveThreshold) { 19 | ChassisControllerPid::driveStraight(static_cast(daa.length - ioffset)); 20 | } 21 | } 22 | 23 | void OdomChassisControllerPid::turnToAngle(const float iangle) { 24 | ChassisControllerPid::pointTurn(iangle - odom.getState().theta); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/control/nsPid.cpp: -------------------------------------------------------------------------------- 1 | #include "control/nsPid.h" 2 | #include 3 | 4 | namespace okapi { 5 | float NsPid::step(const float inewReading) { 6 | using namespace std; 7 | 8 | Pid::step(inewReading); //Main control loop 9 | 10 | //Check if velocity is sufficiently small 11 | if (fabs(velMath.step(inewReading)) < minVel) { 12 | return scale * Pid::output; 13 | } 14 | 15 | return Pid::output; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/control/pid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "control/pid.h" 3 | #include "PAL/PAL.h" 4 | 5 | namespace okapi { 6 | void Pid::setSampleTime(const int isampleTime) { 7 | if (isampleTime > 0) { 8 | const float ratio = static_cast(isampleTime) / static_cast(sampleTime); 9 | kI *= ratio; 10 | kD /= ratio; 11 | sampleTime = isampleTime; 12 | } 13 | } 14 | 15 | void Pid::setOutputLimits(float imax, float imin) { 16 | //Always use larger value as max 17 | if (imin > imax) { 18 | const float temp = imax; 19 | imax = imin; 20 | imin = temp; 21 | } 22 | 23 | outputMax = imax; 24 | outputMin = imin; 25 | 26 | //Fix output 27 | if (output > outputMax) 28 | output = outputMax; 29 | else if (output < outputMin) 30 | output = outputMin; 31 | 32 | //Fix integral 33 | setIntegralLimits(imax, imin); 34 | } 35 | 36 | void Pid::setIntegralLimits(float imax, float imin) { 37 | //Always use larger value as max 38 | if (imin > imax) { 39 | const float temp = imax; 40 | imax = imin; 41 | imin = temp; 42 | } 43 | 44 | integralMax = imax; 45 | integralMin = imin; 46 | 47 | //Fix integral 48 | if (integral > integralMax) 49 | integral = integralMax; 50 | else if (integral < integralMin) 51 | integral = integralMin; 52 | } 53 | 54 | float Pid::step(const float inewReading) { 55 | using namespace std; //Needed to get copysign to compile 56 | 57 | if (isOn) { 58 | const long now = PAL::millis(); 59 | 60 | if (now - lastTime >= sampleTime) { 61 | error = target - inewReading; 62 | 63 | integral += kI * error; //Eliminate integral kick while realtime tuning 64 | 65 | if (shouldResetOnCross && copysign(1.0, (float)error) != copysign(1.0, (float)lastError)) 66 | integral = 0; 67 | 68 | if (integral > integralMax) 69 | integral = integralMax; 70 | else if (integral < integralMin) 71 | integral = integralMin; 72 | 73 | const float derivative = inewReading - lastReading; //Derivative over measurement to eliminate derivative kick on setpoint change 74 | 75 | output = kP * error + integral - kD * derivative + kBias; 76 | 77 | if (output > outputMax) 78 | output = outputMax; 79 | else if (output < outputMin) 80 | output = outputMin; 81 | 82 | lastReading = inewReading; 83 | lastError = error; 84 | lastTime = now; //Important that we only assign lastTime if dt >= sampleTime 85 | } 86 | } else { 87 | output = 0; //Controller is off so write 0 88 | } 89 | 90 | return output; 91 | } 92 | 93 | void Pid::setGains(const float ikP, const float ikI, const float ikD, const float ikBias) { 94 | const float sampleTimeSec = static_cast(sampleTime) / 1000.0; 95 | kP = ikP; 96 | kI = ikI * sampleTimeSec; 97 | kD = ikD * sampleTimeSec; 98 | kBias = ikBias; 99 | } 100 | 101 | void Pid::reset() { 102 | error = 0; 103 | lastError = 0; 104 | lastReading = 0; 105 | integral = 0; 106 | output = 0; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/control/velMath.cpp: -------------------------------------------------------------------------------- 1 | #include "control/velMath.h" 2 | #include "PAL/PAL.h" 3 | 4 | namespace okapi { 5 | float VelMath::step(const float inewPos) { 6 | const long now = PAL::millis(); 7 | 8 | vel = static_cast((1000 / (now - lastTime))) * (inewPos - lastPos) * (60 / ticksPerRev); 9 | vel = filter.filter(vel); 10 | 11 | lastPos = inewPos; 12 | lastTime = now; 13 | 14 | return vel; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/control/velPid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "control/velPid.h" 3 | #include "PAL/PAL.h" 4 | 5 | namespace okapi { 6 | void VelPid::setGains(const float ikP, const float ikD) { 7 | kP = ikP; 8 | kD = ikD * static_cast(sampleTime) / 1000.0; 9 | } 10 | 11 | void VelPid::setSampleTime(const int isampleTime) { 12 | if (isampleTime > 0) { 13 | kD /= static_cast(isampleTime) / static_cast(sampleTime); 14 | sampleTime = isampleTime; 15 | } 16 | } 17 | 18 | void VelPid::setOutputLimits(float imax, float imin) { 19 | //Always use larger value as max 20 | if (imin > imax) { 21 | const float temp = imax; 22 | imax = imin; 23 | imin = temp; 24 | } 25 | 26 | outputMax = imax; 27 | outputMin = imin; 28 | 29 | //Fix output 30 | if (output > outputMax) 31 | output = outputMax; 32 | else if (output < outputMin) 33 | output = outputMin; 34 | } 35 | 36 | float VelPid::stepVel(const float inewReading) { 37 | return velMath.step(inewReading); 38 | } 39 | 40 | float VelPid::step(const float inewReading) { 41 | if (isOn) { 42 | const long now = PAL::millis(); 43 | if (now - lastTime >= sampleTime) { 44 | stepVel(inewReading); 45 | const float error = target - velMath.getOutput(); 46 | 47 | const float derivative = velMath.getDiff(); //Derivative over measurement to eliminate derivative kick on setpoint change 48 | 49 | output += kP * error - kD * derivative; 50 | 51 | if (output > outputMax) 52 | output = outputMax; 53 | else if (output < outputMin) 54 | output = outputMin; 55 | 56 | lastError = error; 57 | lastTime = now; //Important that we only assign lastTime if dt >= sampleTime 58 | } 59 | 60 | return output; 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | void VelPid::reset() { 67 | error = 0; 68 | lastError = 0; 69 | output = 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/init.cpp: -------------------------------------------------------------------------------- 1 | /** @file init.c 2 | * @brief File for initialization code 3 | * 4 | * This file should contain the user initialize() function and any functions related to it. 5 | * 6 | * Any copyright is dedicated to the Public Domain. 7 | * http://creativecommons.org/publicdomain/zero/1.0/ 8 | * 9 | * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be 10 | * obtained from http://sourceforge.net/projects/freertos/files/ or on request. 11 | */ 12 | 13 | #include "main.h" 14 | 15 | extern "C" { 16 | void __libc_init_array(); 17 | void __cxa_pure_virtual() { exit(1111); } 18 | // int _getpid() { return -1;} 19 | // int _kill(int pid, int sig) { return -1; } 20 | // void _sbrk() {} 21 | // void __dso_handle() {} 22 | } 23 | 24 | namespace std { 25 | // void __throw_length_error(char const*) { exit(1112); } 26 | void __throw_bad_alloc() { exit(1113); } 27 | } 28 | 29 | /* 30 | * Runs pre-initialization code. This function will be started in kernel mode one time while the 31 | * VEX Cortex is starting up. As the scheduler is still paused, most API functions will fail. 32 | * 33 | * The purpose of this function is solely to set the default pin modes (pinMode()) and port 34 | * states (digitalWrite()) of limit switches, push buttons, and solenoids. It can also safely 35 | * configure a UART port (usartOpen()) but cannot set up an LCD (lcdInit()). 36 | */ 37 | void initializeIO() { 38 | lcdInit(uart1); 39 | } 40 | 41 | /* 42 | * Runs user initialization code. This function will be started in its own task with the default 43 | * priority and stack size once when the robot is starting up. It is possible that the VEXnet 44 | * communication link may not be fully established at this time, so reading from the VEX 45 | * Joystick may fail. 46 | * 47 | * This function should initialize most sensors (gyro, encoders, ultrasonics), LCDs, global 48 | * variables, and IMEs. 49 | * 50 | * This function must exit relatively promptly, or the operatorControl() and autonomous() tasks 51 | * will not start. An autonomous mode selection menu like the pre_auton() in other environments 52 | * can be implemented in this task if desired. 53 | */ 54 | void initialize() { 55 | __libc_init_array(); 56 | imeInitializeAll(); 57 | } 58 | -------------------------------------------------------------------------------- /src/odometry/odomMath.cpp: -------------------------------------------------------------------------------- 1 | #include "odometry/odomMath.h" 2 | #include 3 | #include "util/mathUtil.h" 4 | 5 | namespace okapi { 6 | float OdomMath::computeDistanceToPoint(const float ix, const float iy, const OdomState& istate) { 7 | const float xDiff = ix - istate.x; 8 | const float yDiff = iy - istate.y; 9 | return std::sqrt((xDiff * xDiff) + (yDiff * yDiff)); 10 | } 11 | 12 | float OdomMath::computeAngleToPoint(const float ix, const float iy, const OdomState& istate) { 13 | const float xDiff = ix - istate.x; 14 | const float yDiff = iy - istate.y; 15 | return (std::atan2(yDiff, xDiff) * radianToDegree) - istate.theta; 16 | } 17 | 18 | DistanceAndAngle OdomMath::computeDistanceAndAngleToPoint(const float ix, const float iy, const OdomState& istate) { 19 | using namespace std; //Needed to get copysign to compile 20 | 21 | const float xDiff = ix - istate.x; 22 | const float yDiff = iy - istate.y; 23 | DistanceAndAngle out; 24 | out.length = std::sqrt((xDiff * xDiff) + (yDiff * yDiff)); 25 | 26 | //Small xDiff is essentially dividing by zero, so avoid it and do custom math 27 | if (xDiff < 0.0001 && xDiff > -0.0001) { 28 | const int yDiffSign = static_cast(copysign(1, yDiff)); 29 | if (yDiffSign == 1) { 30 | out.theta = -1 * istate.theta; 31 | } else if (yDiffSign == -1) { 32 | out.theta = -180 - istate.theta; 33 | 34 | //Fix theta 35 | if (out.theta <= -360) 36 | out.theta += 360; 37 | else if (out.theta >= 360) 38 | out.theta -= 360; 39 | } 40 | } else { 41 | out.theta = (std::atan2(yDiff, xDiff) * radianToDegree) - istate.theta; 42 | } 43 | 44 | return out; 45 | } 46 | 47 | std::tuple OdomMath::guessScales(const float chassisDiam, const float wheelDiam, const float ticksPerRev) { 48 | const float scale = ((wheelDiam * pi * inchToMM) / ticksPerRev) * 0.9945483364; //This scale is usually off by this amount 49 | const float turnScale = (1.0 / (chassisDiam * inchToMM)) * radianToDegree * 2; 50 | return std::make_tuple(scale, turnScale); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/odometry/odometry.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "odometry/odometry.h" 3 | #include "util/mathUtil.h" 4 | #include "PAL/PAL.h" 5 | 6 | namespace okapi { 7 | void Odometry::loop() { 8 | unsigned long now = PAL::millis(); 9 | std::valarray newTicks{0, 0}, tickDiff{0, 0}; 10 | 11 | while (true) { 12 | newTicks = model->getSensorVals(); 13 | tickDiff = newTicks - lastTicks; 14 | mm = (static_cast(tickDiff[1] + tickDiff[0]) / 2.0) * scale; 15 | lastTicks = newTicks; 16 | 17 | state.theta += (static_cast(tickDiff[1] - tickDiff[0]) / 2.0) * turnScale; 18 | if (state.theta > 180) 19 | state.theta -= 360; 20 | else if (state.theta < -180) 21 | state.theta += 360; 22 | 23 | state.x += mm * std::cos(state.theta); 24 | state.y += mm * std::sin(state.theta); 25 | 26 | PAL::taskDelayUntil(&now, 15); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/opcontrol.cpp: -------------------------------------------------------------------------------- 1 | /** @file opcontrol.c 2 | * @brief File for operator control code 3 | * 4 | * This file should contain the user operatorControl() function and any functions related to it. 5 | * 6 | * Any copyright is dedicated to the Public Domain. 7 | * http://creativecommons.org/publicdomain/zero/1.0/ 8 | * 9 | * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be 10 | * obtained from http://sourceforge.net/projects/freertos/files/ or on request. 11 | */ 12 | 13 | #include 14 | #include "main.h" 15 | 16 | #include "chassis/chassisController.h" 17 | #include "chassis/chassisModel.h" 18 | #include "chassis/odomChassisController.h" 19 | 20 | #include "control/controlObject.h" 21 | #include "control/genericController.h" 22 | #include "control/nsPid.h" 23 | #include "control/pid.h" 24 | #include "control/velMath.h" 25 | #include "control/velPid.h" 26 | 27 | #include "device/button.h" 28 | #include "device/ime.h" 29 | #include "device/motor.h" 30 | #include "device/potentiometer.h" 31 | #include "device/quadEncoder.h" 32 | #include "device/rangeFinder.h" 33 | #include "device/rotarySensor.h" 34 | 35 | #include "filter/avgFilter.h" 36 | #include "filter/demaFilter.h" 37 | #include "filter/emaFilter.h" 38 | #include "filter/filter.h" 39 | 40 | #include "odometry/odometry.h" 41 | #include "odometry/odomMath.h" 42 | 43 | #include "util/mathUtil.h" 44 | #include "util/timer.h" 45 | 46 | using namespace okapi; 47 | 48 | void operatorControl() { 49 | using namespace std; //Needed to get round to compile 50 | 51 | IME leftIME = 0_ime, rightIME = 1_rime; 52 | leftIME.reset(); 53 | rightIME.reset(); 54 | 55 | Button driveBtn(1, 8, JOY_UP); 56 | 57 | auto scales = OdomMath::guessScales(11.75, 3.25, imeTurboTPR); 58 | OdomChassisControllerPid controller( 59 | OdomParams(SkidSteerModelParams<3>({2_m,3_m,4_m, 5_m,6_m,7_m}, leftIME, rightIME), std::get<0>(scales), std::get<1>(scales)), 60 | PidParams(0.15, 0.05, 0.07), 61 | PidParams(0.02, 0.01, 0)); 62 | 63 | while (true) { 64 | if (driveBtn.risingEdge()) { 65 | controller.driveToPoint(100, 0); 66 | } 67 | 68 | auto state = controller.getState(); 69 | printf("%1.2f, %1.2f, %1.2f\n", state.x, state.y, state.theta); 70 | delay(15); 71 | } 72 | 73 | // QuadEncoder leftEnc(1, 2, true), rightEnc(3, 4); 74 | // ChassisControllerPid controller(SkidSteerModelParams<3>({2_m,3_m,4_m, 5_m,6_m,7_m}, leftEnc, rightEnc), PidParams(0.15, 0.05, 0.07), PidParams(0.02, 0.01, 0)); 75 | 76 | // const unsigned char liftPot = 1; 77 | 78 | // GenericController<2> liftController({8_m, 9_m}, std::make_shared(NsPid(PidParams(0.2, 0.1, 0.1), VelMathParams(360), 0.5))); 79 | 80 | // constexpr int liftUpTarget = 2570, lift34 = 300, liftDownTarget = 10; 81 | // int target = liftUpTarget; 82 | 83 | // while (1) { 84 | // if (joystickGetDigital(1, 6, JOY_UP)) 85 | // target = liftUpTarget; 86 | // else if (joystickGetDigital(1, 6, JOY_DOWN)) 87 | // target = liftDownTarget; 88 | // else if (joystickGetDigital(1, 5, JOY_UP)) 89 | // target = lift34; 90 | // else if (joystickGetDigital(1, 8, JOY_LEFT)) { 91 | // liftController.flipDisable(); 92 | // while (joystickGetDigital(1, 8, JOY_LEFT)); 93 | // } 94 | 95 | // liftController.setTarget(static_cast(target)); 96 | // liftController.step(static_cast(analogRead(liftPot))); 97 | 98 | // controller.arcade(joystickGetAnalog(1, 2), joystickGetAnalog(1, 1)); 99 | 100 | // if (joystickGetDigital(1, 8, JOY_RIGHT)) { 101 | // encoderReset(leftEnc); 102 | // encoderReset(rightEnc); 103 | // int power = 0; 104 | // VelMath vm1(360); 105 | // VelMath vm2(360, 1, 0); 106 | // Timer timer; 107 | 108 | // printf("Filtered,Unfiltered\n"); 109 | 110 | // while (true) { 111 | // if (timer.repeat(100)) { 112 | // if (power > 127) { 113 | // controller.stop(); 114 | // break; 115 | // } 116 | 117 | // controller.turnClockwise(power); 118 | // power++; 119 | // } 120 | 121 | // const float avg = (encoderGet(leftEnc) - encoderGet(rightEnc)) / 2.0; 122 | // vm1.loop(avg); 123 | // vm2.loop(avg); 124 | // printf("%1.2f,%1.2f\n", vm1.getOutput(), vm2.getOutput()); 125 | 126 | // if (joystickGetDigital(1, 8, JOY_LEFT)) { 127 | // while (joystickGetDigital(1, 8, JOY_LEFT)) { taskDelay(15); } 128 | // break; 129 | // } 130 | 131 | // taskDelay(15); 132 | // } 133 | // } 134 | // } 135 | } 136 | -------------------------------------------------------------------------------- /src/util/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "util/timer.h" 2 | #include "PAL/PAL.h" 3 | 4 | namespace okapi { 5 | unsigned long Timer::getDt() { 6 | const unsigned long currTime = PAL::millis(); 7 | const unsigned long dt = currTime - lastCalled; 8 | lastCalled = currTime; 9 | return dt; 10 | } 11 | 12 | unsigned long Timer::getStartingTime() const { 13 | return firstCalled; 14 | } 15 | 16 | unsigned long Timer::getDtFromStart() const { 17 | return PAL::millis() - firstCalled; 18 | } 19 | 20 | void Timer::placeMark() { 21 | mark = PAL::millis(); 22 | } 23 | 24 | void Timer::placeHardMark() { 25 | if (hardMark == -1) 26 | hardMark = PAL::millis(); 27 | } 28 | 29 | unsigned long Timer::clearHardMark() { 30 | const long old = hardMark; 31 | hardMark = -1; 32 | return old; 33 | } 34 | 35 | unsigned long Timer::getDtFromMark() const { 36 | return PAL::millis() - mark; 37 | } 38 | 39 | unsigned long Timer::getDtFromHardMark() const { 40 | return hardMark == -1 ? 0 : PAL::millis() - hardMark; 41 | } 42 | 43 | bool Timer::repeat(unsigned long ms) { 44 | if (repeatMark == -1) 45 | repeatMark = PAL::millis(); 46 | 47 | if (PAL::millis() - repeatMark >= ms) { 48 | repeatMark = -1; 49 | return true; 50 | } 51 | 52 | return false; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /template.mk: -------------------------------------------------------------------------------- 1 | LIBNAME=okapilib 2 | VERSION=0.5.1 3 | 4 | # extra files (like header files) 5 | TEMPLATEFILES = include/main.h include/device/motor.h include/device/button.h include/device/ime.h include/device/potentiometer.h include/device/quadEncoder.h include/device/rangeFinder.h include/device/rotarySensor.h include/chassis/chassisModel.h include/chassis/odomChassisController.h include/chassis/chassisController.h include/API.h include/util/timer.h include/util/mathUtil.h include/odometry/odomMath.h include/odometry/odometry.h include/filter/filter.h include/filter/emaFilter.h include/filter/avgFilter.h include/filter/demaFilter.h include/control/pid.h include/control/genericController.h include/control/velMath.h include/control/nsPid.h include/control/velPid.h include/control/controlObject.h 6 | # basename of the source files that should be archived 7 | TEMPLATEOBJS = _bin_auto _bin_chassis_chassisController _bin_chassis_odomChassisController _bin_control_nsPid _bin_control_pid _bin_control_velMath _bin_control_velPid _bin_init _bin_odometry_odometry _bin_odometry_odomMath _bin_opcontrol _bin_util_timer 8 | 9 | TEMPLATE=$(ROOT)/$(LIBNAME)-template 10 | 11 | .DEFAULT_GOAL: all 12 | 13 | library: clean $(BINDIR) $(SUBDIRS) $(ASMOBJ) $(COBJ) $(CPPOBJ) 14 | $(MCUPREFIX)ar rvs $(BINDIR)/$(LIBNAME).a $(foreach f,$(TEMPLATEOBJS),$(BINDIR)/$(f).o) 15 | mkdir -p $(TEMPLATE) $(TEMPLATE)/firmware $(addprefix $(TEMPLATE)/, $(dir $(TEMPLATEFILES))) 16 | cp $(BINDIR)/$(LIBNAME).a $(TEMPLATE)/firmware/$(LIBNAME).a 17 | $(foreach f,$(TEMPLATEFILES),cp $(f) $(TEMPLATE)/$(f);) 18 | pros conduct create-template $(LIBNAME) $(VERSION) $(TEMPLATE) --ignore template.pros --upgrade-files firmware/$(LIBNAME).a $(foreach f,$(TEMPLATEFILES),--upgrade-files $(f)) 19 | @echo Need to zip $(TEMPLATE) without the base directory 20 | cd $(TEMPLATE) && zip -r ../$(basename $(TEMPLATE)) * 21 | --------------------------------------------------------------------------------