Made a few small tweaks.

This commit is contained in:
That-One-Nerd 2025-03-21 18:32:09 -04:00
parent 89be599ccf
commit 00943028f2
678 changed files with 4 additions and 127586 deletions

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto

32
.gitignore vendored
View File

@ -1,32 +0,0 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app

View File

@ -1,17 +0,0 @@
# Compiled Object files
*.o
*.obj
# Executables
*.bin
*.elf
# PROS
bin/
.vscode/
.cache/
compile_commands.json
temp.log
temp.errors
*.ini
.d/

Binary file not shown.

View File

@ -1,45 +0,0 @@
################################################################################
######################### User configurable parameters #########################
# filename extensions
CEXTS:=c
ASMEXTS:=s S
CXXEXTS:=cpp c++ cc
# probably shouldn't modify these, but you may need them below
ROOT=.
FWDIR:=$(ROOT)/firmware
BINDIR=$(ROOT)/bin
SRCDIR=$(ROOT)/src
INCDIR=$(ROOT)/include
WARNFLAGS+=
EXTRA_CFLAGS=
EXTRA_CXXFLAGS=
# Set to 1 to enable hot/cold linking
USE_PACKAGE:=1
# Add libraries you do not wish to include in the cold image here
# EXCLUDE_COLD_LIBRARIES:= $(FWDIR)/your_library.a
EXCLUDE_COLD_LIBRARIES:=
# Set this to 1 to add additional rules to compile your project as a PROS library template
IS_LIBRARY:=0
# TODO: CHANGE THIS!
LIBNAME:=libbest
VERSION:=1.0.0
# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c
# this line excludes opcontrol.c and similar files
EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext)))
# files that get distributed to every user (beyond your source archive) - add
# whatever files you want here. This line is configured to add all header files
# that are in the the include directory get exported
TEMPLATE_FILES=$(INCDIR)/**/*.h $(INCDIR)/**/*.hpp
.DEFAULT_GOAL=quick
################################################################################
################################################################################
########## Nothing below this line should be edited by typical users ###########
-include ./common.mk

View File

@ -1,295 +0,0 @@
ARCHTUPLE=arm-none-eabi-
DEVICE=VEX EDR V5
MFLAGS=-mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=softfp -Os -g
CPPFLAGS=-D_POSIX_THREADS -D_UNIX98_THREAD_MUTEX_ATTRIBUTES -D_POSIX_TIMERS -D_POSIX_MONOTONIC_CLOCK
GCCFLAGS=-ffunction-sections -fdata-sections -fdiagnostics-color -funwind-tables
WARNFLAGS+=-Wno-psabi
SPACE := $() $()
COMMA := ,
DEPDIR := .d
$(shell mkdir -p $(DEPDIR))
DEPFLAGS = -MT $$@ -MMD -MP -MF $(DEPDIR)/$$*.Td
MAKEDEPFOLDER = -$(VV)mkdir -p $(DEPDIR)/$$(dir $$(patsubst $(BINDIR)/%, %, $(ROOT)/$$@))
RENAMEDEPENDENCYFILE = -$(VV)mv -f $(DEPDIR)/$$*.Td $$(patsubst $(SRCDIR)/%, $(DEPDIR)/%.d, $(ROOT)/$$<) && touch $$@
LIBRARIES+=$(wildcard $(FWDIR)/*.a)
# Cannot include newlib and libc because not all of the req'd stubs are implemented
EXCLUDE_COLD_LIBRARIES+=$(FWDIR)/libc.a $(FWDIR)/libm.a
COLD_LIBRARIES=$(filter-out $(EXCLUDE_COLD_LIBRARIES), $(LIBRARIES))
wlprefix=-Wl,$(subst $(SPACE),$(COMMA),$1)
LNK_FLAGS=--gc-sections --start-group $(strip $(LIBRARIES)) -lgcc -lstdc++ --end-group -T$(FWDIR)/v5-common.ld
ASMFLAGS=$(MFLAGS) $(WARNFLAGS)
CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu11
CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu++17
LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostdlib $(GCCFLAGS)
SIZEFLAGS=-d --common
NUMFMTFLAGS=--to=iec --format %.2f --suffix=B
AR:=$(ARCHTUPLE)ar
# using arm-none-eabi-as generates a listing by default. This produces a super verbose output.
# Using gcc accomplishes the same thing without the extra output
AS:=$(ARCHTUPLE)gcc
CC:=$(ARCHTUPLE)gcc
CXX:=$(ARCHTUPLE)g++
LD:=$(ARCHTUPLE)g++
OBJCOPY:=$(ARCHTUPLE)objcopy
SIZETOOL:=$(ARCHTUPLE)size
READELF:=$(ARCHTUPLE)readelf
STRIP:=$(ARCHTUPLE)strip
ifneq (, $(shell command -v gnumfmt 2> /dev/null))
SIZES_NUMFMT:=| gnumfmt --field=-4 --header $(NUMFMTFLAGS)
else
ifneq (, $(shell command -v numfmt 2> /dev/null))
SIZES_NUMFMT:=| numfmt --field=-4 --header $(NUMFMTFLAGS)
else
SIZES_NUMFMT:=
endif
endif
ifneq (, $(shell command -v sed 2> /dev/null))
SIZES_SED:=| sed -e 's/ dec/total/'
else
SIZES_SED:=
endif
rwildcard=$(foreach d,$(filter-out $3,$(wildcard $1*)),$(call rwildcard,$d/,$2,$3)$(filter $(subst *,%,$2),$d))
# Colors
NO_COLOR=$(shell printf "%b" "\033[0m")
OK_COLOR=$(shell printf "%b" "\033[32;01m")
ERROR_COLOR=$(shell printf "%b" "\033[31;01m")
WARN_COLOR=$(shell printf "%b" "\033[33;01m")
STEP_COLOR=$(shell printf "%b" "\033[37;01m")
OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR)
DONE_STRING=$(OK_COLOR)[DONE]$(NO_COLOR)
ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR)
WARN_STRING=$(WARN_COLOR)[WARNINGS]$(NO_COLOR)
ECHO=/bin/printf "%s\n"
echo=@$(ECHO) "$2$1$(NO_COLOR)"
echon=@/bin/printf "%s" "$2$1$(NO_COLOR)"
define test_output_2
@if test $(BUILD_VERBOSE) -eq $(or $4,1); then printf "%s\n" "$2"; fi;
@output="$$($2 2>&1)"; exit=$$?; \
if test 0 -ne $$exit; then \
printf "%s%s\n" "$1" "$(ERROR_STRING)"; \
printf "%s\n" "$$output"; \
exit $$exit; \
elif test -n "$$output"; then \
printf "%s%s\n" "$1" "$(WARN_STRING)"; \
printf "%s\n" "$$output"; \
else \
printf "%s%s\n" "$1" "$3"; \
fi;
endef
define test_output
@output=$$($1 2>&1); exit=$$?; \
if test 0 -ne $$exit; then \
printf "%s\n" "$(ERROR_STRING)" $$?; \
printf "%s\n" $$output; \
exit $$exit; \
elif test -n "$$output"; then \
printf "%s\n" "$(WARN_STRING)"; \
printf "%s" $$output; \
else \
printf "%s\n" "$2"; \
fi;
endef
# Makefile Verbosity
ifeq ("$(origin VERBOSE)", "command line")
BUILD_VERBOSE = $(VERBOSE)
endif
ifeq ("$(origin V)", "command line")
BUILD_VERBOSE = $(V)
endif
ifndef BUILD_VERBOSE
BUILD_VERBOSE = 0
endif
# R is reduced (default messages) - build verbose = 0
# V is verbose messages - verbosity = 1
# VV is super verbose - verbosity = 2
ifeq ($(BUILD_VERBOSE), 0)
R = @echo
D = @
VV = @
endif
ifeq ($(BUILD_VERBOSE), 1)
R = @echo
D =
VV = @
endif
ifeq ($(BUILD_VERBOSE), 2)
R =
D =
VV =
endif
INCLUDE=$(foreach dir,$(INCDIR) $(EXTRA_INCDIR),-iquote"$(dir)")
ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1))
ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1)))
CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1))
COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC, $1)))
CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1))
CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1)))
GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1))
ARCHIVE_TEXT_LIST=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(LIBRARIES))))
LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o
MONOLITH_BIN:=$(BINDIR)/monolith.bin
MONOLITH_ELF:=$(basename $(MONOLITH_BIN)).elf
HOT_BIN:=$(BINDIR)/hot.package.bin
HOT_ELF:=$(basename $(HOT_BIN)).elf
COLD_BIN:=$(BINDIR)/cold.package.bin
COLD_ELF:=$(basename $(COLD_BIN)).elf
# Check if USE_PACKAGE is defined to check for migration steps from purduesigbots/pros#87
ifndef USE_PACKAGE
$(error Your Makefile must be migrated! Visit https://pros.cs.purdue.edu/v5/releases/kernel3.1.6.html to learn how)
endif
DEFAULT_BIN=$(MONOLITH_BIN)
ifeq ($(USE_PACKAGE),1)
DEFAULT_BIN=$(HOT_BIN)
endif
-include $(wildcard $(FWDIR)/*.mk)
.PHONY: all clean quick
quick: $(DEFAULT_BIN)
all: clean $(DEFAULT_BIN)
clean:
@echo Cleaning project
-$Drm -rf $(BINDIR)
-$Drm -rf $(DEPDIR)
ifeq ($(IS_LIBRARY),1)
ifeq ($(LIBNAME),libbest)
$(errror "You should rename your library! libbest is the default library name and should be changed")
endif
LIBAR=$(BINDIR)/$(LIBNAME).a
TEMPLATE_DIR=$(ROOT)/template
clean-template:
@echo Cleaning $(TEMPLATE_DIR)
-$Drm -rf $(TEMPLATE_DIR)
$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS)
-$Drm -f $@
$(call test_output_2,Creating $@ ,$(AR) rcs $@ $^, $(DONE_STRING))
.PHONY: library
library: $(LIBAR)
.PHONY: template
template: clean-template $(LIBAR)
$Dpros c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 $(CREATE_TEMPLATE_FLAGS)
endif
# if project is a library source, compile the archive and link output.elf against the archive rather than source objects
ifeq ($(IS_LIBRARY),1)
ELF_DEPS+=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS)))
LIBRARIES+=$(LIBAR)
else
ELF_DEPS+=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS))
endif
$(MONOLITH_BIN): $(MONOLITH_ELF) $(BINDIR)
$(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING))
$(MONOLITH_ELF): $(ELF_DEPS) $(LIBRARIES)
$(call _pros_ld_timestamp)
$(call test_output_2,Linking project with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(ELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING))
@echo Section sizes:
-$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT)
$(COLD_BIN): $(COLD_ELF)
$(call test_output_2,Creating cold package binary for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING))
$(COLD_ELF): $(COLD_LIBRARIES)
$(VV)mkdir -p $(dir $@)
$(call test_output_2,Creating cold package with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(call wlprefix,--gc-keep-exported --whole-archive $^ -lstdc++ --no-whole-archive) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS) -o $@),$(OK_STRING))
$(call test_output_2,Stripping cold package ,$(OBJCOPY) --strip-symbol=install_hot_table --strip-symbol=__libc_init_array --strip-symbol=_PROS_COMPILE_DIRECTORY --strip-symbol=_PROS_COMPILE_TIMESTAMP --strip-symbol=_PROS_COMPILE_TIMESTAMP_INT $@ $@, $(DONE_STRING))
@echo Section sizes:
-$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT)
$(HOT_BIN): $(HOT_ELF) $(COLD_BIN)
$(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary $@,$(DONE_STRING))
$(HOT_ELF): $(COLD_ELF) $(ELF_DEPS)
$(call _pros_ld_timestamp)
$(call test_output_2,Linking hot project with $(COLD_ELF) and $(ARCHIVE_TEXT_LIST) ,$(LD) -nostartfiles $(LDFLAGS) $(call wlprefix,-R $<) $(filter-out $<,$^) $(LDTIMEOBJ) $(LIBRARIES) $(call wlprefix,-T$(FWDIR)/v5-hot.ld $(LNK_FLAGS) -o $@),$(OK_STRING))
@printf "%s\n" "Section sizes:"
-$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT)
define asm_rule
$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1
$(VV)mkdir -p $$(dir $$@)
$$(call test_output_2,Compiled $$< ,$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING))
endef
$(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext))))
define c_rule
$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1
$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename $1).d
$(VV)mkdir -p $$(dir $$@)
$(MAKEDEPFOLDER)
$$(call test_output_2,Compiled $$< ,$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING))
$(RENAMEDEPENDENCYFILE)
endef
$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext))))
define cxx_rule
$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1
$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename %).d
$(VV)mkdir -p $$(dir $$@)
$(MAKEDEPFOLDER)
$$(call test_output_2,Compiled $$< ,$(CXX) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CXXFLAGS) $(EXTRA_CXXFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING))
$(RENAMEDEPENDENCYFILE)
endef
$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext))))
define _pros_ld_timestamp
$(VV)mkdir -p $(dir $(LDTIMEOBJ))
@# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC,
@# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro
@# which is the pwd | tail bit, which will truncate the path to the last 23 characters
@#
@# const int _PROS_COMPILE_TIMESTAMP_INT = $(( $(date +%s) - $(date +%z) * 3600 ))
@# char const * const _PROS_COMPILE_TIEMSTAMP = __DATE__ " " __TIME__
@# char const * const _PROS_COMPILE_DIRECTORY = "$(shell pwd | tail -c 23)";
@#
@# The shell command $$(($$(date +%s)+($$(date +%-z)/100*3600))) fetches the current
@# unix timestamp, and then adds the UTC timezone offset to account for time zones.
$(call test_output_2,Adding timestamp ,echo 'const int _PROS_COMPILE_TIMESTAMP_INT = $(shell echo $$(($$(date +%s)+($$(date +%-z)/100*3600)))); char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = "$(wildcard $(shell pwd | tail -c 23))";' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -o $(LDTIMEOBJ) -,$(OK_STRING))
endef
# these rules are for build-compile-commands, which just print out sysroot information
cc-sysroot:
@echo | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) --verbose -o /dev/null -
cxx-sysroot:
@echo | $(CXX) -c -x c++ $(CXXFLAGS) $(EXTRA_CXXFLAGS) --verbose -o /dev/null -
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
include $(wildcard $(patsubst $(SRCDIR)/%,$(DEPDIR)/%.d,$(CSRC) $(CXXSRC)))

View File

@ -1,10 +0,0 @@
ASSET_FILES=$(wildcard static/*)
ASSET_OBJ=$(addprefix $(BINDIR)/, $(addsuffix .o, $(ASSET_FILES)) )
GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) $(ASSET_OBJ)
.SECONDEXPANSION:
$(ASSET_OBJ): $$(patsubst bin/%,%,$$(basename $$@))
$(VV)mkdir -p $(BINDIR)/static
@echo "ASSET $@"
$(VV)$(OBJCOPY) -I binary -O elf32-littlearm -B arm $^ $@

View File

@ -1 +0,0 @@
INCLUDE+=-iquote"$(ROOT)/include/okapi/squiggles"

View File

@ -1,263 +0,0 @@
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
/* This will get stripped out before uploading, but we need to place code
here so we can at least link to it (install_hot_table) */
.hot_init : {
KEEP (*(.hot_magic))
KEEP (*(.hot_init))
} > HOT_MEMORY
.text : {
KEEP (*(.vectors))
/* boot data should be exactly 32 bytes long */
*(.boot_data)
. = 0x20;
*(.boot)
. = ALIGN(64);
*(.freertos_vectors)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_except_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > RAM
.init : {
KEEP (*(.init))
} > RAM
.fini : {
KEEP (*(.fini))
} > RAM
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > RAM
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > RAM
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > RAM
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > RAM
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > RAM
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > RAM
.got : {
*(.got)
} > RAM
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > RAM
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
___DTORS_END___ = .;
} > RAM
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > RAM
.eh_frame : {
*(.eh_frame)
} > RAM
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > RAM
.gcc_except_table : {
*(.gcc_except_table)
} > RAM
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > RAM
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > RAM
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > RAM
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > RAM
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > RAM
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > RAM
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > RAM
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > RAM
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > RAM
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > RAM
.bss (NOLOAD) : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
__bss_end = .;
} > RAM
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > HEAP
.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
. = ALIGN(16);
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _IRQ_STACK_SIZE;
. = ALIGN(16);
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > COLD_MEMORY
_end = .;
}

View File

@ -1,33 +0,0 @@
/* This stack is used during initialization, but FreeRTOS tasks have their own
stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks
in standard heap) */
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */
/* Define Memories in the system */
start_of_cold_mem = 0x03800000;
_COLD_MEM_SIZE = 0x04800000;
end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE;
start_of_hot_mem = 0x07800000;
_HOT_MEM_SIZE = 0x00800000;
end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE;
MEMORY
{
/* user code 72M */
COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */
HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE
HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */
}
REGION_ALIAS("RAM", HOT_MEMORY);
ENTRY(install_hot_table)

View File

@ -1,33 +0,0 @@
/* This stack is used during initialization, but FreeRTOS tasks have their own
stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks
in standard heap) */
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */
/* Define Memories in the system */
start_of_cold_mem = 0x03800000;
_COLD_MEM_SIZE = 0x04800000;
end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE;
start_of_hot_mem = 0x07800000;
_HOT_MEM_SIZE = 0x00800000;
end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE;
MEMORY
{
/* user code 72M */
COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */
HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE
HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */
}
REGION_ALIAS("RAM", COLD_MEMORY);
ENTRY(vexStartup)

View File

@ -1,19 +0,0 @@
#pragma once
#ifndef _Timer_h_
#define _Timer_h_
#include "main.h"
class Timer {
public:
Timer();
double getElapsedTimeMS();
void reset();
private:
double start;
};
#endif

View File

@ -1,22 +0,0 @@
#pragma once
#ifndef _Wings_h
#define _Wings_h_
#include "main.h"
class Wings {
public:
Wings();
void open();
void close();
void toggleLeft(int value);
void toggleRight(int value);
void openFor(double duration);
int getState();
private:
int left_wing_state;
int right_wing_state;
};
#endif

View File

@ -1,75 +0,0 @@
/**
* \file api.h
*
* PROS API header provides high-level user functionality
*
* Contains declarations for use by typical VEX programmers using PROS.
*
* This file should not be modified by users, since it gets replaced whenever
* a kernel upgrade occurs.
*
* \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots.
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef _PROS_API_H_
#define _PROS_API_H_
#ifdef __cplusplus
#include <cerrno>
#include <cmath>
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#else /* (not) __cplusplus */
#include <errno.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#endif /* __cplusplus */
#define PROS_VERSION_MAJOR 3
#define PROS_VERSION_MINOR 8
#define PROS_VERSION_PATCH 0
#define PROS_VERSION_STRING "3.8.0"
#include "pros/adi.h"
#include "pros/colors.h"
#include "pros/distance.h"
#include "pros/error.h"
#include "pros/ext_adi.h"
#include "pros/gps.h"
#include "pros/imu.h"
#include "pros/link.h"
#include "pros/llemu.h"
#include "pros/misc.h"
#include "pros/motors.h"
#include "pros/optical.h"
#include "pros/rtos.h"
#include "pros/rotation.h"
#include "pros/screen.h"
#include "pros/vision.h"
#ifdef __cplusplus
#include "pros/adi.hpp"
#include "pros/distance.hpp"
#include "pros/gps.hpp"
#include "pros/imu.hpp"
#include "pros/llemu.hpp"
#include "pros/misc.hpp"
#include "pros/motors.hpp"
#include "pros/optical.hpp"
#include "pros/rotation.hpp"
#include "pros/rtos.hpp"
#include "pros/screen.hpp"
#include "pros/vision.hpp"
#include "pros/link.hpp"
#endif
#include "asset.h"
#endif // _PROS_API_H_

View File

@ -1,184 +0,0 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "ary-lib/util.hpp"
#include "api.h"
class PID {
public:
/**
* Default constructor.
*/
PID();
/**
* Constructor with constants.
*
* \param p
* kP
* \param i
* ki
* \param d
* kD
* \param p_start_i
* error value that i starts within
* \param name
* std::string of name that prints
*/
PID(double p, double i = 0, double d = 0, double start_i = 0, std::string name = "");
/**
* Set constants for PID.
*
* \param p
* kP
* \param i
* ki
* \param d
* kD
* \param p_start_i
* error value that i starts within
*/
void set_constants(double p, double i = 0, double d = 0, double p_start_i = 0);
/**
* Struct for constants.
*/
struct Constants {
double kp;
double ki;
double kd;
double start_i;
};
/**
* Struct for exit condition.
*/
struct exit_condition_ {
int small_exit_time = 0;
double small_error = 0;
int big_exit_time = 0;
double big_error = 0;
int velocity_exit_time = 0;
int mA_timeout = 0;
};
/**
* Set's constants for exit conditions.
*
* \param p_small_exit_time
* Sets small_exit_time. Timer for to exit within smalL_error.
* \param p_small_error
* Sets smalL_error. Timer will start when error is within this.
* \param p_big_exit_time
* Sets big_exit_time. Timer for to exit within big_error.
* \param p_big_error
* Sets big_error. Timer will start when error is within this.
* \param p_velocity_exit_time
* Sets velocity_exit_time. Timer will start when velocity is 0.
*/
void set_exit_condition(int p_small_exit_time, double p_small_error, int p_big_exit_time = 0, double p_big_error = 0, int p_velocity_exit_time = 0, int p_mA_timeout = 0);
/**
* Set's target.
*
* \param target
* Target for PID.
*/
void set_target(double input);
/**
* Computes PID.
*
* \param current
* Current sensor library.
*/
double calculate(double current);
/**
* Returns target value.
*/
double get_target();
/**
* Returns constants.
*/
Constants get_constants();
/**
* Resets all variables to 0. This does not reset constants.
*/
void reset_variables();
/**
* Constants
*/
Constants constants;
/**
* Exit
*/
exit_condition_ exit;
/**
* Iterative exit condition for PID.
*
* \param print = false
* if true, prints when complete.
*/
ary::exit_output exit_condition(bool print = false);
/**
* Iterative exit condition for PID.
*
* \param sensor
* A pros motor on your mechanism.
* \param print = false
* if true, prints when complete.
*/
ary::exit_output exit_condition(pros::Motor sensor, bool print = false);
/**
* Iterative exit condition for PID.
*
* \param sensor
* Pros motors on your mechanism.
* \param print = false
* if true, prints when complete.
*/
ary::exit_output exit_condition(std::vector<pros::Motor> sensor, bool print = false);
/**
* Sets the name of the PID that prints during exit conditions.
*
* \param name
* a string that is the name you want to print
*/
void set_name(std::string name);
/**
* PID variables.
*/
double output;
double cur;
double error;
double target;
double lastError;
double integral;
double derivative;
long time;
long prev_time;
private:
int i = 0, j = 0, k = 0, l = 0;
bool is_mA = false;
void reset_timers();
std::string name;
bool is_name = false;
void print_exit(ary::exit_output exit_type);
};

View File

@ -1,14 +0,0 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "ary-lib/PID.hpp"
#include "ary-lib/auton.hpp"
#include "ary-lib/auton_selector.hpp"
#include "ary-lib/drive/drive.hpp"
#include "ary-lib/autonselector.hpp"
#include "ary-lib/util.hpp"

View File

@ -1,19 +0,0 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <functional>
#include <iostream>
class Auton {
public:
Auton();
Auton(std::string, std::function<void()>);
std::string Name;
std::function<void()> auton_call;
private:
};

View File

@ -1,23 +0,0 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <tuple>
#include "ary-lib/auton.hpp"
using namespace std;
class AutonSelector {
public:
std::vector<Auton> Autons;
int current_auton_page;
int auton_count;
AutonSelector();
AutonSelector(std::vector<Auton> autons);
void call_selected_auton();
void print_selected_auton();
void add_autons(std::vector<Auton> autons);
};

View File

@ -1,64 +0,0 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "ary-lib/auton_selector.hpp"
#include "api.h"
namespace ary {
namespace autonselector {
extern AutonSelector auton_selector;
/**
* Sets sd card to current page.
*/
void init_auton_selector();
/**
* Sets the sd card to current page.
*/
void update_auto_sd();
/**
* Increases the page by 1.
*/
void page_up();
/**
* Decreases the page by 1.
*/
void page_down();
/**
* Initializes LLEMU and sets up callbacks for auton selector.
*/
void initialize();
/**
* Wrapper for pros::lcd::shutdown.
*/
void shutdown();
extern bool turn_off;
extern pros::ADIDigitalIn* left_limit_switch;
extern pros::ADIDigitalIn* right_limit_switch;
/**
* Initialize two limitswithces to change pages on the lcd
*
* @param left_limit_port
* port for the left limit switch
* @param right_limit_port
* port for the right limit switch
*/
void limit_switch_lcd_initialize(pros::ADIDigitalIn* right_limit, pros::ADIDigitalIn* left_limit = nullptr);
/**
* pre_auto_task
*/
void limitSwitchTask();
}
}

View File

@ -1,856 +0,0 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <functional>
#include <iostream>
#include <tuple>
#include <cmath>
#include "ary-lib/PID.hpp"
#include "ary-lib/util.hpp"
#include "pros/motors.h"
#define VELOCITY_TO_VOLTS_LIN 196.001723856
#define VELOCITY_TO_VOLTS_ANG 127 / 0.796332147963
#define LINEAR_MAX_VEL 0.647953484803
#define LINEAR_FWD_ACCEL 0.647953484803 / 26
#define LINEAR_FWD_DECEL 0.647953484803 / 18
#define LINEAR_REV_ACCEL 0.647953484803 / 18
#define LINEAR_REV_DECEL 0.647953484803 / 32
#define ANGULAR_MAX_VEL 0.796332147963
#define ANGULAR_FWD_ACCEL 0.796332147963 / 40
#define ANGULAR_FWD_DECEL 0.796332147963 / 40
#define ANGULAR_REV_ACCEL 0.796332147963 / 40
#define ANGULAR_REV_DECEL 0.796332147963 / 40
using namespace ary;
class Drive {
public:
/**
* Joysticks will return 0 when they are within this number. Set with set_joystick_threshold()
*/
int JOYSTICK_THRESHOLD;
/**
* Global current brake mode.
*/
pros::motor_brake_mode_e_t CURRENT_BRAKE = pros::E_MOTOR_BRAKE_COAST;
/**
* Global current mA.
*/
int CURRENT_MA = 2500;
/**
* Current swing type.
*/
e_swing current_swing;
/**
* Vector of pros motors for the left chassis.
*/
std::vector<pros::Motor> left_motors;
/**
* Vector of pros motors for the right chassis.
*/
std::vector<pros::Motor> right_motors;
/**
* Vector of pros motors that are disconnected from the drive.
*/
std::vector<int> pto_active;
/**
* Inertial sensor.
*/
pros::Imu imu;
/**
* Left tracking wheel.
*/
pros::ADIEncoder left_tracker;
/**
* Right tracking wheel.
*/
pros::ADIEncoder right_tracker;
/**
* Left rotation tracker.
*/
pros::Rotation left_rotation;
/**
* Right rotation tracker.
*/
pros::Rotation right_rotation;
/**
* PID objects.
*/
PID headingPID;
PID turnPID;
PID forward_drivePID;
PID leftPID;
PID rightPID;
PID backward_drivePID;
PID swingPID;
/**
* Current mode of the drive.
*/
e_mode mode;
/**
* Sets current mode of drive.
*/
void set_mode(e_mode p_mode);
/**
* Returns current mode of drive.
*/
e_mode get_mode();
/**
* Calibrates imu and initializes sd card to curve.
*/
void initialize();
/**
* Tasks for autonomous.
*/
pros::Task ez_auto;
/**
* Creates a Drive Controller using internal encoders.
*
* \param left_motor_ports
* Input {1, -2...}. Make ports negative if reversed!
* \param right_motor_ports
* Input {-3, 4...}. Make ports negative if reversed!
* \param imu_port
* Port the IMU is plugged into.
* \param wheel_diameter
* Diameter of your drive wheels. Remember 4" is 4.125"!
* \param ticks
* Motor cartridge RPM
* \param ratio
* External gear ratio, wheel gear / motor gear.
*/
Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports, int imu_port, double wheel_diameter, double ticks, double ratio);
/**
* Creates a Drive Controller using encoders plugged into the brain.
*
* \param left_motor_ports
* Input {1, -2...}. Make ports negative if reversed!
* \param right_motor_ports
* Input {-3, 4...}. Make ports negative if reversed!
* \param imu_port
* Port the IMU is plugged into.
* \param wheel_diameter
* Diameter of your sensored wheels. Remember 4" is 4.125"!
* \param ticks
* Ticks per revolution of your encoder.
* \param ratio
* External gear ratio, wheel gear / sensor gear.
* \param left_tracker_ports
* Input {1, 2}. Make ports negative if reversed!
* \param right_tracker_ports
* Input {3, 4}. Make ports negative if reversed!
*/
Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports, int imu_port, double wheel_diameter, double ticks, double ratio, std::vector<int> left_tracker_ports, std::vector<int> right_tracker_ports);
/**
* Creates a Drive Controller using encoders plugged into a 3 wire expander.
*
* \param left_motor_ports
* Input {1, -2...}. Make ports negative if reversed!
* \param right_motor_ports
* Input {-3, 4...}. Make ports negative if reversed!
* \param imu_port
* Port the IMU is plugged into.
* \param wheel_diameter
* Diameter of your sensored wheels. Remember 4" is 4.125"!
* \param ticks
* Ticks per revolution of your encoder.
* \param ratio
* External gear ratio, wheel gear / sensor gear.
* \param left_tracker_ports
* Input {1, 2}. Make ports negative if reversed!
* \param right_tracker_ports
* Input {3, 4}. Make ports negative if reversed!
* \param expander_smart_port
* Port the expander is plugged into.
*/
Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports, int imu_port, double wheel_diameter, double ticks, double ratio, std::vector<int> left_tracker_ports, std::vector<int> right_tracker_ports, int expander_smart_port);
/**
* Creates a Drive Controller using rotation sensors.
*
* \param left_motor_ports
* Input {1, -2...}. Make ports negative if reversed!
* \param right_motor_ports
* Input {-3, 4...}. Make ports negative if reversed!
* \param imu_port
* Port the IMU is plugged into.
* \param wheel_diameter
* Diameter of your sensored wheels. Remember 4" is 4.125"!
* \param ratio
* External gear ratio, wheel gear / sensor gear.
* \param left_tracker_port
* Make ports negative if reversed!
* \param right_tracker_port
* Make ports negative if reversed!
*/
Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports, int imu_port, double wheel_diameter, double ratio, int left_rotation_port, int right_rotation_port);
/**
* Sets drive defaults.
*/
void set_defaults();
/////
//
// User Control
//
/////
/**
* Sets the chassis to controller joysticks using tank control. Run is usercontrol.
* This passes the controller through the curve functions, but is disabled by default. Use toggle_controller_curve_modifier() to enable it.
*/
void tank_control();
/**
* Sets the chassis to controller joysticks using standard arcade control. Run is usercontrol.
* This passes the controller through the curve functions, but is disabled by default. Use toggle_controller_curve_modifier() to enable it.
*
* \param stick_type
* ez::SINGLE or ez::SPLIT control
* \param curve_type
*/
void arcade_standard(e_type stick_type, e_curve_type curve_type);
/**
* Sets the chassis to controller joysticks using flipped arcade control. Run is usercontrol.
* This passes the controller through the curve functions, but is disabled by default. Use toggle_controller_curve_modifier() to enable it.
*
* \param stick_type
* ez::SINGLE or ez::SPLIT control
*/
void arcade_flipped(e_type stick_type);
/**
* Initializes left and right curves with the SD card, reccomended to run in initialize().
*/
void init_curve_sd();
/**
* Sets the default joystick curves.
*
* \param left
* Left default curve.
* \param right
* Right default curve.
*/
void set_curve_default(double left, double right = 0);
/**
* Runs a P loop on the drive when the joysticks are released.
*
* \param kp
* Constant for the p loop.
*/
void set_active_brake(double kp);
void set_cata_active_brake(double kp);
double get_cata_active_brake();
/**
* Enables/disables modifying the joystick input curves with the controller. True enables, false disables.
*
* \param input
* bool input
*/
void toggle_modify_curve_with_controller(bool toggle);
/**
* Sets buttons for modifying the left joystick curve.
*
* \param decrease
* a pros button enumerator
* \param increase
* a pros button enumerator
*/
void set_left_curve_buttons(pros::controller_digital_e_t decrease, pros::controller_digital_e_t increase);
/**
* Sets buttons for modifying the right joystick curve.
*
* \param decrease
* a pros button enumerator
* \param increase
* a pros button enumerator
*/
void set_right_curve_buttons(pros::controller_digital_e_t decrease, pros::controller_digital_e_t increase);
void set_curve_buttons(pros::controller_digital_e_t decrease, pros::controller_digital_e_t increase);
/**
* Outputs a curve from 5225A In the Zone. This gives more control over the robot at lower speeds. https://www.desmos.com/calculator/rcfjjg83zx
*
* \param x
* joystick input
*/
double left_curve_function(double x);
/**
* Outputs a curve from 5225A In the Zone. This gives more control over the robot at lower speeds. https://www.desmos.com/calculator/rcfjjg83zx
*
* \param x
* joystick input
*/
double right_curve_function(double x);
/**
* Sets a new threshold for the joystick. The joysticks wil not return a value if they are within this.
*
* \param threshold
* new threshold
*/
void set_joystick_threshold(int threshold);
void set_joystick_drivescale(double scaleval);
void set_joystick_turnscale(double scaleval);
/**
* Resets drive sensors at the start of opcontrol.
*/
void reset_drive_sensors_opcontrol();
/**
* Sets minimum slew distance constants.
*
* \param l_stick
* input for left joystick
* \param r_stick
* input for right joystick
*/
void joy_thresh_opcontrol(int l_stick, int r_stick);
/////
//
// PTO
//
/////
/**
* Checks if the motor is currently in pto_list. Returns true if it's already in pto_list.
*
* \param check_if_pto
* motor to check.
*/
bool pto_check(pros::Motor check_if_pto);
/**
* Adds motors to the pto list, removing them from the drive.
*
* \param pto_list
* list of motors to remove from the drive.
*/
void pto_add(std::vector<pros::Motor> pto_list);
/**
* Removes motors from the pto list, adding them to the drive. You cannot use the first index in a pto.
*
* \param pto_list
* list of motors to add to the drive.
*/
void pto_remove(std::vector<pros::Motor> pto_list);
/**
* Adds/removes motors from drive. You cannot use the first index in a pto.
*
* \param pto_list
* list of motors to add/remove from the drive.
* \param toggle
* if true, adds to list. if false, removes from list.
*/
void pto_toggle(std::vector<pros::Motor> pto_list, bool toggle);
/////
//
// PROS Wrapers
//
/////
/**
* Sets the chassis to voltage
*
* \param left
* voltage for left side, -127 to 127
* \param right
* voltage for right side, -127 to 127
*/
void set_tank(int left, int right);
/**
* Changes the way the drive behaves when it is not under active user control
*
* \param brake_type
* the 'brake mode' of the motor e.g. 'pros::E_MOTOR_BRAKE_COAST' 'pros::E_MOTOR_BRAKE_BRAKE' 'pros::E_MOTOR_BRAKE_HOLD'
*/
void set_drive_brake(pros::motor_brake_mode_e_t brake_type);
/**
* Sets the limit for the current on the drive.
*
* \param mA
* input in milliamps
*/
void set_drive_current_limit(int mA);
/**
* Toggles set drive in autonomous. True enables, false disables.
*/
void toggle_auto_drive(bool toggle);
/**
* Toggles printing in autonomous. True enables, false disables.
*/
void toggle_auto_print(bool toggle);
/////
//
// Telemetry
//
/////
/**
* The position of the right motor.
*/
int right_sensor();
/**
* The velocity of the right motor.
*/
int right_velocity();
/**
* The watts of the right motor.
*/
double right_mA();
/**
* Return TRUE when the motor is over current.
*/
bool right_over_current();
/**
* The position of the left motor.
*/
int left_sensor();
/**
* The velocity of the left motor.
*/
int left_velocity();
/**
* The watts of the left motor.
*/
double left_mA();
/**
* Return TRUE when the motor is over current.
*/
bool left_over_current();
/**
* Reset all the chassis motors, reccomended to run at the start of your autonomous routine.
*/
void reset_drive_sensor();
/**
* Resets the current gyro value. Defaults to 0, reccomended to run at the start of your autonomous routine.
*
* \param new_heading
* New heading value.
*/
void reset_gyro(double new_heading = 0);
/**
* Resets the imu so that where the drive is pointing is zero in set_drive_pid(turn)
*/
double get_gyro();
/**
* Calibrates the IMU, reccomended to run in initialize().
*
* \param run_loading_animation
* bool for running loading animation
*/
bool imu_calibrate(bool run_loading_animation = true);
/**
* Loading display while the IMU calibrates.
*/
void imu_loading_display(int iter);
/////
//
// Autonomous Functions
//
/////
/**
* Sets the robot to move forward using PID.
*
* \param target
* target value in inches
* \param speed
* 0 to 127, max speed during motion
* \param slew_on
* ramp up from slew_min to speed over slew_distance. only use when you're going over about 14"
* \param toggle_heading
* toggle for heading correction
*/
void set_drive(double target, int speed, bool slew_on = false, bool toggle_heading = true);
/*
Stops movement on the drivetrain
*/
void stop_drive(Drive& chassis);
/**
* Drives the robot forward using a trapezoidal motional profile
*
* /param target
* target value in inches
* /param endTimeout
* timeout value
*/
void set_proifiled_drive(Drive& chassis, double target, int endTimeout);
/**
* Sets the robot to turn using PID.
*
* \param target
* target value in degrees
* \param speed
* 0 to 127, max speed during motion
*/
void set_turn(double target, int speed);
/**
* Turn using only the left or right side.
*
* \param type
* L_SWING or R_SWING
* \param target
* target value in degrees
* \param speed
* 0 to 127, max speed during motion
*/
void set_swing(e_swing type, double target, int speed);
/**
* Resets all PID targets to 0.
*/
void reset_pid_targets();
/**
* Resets all PID targets to 0.
*/
void set_angle(double angle);
/**
* Lock the code in a while loop until the robot has settled.
*/
void wait_drive();
/**
* Lock the code in a while loop until this position has passed.
*
* \param target
* when driving, this is inches. when turning, this is degrees.
*/
void wait_until(double target);
/**
* Autonomous interference detection. Returns true when interfered, and false when nothing happened.
*/
bool interfered = false;
/**
* Changes max speed during a drive motion.
*
* \param speed
* new clipped speed
*/
void set_max_speed(int speed);
/**
* Set Either the headingPID, turnPID, forwardPID, backwardPID, activeBrakePID, or swingPID
*/
void set_pid_constants(PID *pid, double p, double i, double d, double p_start_i);
/**
* Sets minimum power for swings when kI and startI are enabled.
*
* \param min
* new clipped speed
*/
void set_swing_min(int min);
/**
* The minimum power for turns when kI and startI are enabled.
*
* \param min
* new clipped speed
*/
void set_turn_min(int min);
/**
* Returns minimum power for swings when kI and startI are enabled.
*/
int get_swing_min();
/**
* Returns minimum power for turns when kI and startI are enabled.
*/
int get_turn_min();
/**
* Sets minimum slew speed constants.
*
* \param fwd
* minimum power for forward drive pd
* \param rev
* minimum power for backwards drive pd
*/
void set_slew_min_power(int fwd, int rev);
/**
* Sets minimum slew distance constants.
*
* \param fw
* minimum distance for forward drive pd
* \param bw
* minimum distance for backwards drive pd
*/
void set_slew_distance(int fwd, int rev);
/**
* Set's constants for exit conditions.
*
* \param &type
* turn_exit, swing_exit, or drive_exit
* \param p_small_exit_time
* Sets small_exit_time. Timer for to exit within smalL_error.
* \param p_small_error
* Sets smalL_error. Timer will start when error is within this.
* \param p_big_exit_time
* Sets big_exit_time. Timer for to exit within big_error.
* \param p_big_error
* Sets big_error. Timer will start when error is within this.
* \param p_velocity_exit_time
* Sets velocity_exit_time. Timer will start when velocity is 0.
*/
void set_exit_condition(int type, int p_small_exit_time, double p_small_error, int p_big_exit_time, double p_big_error, int p_velocity_exit_time, int p_mA_timeout);
/**
* Exit condition for turning.
*/
const int turn_exit = 1;
/**
* Exit condition for swinging.
*/
const int swing_exit = 2;
/**
* Exit condition for driving.
*/
const int drive_exit = 3;
/**
* Returns current tick_per_inch()
*/
double get_tick_per_inch();
/**
* Returns current tick_per_inch()
*/
void modify_curve_with_controller();
// Slew
struct slew_ {
int sign = 0;
double error = 0;
double x_intercept = 0;
double y_intercept = 0;
double slope = 0;
double output = 0;
bool enabled = false;
double max_speed = 0;
};
slew_ left_slew;
slew_ right_slew;
/**
* Initialize slew.
*
* \param input
* slew_ enum
* \param slew_on
* is slew on?
* \param max_speed
* target speed during the slew
* \param target
* target sensor value
* \param current
* current sensor value
* \param start
* starting position
* \param backwards
* slew direction for constants
*/
void slew_initialize(slew_ &input, bool slew_on, double max_speed, double target, double current, double start, bool backwards);
/**
* Calculate slew.
*
* \param input
* slew_ enum
* \param current
* current sensor value
*/
double slew_calculate(slew_ &input, double current);
private: // !Auton
bool drive_toggle = true;
bool print_toggle = true;
int swing_min = 0;
int turn_min = 0;
/**
* Heading bool.
*/
bool heading_on = true;
/**
* Active brake kp constant.
*/
double active_brake_kp = 0;
/**
* Tick per inch calculation.
*/
double TICK_PER_REV;
double TICK_PER_INCH;
double CIRCUMFERENCE;
double CARTRIDGE;
double RATIO;
double WHEEL_DIAMETER;
/**
* Max speed for autonomous.
*/
int max_speed;
/**
* Tasks
*/
void drive_pid_task();
void swing_pid_task();
void turn_pid_task();
void ez_auto_task();
/**
* Constants for slew
*/
double SLEW_DISTANCE[2];
double SLEW_MIN_POWER[2];
/**
* Starting value for left/right
*/
double l_start = 0;
double r_start = 0;
/**
* Enable/disable modifying controller curve with controller.
*/
bool disable_controller = true; // True enables, false disables.
/**
* Is tank drive running?
*/
bool is_tank;
#define DRIVE_INTEGRATED 1
#define DRIVE_ADI_ENCODER 2
#define DRIVE_ROTATION 3
/**
* Is tracking?
*/
int is_tracker = DRIVE_INTEGRATED;
/**
* Save input to sd card
*/
void save_l_curve_sd();
void save_r_curve_sd();
/**
* Struct for buttons for increasing/decreasing curve with controller
*/
struct button_ {
bool lock = false;
bool release_reset = false;
int release_timer = 0;
int hold_timer = 0;
int increase_timer;
pros::controller_digital_e_t button;
};
button_ l_increase_;
button_ l_decrease_;
button_ r_increase_;
button_ r_decrease_;
/**
* Function for button presses.
*/
void button_press(button_ *input_name, int button, std::function<void()> changeCurve, std::function<void()> save);
/**
* The left and right curve scalers.
*/
double left_curve_scale;
double right_curve_scale;
/**
* Increase and decrease left and right curve scale.
*/
void l_decrease();
void l_increase();
void r_decrease();
void r_increase();
};

View File

@ -1,118 +0,0 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <bits/stdc++.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include "api.h"
/**
* Controller.
*/
extern pros::Controller master;
namespace ary {
/**
* Prints our branding all over your pros terminal
*/
void printScr();
/**
* Prints to the brain screen in one string. Splits input between lines with
* '\n' or when text longer then 32 characters.
*
* @param text
* Input string. Use '\n' for a new line
* @param line
* Starting line to print on, defaults to 0
*/
void print_to_screen(std::string text, int line = 0);
/////
//
// Public Variables
//
/////
enum e_curve_type {
DEFAULT = 0,
LOGARITHMIC = 1,
SQRT = 2,
SINE = 3,
};
/**
* Enum for split and single stick arcade.
*/
enum e_type { SINGLE = 0,
SPLIT = 1 };
/**
* Enum for split and single stick arcade.
*/
enum e_swing { LEFT_SWING = 0,
RIGHT_SWING = 1 };
/**
* Enum for PID::exit_condition outputs.
*/
enum exit_output { RUNNING = 1,
SMALL_EXIT = 2,
BIG_EXIT = 3,
VELOCITY_EXIT = 4,
mA_EXIT = 5,
ERROR_NO_CONSTANTS = 6 };
/**
* Enum for split and single stick arcade.
*/
enum e_mode { DISABLE = 0,
SWING = 1,
TURN = 2,
DRIVE = 3 };
/**
* Outputs string for exit_condition enum.
*/
std::string exit_to_string(exit_output input);
namespace util {
extern bool AUTON_RAN;
/**
* Returns 1 if input is positive and -1 if input is negative
*/
int signum(double input);
/**
* Returns true if the input is < 0
*/
bool is_reversed(double input);
/**
* Returns input restricted to min-max threshold
*/
double clip_num(double input, double max, double min);
std::vector<double> trapezoidalMotionProfile(double target, double maxVel, double accel, double decel);
/**
* Is the SD card plugged in?
*/
const bool IS_SD_CARD = pros::usd::is_installed();
/**
* Delay time for tasks
*/
const int DELAY_TIME = 10;
} // namespace util
} // ary

View File

@ -1,13 +0,0 @@
#pragma once
#include "ary-lib/drive/drive.hpp"
#include "main.h"
void near_side();
void far_side();
void skills();
void test_seq();
void odom_test();
void default_constants();
void exit_condition_defaults();

View File

@ -1,71 +0,0 @@
# Littlev Graphics Libraray
![LittlevGL cover](http://www.gl.littlev.hu/home/main_cover_small.png)
LittlevGL provides everything you need to create a Graphical User Interface (GUI) on embedded systems with easy-to-use graphical elements, beautiful visual effects and low memory footprint.
Homepage: https://littlevgl.com
### Table Of Content
* [Key features](#key-features)
* [Porting](#porting)
* [Project set-up](#project-set-up)
* [PC simulator](#pc-simulator)
* [Screenshots](#screenshots)
* [Contributing](#contributing)
* [Donate](#donate)
## Key features
* Powerful building blocks buttons, charts, lists, sliders, images etc
* Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling
* Various input devices touch pad, mouse, keyboard, encoder, buttons etc
* Multi language support with UTF-8 decoding
* Fully customizable graphical elements
* Hardware independent to use with any microcontroller or display
* Scalable to operate with few memory (50 kB Flash, 10 kB RAM)
* OS, External memory and GPU supported but not required
* Single frame buffer operation even with advances graphical effects
* Written in C for maximal compatibility
* Simulator to develop on PC without embedded hardware
* Tutorials, examples, themes for rapid development
* Documentation and API references online
## Porting
In the most sime case you need 4 things:
1. Call `lv_tick_inc(1)` in every millisecods in a Timer or Task
2. Register a function which can **copy a pixel array** to an area of the screen
3. Register a function which can **read an input device**. (E.g. touch pad)
4. Call `lv_task_handler()` periodically in every few milliseconds
For more information visit https://littlevgl.com/porting
## Project set-up
1. **Clone** or [Download](https://littlevgl.com/download) the lvgl repository: `git clone https://github.com/littlevgl/lvgl.git`
2. **Create project** with your preferred IDE and add the *lvgl* folder
3. Copy **lvgl/lv_conf_templ.h** as **lv_conf.h** next to the *lvgl* folder
4. In the lv_conf.h delete the first `#if 0` and its `#endif`. Let the default configurations at first.
5. In your *main.c*: #include "lvgl/lvgl.h"
6. In your *main function*:
* lvgl_init();
* tick, display and input device initialization (see above)
7. To **test** create a label: `lv_obj_t * label = lv_label_create(lv_scr_act(), NULL);`
8. In the main *while(1)* call `lv_task_handler();` and make a few milliseconds delay (e.g. `my_delay_ms(5);`)
9. Compile the code and load it to your embedded hardware
## PC Simulator
If you don't have got an embedded hardware you can test the graphics library in a PC simulator. The simulator uses [SDL2](https://www.libsdl.org/) to emulate a display on your monitor and a touch pad with your mouse.
There is a pre-configured PC project for **Eclipse CDT** in this repository: https://github.com/littlevgl/pc_simulator
## Screenshots
![TFT material](http://www.gl.littlev.hu/github_res/tft_material.png)
![TFT zen](http://www.gl.littlev.hu/github_res/tft_zen.png)
![TFT alien](http://www.gl.littlev.hu/github_res/tft_alien.png)
![TFT night](http://www.gl.littlev.hu/github_res/tft_night.png)
## Contributing
See [CONTRIBUTING.md](https://github.com/littlevgl/lvgl/blob/master/docs/CONTRIBUTING.md)
## Donate
If you are pleased with the graphics library, found it useful or be happy with the support you got, please help its further development:
[![Donate](https://littlevgl.com/donate_dir/donate_btn.png)](https://littlevgl.com/donate)

View File

@ -1,8 +0,0 @@
MIT licence
Copyright (c) 2016 Gábor Kiss-Vámosi
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,12 +0,0 @@
CSRCS += lv_group.c
CSRCS += lv_indev.c
CSRCS += lv_obj.c
CSRCS += lv_refr.c
CSRCS += lv_style.c
CSRCS += lv_vdb.c
CSRCS += lv_lang.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core
VPATH += :$(LVGL_DIR)/lvgl/lv_core
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_core"

View File

@ -1,14 +0,0 @@
CSRCS += lv_draw_vbasic.c
CSRCS += lv_draw_rbasic.c
CSRCS += lv_draw.c
CSRCS += lv_draw_rect.c
CSRCS += lv_draw_label.c
CSRCS += lv_draw_line.c
CSRCS += lv_draw_img.c
CSRCS += lv_draw_arc.c
CSRCS += lv_draw_triangle.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw
VPATH += :$(LVGL_DIR)/lvgl/lv_draw
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_draw"

View File

@ -1,23 +0,0 @@
CSRCS += lv_font_builtin.c
CSRCS += lv_font_dejavu_10.c
CSRCS += lv_font_dejavu_20.c
CSRCS += lv_font_dejavu_30.c
CSRCS += lv_font_dejavu_40.c
CSRCS += lv_font_dejavu_10_cyrillic.c
CSRCS += lv_font_dejavu_20_cyrillic.c
CSRCS += lv_font_dejavu_30_cyrillic.c
CSRCS += lv_font_dejavu_40_cyrillic.c
CSRCS += lv_font_dejavu_10_latin_sup.c
CSRCS += lv_font_dejavu_20_latin_sup.c
CSRCS += lv_font_dejavu_30_latin_sup.c
CSRCS += lv_font_dejavu_40_latin_sup.c
CSRCS += lv_font_symbol_10.c
CSRCS += lv_font_symbol_20.c
CSRCS += lv_font_symbol_30.c
CSRCS += lv_font_symbol_40.c
CSRCS += lv_font_monospace_8.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_fonts
VPATH += :$(LVGL_DIR)/lvgl/lv_fonts
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_fonts"

View File

@ -1,8 +0,0 @@
CSRCS += lv_hal_disp.c
CSRCS += lv_hal_indev.c
CSRCS += lv_hal_tick.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_hal
VPATH += :$(LVGL_DIR)/lvgl/lv_hal
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_hal"

View File

@ -1,19 +0,0 @@
CSRCS += lv_font.c
CSRCS += lv_circ.c
CSRCS += lv_area.c
CSRCS += lv_task.c
CSRCS += lv_fs.c
CSRCS += lv_anim.c
CSRCS += lv_mem.c
CSRCS += lv_ll.c
CSRCS += lv_color.c
CSRCS += lv_txt.c
CSRCS += lv_ufs.c
CSRCS += lv_math.c
CSRCS += lv_log.c
CSRCS += lv_gc.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_misc
VPATH += :$(LVGL_DIR)/lvgl/lv_misc
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_misc"

View File

@ -1,36 +0,0 @@
CSRCS += lv_arc.c
CSRCS += lv_bar.c
CSRCS += lv_cb.c
CSRCS += lv_ddlist.c
CSRCS += lv_kb.c
CSRCS += lv_line.c
CSRCS += lv_mbox.c
CSRCS += lv_preload.c
CSRCS += lv_roller.c
CSRCS += lv_table.c
CSRCS += lv_tabview.c
CSRCS += lv_tileview.c
CSRCS += lv_btn.c
CSRCS += lv_calendar.c
CSRCS += lv_chart.c
CSRCS += lv_canvas.c
CSRCS += lv_gauge.c
CSRCS += lv_label.c
CSRCS += lv_list.c
CSRCS += lv_slider.c
CSRCS += lv_ta.c
CSRCS += lv_spinbox.c
CSRCS += lv_btnm.c
CSRCS += lv_cont.c
CSRCS += lv_img.c
CSRCS += lv_imgbtn.c
CSRCS += lv_led.c
CSRCS += lv_lmeter.c
CSRCS += lv_page.c
CSRCS += lv_sw.c
CSRCS += lv_win.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_objx
VPATH += :$(LVGL_DIR)/lvgl/lv_objx
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_objx"

View File

@ -1,14 +0,0 @@
CSRCS += lv_theme_alien.c
CSRCS += lv_theme.c
CSRCS += lv_theme_default.c
CSRCS += lv_theme_night.c
CSRCS += lv_theme_templ.c
CSRCS += lv_theme_zen.c
CSRCS += lv_theme_material.c
CSRCS += lv_theme_nemo.c
CSRCS += lv_theme_mono.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_themes
VPATH += :$(LVGL_DIR)/lvgl/lv_themes
CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_themes"

View File

@ -1,207 +0,0 @@
// Formatting library for C++ - dynamic argument lists
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_ARGS_H_
#define FMT_ARGS_H_
#include <functional> // std::reference_wrapper
#include <memory> // std::unique_ptr
#include <vector>
#include "core.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T> struct is_reference_wrapper : std::false_type {};
template <typename T> struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T> const T& unwrap(const T& v) { return v; }
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) { return static_cast<const T&>(v); }
class dynamic_arg_list {
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
// templates it doesn't complain about inability to deduce single translation
// unit for placing vtable. So storage_node_base is made a fake template.
template <typename = void> struct node {
virtual ~node() = default;
std::unique_ptr<node<>> next;
};
template <typename T> struct typed_node : node<> {
T value;
template <typename Arg> FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
template <typename Char> FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
: value(arg.data(), arg.size()) {}
};
std::unique_ptr<node<>> head_;
public:
template <typename T, typename Arg> const T& push(const Arg& arg) {
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
auto& value = new_node->value;
new_node->next = std::move(head_);
head_ = std::move(new_node);
return value;
}
};
} // namespace detail
/**
\rst
A dynamic version of `fmt::format_arg_store`.
It's equipped with a storage to potentially temporary objects which lifetimes
could be shorter than the format arguments object.
It can be implicitly converted into `~fmt::basic_format_args` for passing
into type-erased formatting functions such as `~fmt::vformat`.
\endrst
*/
template <typename Context> class dynamic_format_arg_store
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
private:
using char_type = typename Context::char_type;
template <typename T> struct need_copy {
static constexpr detail::type mapped_type = detail::mapped_type_constant<T, Context>::value;
enum {
value = !(detail::is_reference_wrapper<T>::value ||
std::is_same<T, basic_string_view<char_type>>::value ||
std::is_same<T, detail::std_string_view<char_type>>::value ||
(mapped_type != detail::type::cstring_type && mapped_type != detail::type::string_type &&
mapped_type != detail::type::custom_type))
};
};
template <typename T> using stored_type =
conditional_t<std::is_convertible<T, std::basic_string<char_type>>::value &&
!detail::is_reference_wrapper<T>::value,
std::basic_string<char_type>, T>;
// Storage of basic_format_arg must be contiguous.
std::vector<basic_format_arg<Context>> data_;
std::vector<detail::named_arg_info<char_type>> named_info_;
// Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it.
detail::dynamic_arg_list dynamic_args_;
friend class basic_format_args<Context>;
unsigned long long get_types() const {
return detail::is_unpacked_bit | data_.size() |
(named_info_.empty() ? 0ULL : static_cast<unsigned long long>(detail::has_named_args_bit));
}
const basic_format_arg<Context>* data() const { return named_info_.empty() ? data_.data() : data_.data() + 1; }
template <typename T> void emplace_arg(const T& arg) { data_.emplace_back(detail::make_arg<Context>(arg)); }
template <typename T> void emplace_arg(const detail::named_arg<char_type, T>& arg) {
if (named_info_.empty()) {
constexpr const detail::named_arg_info<char_type>* zero_ptr {nullptr};
data_.insert(data_.begin(), {zero_ptr, 0});
}
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { data->pop_back(); };
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> guard {&data_, pop_one};
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
guard.release();
}
public:
constexpr dynamic_format_arg_store() = default;
/**
\rst
Adds an argument into the dynamic store for later passing to a formatting
function.
Note that custom types and string types (but not string views) are copied
into the store dynamically allocating memory if necessary.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc");
store.push_back(1.5f);
std::string result = fmt::vformat("{} and {} and {}", store);
\endrst
*/
template <typename T> void push_back(const T& arg) {
if (detail::const_check(need_copy<T>::value)) emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
else emplace_arg(detail::unwrap(arg));
}
/**
\rst
Adds a reference to the argument into the dynamic store for later passing to
a formatting function.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
char band[] = "Rolling Stones";
store.push_back(std::cref(band));
band[9] = 'c'; // Changing str affects the output.
std::string result = fmt::vformat("{}", store);
// result == "Rolling Scones"
\endrst
*/
template <typename T> void push_back(std::reference_wrapper<T> arg) {
static_assert(need_copy<T>::value, "objects of built-in types and string views are always copied");
emplace_arg(arg.get());
}
/**
Adds named argument into the dynamic store for later passing to a formatting
function. ``std::reference_wrapper`` is supported to avoid copying of the
argument. The name is always copied into the store.
*/
template <typename T> void push_back(const detail::named_arg<char_type, T>& arg) {
const char_type* arg_name = dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
if (detail::const_check(need_copy<T>::value)) {
emplace_arg(fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
} else {
emplace_arg(fmt::arg(arg_name, arg.value));
}
}
/** Erase all elements from the store */
void clear() {
data_.clear();
named_info_.clear();
dynamic_args_ = detail::dynamic_arg_list();
}
/**
\rst
Reserves space to store at least *new_cap* arguments including
*new_cap_named* named arguments.
\endrst
*/
void reserve(size_t new_cap, size_t new_cap_named) {
FMT_ASSERT(new_cap >= new_cap_named, "Set of arguments includes set of named arguments");
data_.reserve(new_cap);
named_info_.reserve(new_cap_named);
}
};
FMT_END_NAMESPACE
#endif // FMT_ARGS_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +0,0 @@
#pragma once
#include "main.h"
#include "Wings.h"
#include "Timer.h"
#define TRACK_WIDTH 11.5
#define PLACEHOLDER_TC_OFFSET 2.5
#define WHEEL_SIZE 2.75
#define DRIVE_RATIO 0.75
#define DRIVE_RPM 450
namespace globals {
extern pros::Controller master;
extern pros::Motor motor_tlf;
extern pros::Motor motor_tlb;
extern pros::Motor motor_blf;
extern pros::Motor motor_blb;
extern pros::Motor motor_trf;
extern pros::Motor motor_trb;
extern pros::Motor motor_brf;
extern pros::Motor motor_brb;
extern pros::Motor_Group left_drive;
extern pros::Motor_Group right_drive;
extern lemlib::Drivetrain_t dt_odom;
extern lemlib::OdomSensors_t chassis_sensors;
extern lemlib::ChassisController_t latController;
extern lemlib::ChassisController_t angController;
extern lemlib::Chassis chassis_odom;
extern pros::Rotation rot_vert;
extern pros::Rotation rot_horiz;
extern pros::Rotation enc_theta;
extern pros::ADIDigitalOut pto_piston;
extern pros::ADIDigitalOut left_wing_piston;
extern pros::ADIDigitalOut right_wing_piston;
extern pros::ADIDigitalOut intake_piston;
extern pros::ADIDigitalOut climb_piston;
extern Wings wings;
extern Timer timer;
extern lemlib::TrackingWheel vert_tracking_wheel;
extern lemlib::TrackingWheel horiz_tracking_wheel;
extern pros::Imu inertial_sensor;
extern Drive chassis;
extern pros::Motor& intake_mtr;
extern pros::Motor& cata_mtr;
enum e_controlsch {
RENU,
RIA,
CHRIS
};
}

View File

@ -1,19 +0,0 @@
/**
* @file include/lemlib/api.hpp
* @author LemLib Team
* @brief LemLib API header file. Include this in your source files to use the library.
* @version 0.4.5
* @date 2023-01-27
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include "lemlib/util.hpp"
#include "lemlib/pid.hpp"
#include "lemlib/pose.hpp"
#include "lemlib/chassis/trackingWheel.hpp"
#include "lemlib/chassis/chassis.hpp"
#include "lemlib/logger/logger.hpp"

View File

@ -1,18 +0,0 @@
#pragma once
#include <stdint.h>
#include <cstddef>
extern "C" {
typedef struct __attribute__((__packed__)) _asset {
uint8_t* buf;
size_t size;
} asset;
}
#define ASSET(x) \
extern "C" { \
extern uint8_t _binary_static_##x##_start[], _binary_static_##x##_size[]; \
static asset x = {_binary_static_##x##_start, (size_t)_binary_static_##x##_size}; \
}

View File

@ -1,299 +0,0 @@
/**
* @file include/lemlib/chassis/chassis.hpp
* @author LemLib Team
* @brief Chassis class declarations
* @version 0.4.5
* @date 2023-01-23
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include <functional>
#include "pros/rtos.hpp"
#include "pros/motors.hpp"
#include "pros/imu.hpp"
#include "lemlib/asset.hpp"
#include "lemlib/chassis/trackingWheel.hpp"
#include "lemlib/pose.hpp"
namespace lemlib {
/**
* @brief Struct containing all the sensors used for odometry
*
*/
struct OdomSensors {
/**
* The sensors are stored in a struct so that they can be easily passed to the chassis class
* The variables are pointers so that they can be set to nullptr if they are not used
* Otherwise the chassis class would have to have a constructor for each possible combination of sensors
*
* @param vertical1 pointer to the first vertical tracking wheel
* @param vertical2 pointer to the second vertical tracking wheel
* @param horizontal1 pointer to the first horizontal tracking wheel
* @param horizontal2 pointer to the second horizontal tracking wheel
* @param imu pointer to the IMU
*/
OdomSensors(TrackingWheel* vertical1, TrackingWheel* vertical2, TrackingWheel* horizontal1,
TrackingWheel* horizontal2, pros::Imu* imu);
TrackingWheel* vertical1;
TrackingWheel* vertical2;
TrackingWheel* horizontal1;
TrackingWheel* horizontal2;
pros::Imu* imu;
};
/**
* @brief Struct containing constants for a chassis controller
*
*/
struct ControllerSettings {
/**
* The constants are stored in a struct so that they can be easily passed to the chassis class
* Set a constant to 0 and it will be ignored
*
* @param kP proportional constant for the chassis controller
* @param kD derivative constant for the chassis controller
* @param smallError the error at which the chassis controller will switch to a slower control loop
* @param smallErrorTimeout the time the chassis controller will wait before switching to a slower control loop
* @param largeError the error at which the chassis controller will switch to a faster control loop
* @param largeErrorTimeout the time the chassis controller will wait before switching to a faster control loop
* @param slew the maximum acceleration of the chassis controller
*/
ControllerSettings(float kP, float kD, float smallError, float smallErrorTimeout, float largeError,
float largeErrorTimeout, float slew);
float kP;
float kD;
float smallError;
float smallErrorTimeout;
float largeError;
float largeErrorTimeout;
float slew;
};
/**
* @brief Struct containing constants for a drivetrain
*
*/
struct Drivetrain {
/**
* The constants are stored in a struct so that they can be easily passed to the chassis class
* Set a constant to 0 and it will be ignored
*
* @param leftMotors pointer to the left motors
* @param rightMotors pointer to the right motors
* @param trackWidth the track width of the robot
* @param wheelDiameter the diameter of the wheel used on the drivetrain
* @param rpm the rpm of the wheels
* @param chasePower higher values make the robot move faster but causes more overshoot on turns
*/
Drivetrain(pros::MotorGroup* leftMotors, pros::MotorGroup* rightMotors, float trackWidth, float wheelDiameter,
float rpm, float chasePower);
pros::Motor_Group* leftMotors;
pros::Motor_Group* rightMotors;
float trackWidth;
float wheelDiameter;
float rpm;
float chasePower;
};
/**
* @brief Function pointer type for drive curve functions.
* @param input The control input in the range [-127, 127].
* @param scale The scaling factor, which can be optionally ignored.
* @return The new value to be used.
*/
typedef std::function<float(float, float)> DriveCurveFunction_t;
/**
* @brief Default drive curve. Modifies the input with an exponential curve. If the input is 127, the function
* will always output 127, no matter the value of scale, likewise for -127. This curve was inspired by team
* 5225, the Pilons. A Desmos graph of this curve can be found here:
* https://www.desmos.com/calculator/rcfjjg83zx
* @param input value from -127 to 127
* @param scale how steep the curve should be.
* @return The new value to be used.
*/
float defaultDriveCurve(float input, float scale);
/**
* @brief Chassis class
*
*/
class Chassis {
public:
/**
* @brief Construct a new Chassis
*
* @param drivetrain drivetrain to be used for the chassis
* @param linearSettings settings for the linear controller
* @param angularSettings settings for the angular controller
* @param sensors sensors to be used for odometry
* @param driveCurve drive curve to be used. defaults to `defaultDriveCurve`
*/
Chassis(Drivetrain drivetrain, ControllerSettings linearSettings, ControllerSettings angularSettings,
OdomSensors sensors, DriveCurveFunction_t driveCurve = &defaultDriveCurve);
/**
* @brief Calibrate the chassis sensors
*
* @param calibrateIMU whether the IMU should be calibrated. true by default
*/
void calibrate(bool calibrateIMU = true);
/**
* @brief Set the pose of the chassis
*
* @param x new x value
* @param y new y value
* @param theta new theta value
* @param radians true if theta is in radians, false if not. False by default
*/
void setPose(float x, float y, float theta, bool radians = false);
/**
* @brief Set the pose of the chassis
*
* @param pose the new pose
* @param radians whether pose theta is in radians (true) or not (false). false by default
*/
void setPose(Pose pose, bool radians = false);
/**
* @brief Get the pose of the chassis
*
* @param radians whether theta should be in radians (true) or degrees (false). false by default
* @return Pose
*/
Pose getPose(bool radians = false);
/**
* @brief Get the speed of the robot
*
* @param radians true for theta in radians, false for degrees. False by default
* @return lemlib::Pose
*/
Pose getSpeed(bool radians = false);
/**
* @brief Get the local speed of the robot
*
* @param radians true for theta in radians, false for degrees. False by default
* @return lemlib::Pose
*/
Pose getLocalSpeed(bool radians = false);
/**
* @brief Estimate the pose of the robot after a certain amount of time
*
* @param time time in seconds
* @param radians False for degrees, true for radians. False by default
* @return lemlib::Pose
*/
Pose estimatePose(float time, bool radians = false);
/**
* @brief Wait until the robot has traveled a certain distance along the path
*
* @note Units are in inches if current motion is moveTo or follow, degrees if using turnTo
*
* @param dist the distance the robot needs to travel before returning
*/
void waitUntil(float dist);
/**
* @brief Wait until the robot has completed the path
*
*/
void waitUntilDone();
/**
* @brief Turn the chassis so it is facing the target point
*
* The PID logging id is "angularPID"
*
* @param x x location
* @param y y location
* @param timeout longest time the robot can spend moving
* @param forwards whether the robot should turn to face the point with the front of the robot. true by
* default
* @param maxSpeed the maximum speed the robot can turn at. Default is 127
* @param async whether the function should be run asynchronously. true by default
*/
void turnTo(float x, float y, int timeout, bool forwards = true, float maxSpeed = 127, bool async = true);
/**
* @brief Move the chassis towards the target pose
*
* Uses the boomerang controller
*
* @param x x location
* @param y y location
* @param theta target heading in degrees.
* @param timeout longest time the robot can spend moving
* @param forwards whether the robot should move forwards or backwards. true for forwards (default),
* false for backwards
* @param chasePower higher values make the robot move faster but causes more overshoot on turns. 0
* makes it default to global value
* @param lead the lead parameter. Determines how curved the robot will move. 0.6 by default (0 < lead <
* 1)
* @param maxSpeed the maximum speed the robot can move at. 127 at default
* @param async whether the function should be run asynchronously. true by default
*/
void moveToPose(float x, float y, float theta, int timeout, bool forwards = true, float chasePower = 0,
float lead = 0.6, float maxSpeed = 127, bool async = true);
/**
* @brief Move the chassis towards a target point
*
* @param x x location
* @param y y location
* @param timeout longest time the robot can spend moving
* @param maxSpeed the maximum speed the robot can move at. 127 by default
* @param async whether the function should be run asynchronously. true by default
*/
void moveToPoint(float x, float y, int timeout, bool forwards = true, float maxSpeed = 127, bool async = true);
/**
* @brief Move the chassis along a path
*
* @param path the path asset to follow
* @param lookahead the lookahead distance. Units in inches. Larger values will make the robot move
* faster but will follow the path less accurately
* @param timeout the maximum time the robot can spend moving
* @param forwards whether the robot should follow the path going forwards. true by default
* @param async whether the function should be run asynchronously. true by default
*/
void follow(const asset& path, float lookahead, int timeout, bool forwards = true, bool async = true);
/**
* @brief Control the robot during the driver control period using the tank drive control scheme. In
* this control scheme one joystick axis controls one half of the robot, and another joystick axis
* controls another.
* @param left speed of the left side of the drivetrain. Takes an input from -127 to 127.
* @param right speed of the right side of the drivetrain. Takes an input from -127 to 127.
* @param curveGain control how steep the drive curve is. The larger the number, the steeper the curve.
* A value of 0 disables the curve entirely.
*/
void tank(int left, int right, float curveGain = 0.0);
/**
* @brief Control the robot during the driver using the arcade drive control scheme. In this control
* scheme one joystick axis controls the forwards and backwards movement of the robot, while the other
* joystick axis controls the robot's turning
* @param throttle speed to move forward or backward. Takes an input from -127 to 127.
* @param turn speed to turn. Takes an input from -127 to 127.
* @param curveGain the scale inputted into the drive curve function. If you are using the default drive
* curve, refer to the `defaultDriveCurve` documentation.
*/
void arcade(int throttle, int turn, float curveGain = 0.0);
/**
* @brief Control the robot during the driver using the curvature drive control scheme. This control
* scheme is very similar to arcade drive, except the second joystick axis controls the radius of the
* curve that the drivetrain makes, rather than the speed. This means that the driver can accelerate in
* a turn without changing the radius of that turn. This control scheme defaults to arcade when forward
* is zero.
* @param throttle speed to move forward or backward. Takes an input from -127 to 127.
* @param turn speed to turn. Takes an input from -127 to 127.
* @param curveGain the scale inputted into the drive curve function. If you are using the default drive
* curve, refer to the `defaultDriveCurve` documentation.
*/
void curvature(int throttle, int turn, float cureGain = 0.0);
private:
pros::Mutex mutex;
float distTravelled = 0;
ControllerSettings linearSettings;
ControllerSettings angularSettings;
Drivetrain drivetrain;
OdomSensors sensors;
DriveCurveFunction_t driveCurve;
};
} // namespace lemlib

View File

@ -1,72 +0,0 @@
/**
* @file include/lemlib/chassis/odom.hpp
* @author LemLib Team
* @brief This is the header file for the odom.cpp file. Its not meant to be used directly, only through the chassis
* class
* @version 0.4.5
* @date 2023-01-23
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include "lemlib/chassis/chassis.hpp"
#include "lemlib/pose.hpp"
namespace lemlib {
/**
* @brief Set the sensors to be used for odometry
*
* @param sensors the sensors to be used
* @param drivetrain drivetrain to be used
*/
void setSensors(lemlib::OdomSensors sensors, lemlib::Drivetrain drivetrain);
/**
* @brief Get the pose of the robot
*
* @param radians true for theta in radians, false for degrees. False by default
* @return Pose
*/
Pose getPose(bool radians = false);
/**
* @brief Set the Pose of the robot
*
* @param pose the new pose
* @param radians true if theta is in radians, false if in degrees. False by default
*/
void setPose(Pose pose, bool radians = false);
/**
* @brief Get the speed of the robot
*
* @param radians true for theta in radians, false for degrees. False by default
* @return lemlib::Pose
*/
Pose getSpeed(bool radians = false);
/**
* @brief Get the local speed of the robot
*
* @param radians true for theta in radians, false for degrees. False by default
* @return lemlib::Pose
*/
Pose getLocalSpeed(bool radians = false);
/**
* @brief Estimate the pose of the robot after a certain amount of time
*
* @param time time in seconds
* @param radians False for degrees, true for radians. False by default
* @return lemlib::Pose
*/
Pose estimatePose(float time, bool radians = false);
/**
* @brief Update the pose of the robot
*
*/
void update();
/**
* @brief Initialize the odometry system
*
*/
void init();
} // namespace lemlib

View File

@ -1,99 +0,0 @@
/**
* @file include/lemlib/chassis/trackingWheel.hpp
* @author LemLib Team
* @brief tracking wheel class declarations
* @version 0.4.5
* @date 2023-01-23
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include "pros/motors.hpp"
#include "pros/adi.hpp"
#include "pros/rotation.hpp"
namespace lemlib {
/**
* @brief A namespace representing the size of omniwheels.
*/
namespace Omniwheel {
constexpr float NEW_275 = 2.75;
constexpr float OLD_275 = 2.75;
constexpr float NEW_275_HALF = 2.744;
constexpr float OLD_275_HALF = 2.74;
constexpr float NEW_325 = 3.25;
constexpr float OLD_325 = 3.25;
constexpr float NEW_325_HALF = 3.246;
constexpr float OLD_325_HALF = 3.246;
constexpr float NEW_4 = 4;
constexpr float OLD_4 = 4.18;
constexpr float NEW_4_HALF = 3.995;
constexpr float OLD_4_HALF = 4.175;
} // namespace Omniwheel
class TrackingWheel {
public:
/**
* @brief Create a new tracking wheel
*
* @param encoder the optical shaft encoder to use
* @param wheelDiameter the diameter of the wheel
* @param distance distance between the tracking wheel and the center of rotation in inches
* @param gearRatio gear ratio of the tracking wheel, defaults to 1
*/
TrackingWheel(pros::ADIEncoder* encoder, float wheelDiameter, float distance, float gearRatio = 1);
/**
* @brief Create a new tracking wheel
*
* @param encoder the v5 rotation sensor to use
* @param wheelDiameter the diameter of the wheel
* @param distance distance between the tracking wheel and the center of rotation in inches
* @param gearRatio gear ratio of the tracking wheel, defaults to 1
*/
TrackingWheel(pros::Rotation* encoder, float wheelDiameter, float distance, float gearRatio = 1);
/**
* @brief Create a new tracking wheel
*
* @param motors the motor group to use
* @param wheelDiameter the diameter of the wheel
* @param distance half the track width of the drivetrain in inches
* @param rpm theoretical maximum rpm of the drivetrain wheels
*/
TrackingWheel(pros::Motor_Group* motors, float wheelDiameter, float distance, float rpm);
/**
* @brief Reset the tracking wheel position to 0
*
*/
void reset();
/**
* @brief Get the distance traveled by the tracking wheel
*
* @return float distance traveled in inches
*/
float getDistanceTraveled();
/**
* @brief Get the offset of the tracking wheel from the center of rotation
*
* @return float offset in inches
*/
float getOffset();
/**
* @brief Get the type of tracking wheel
*
* @return int - 1 if motor group, 0 otherwise
*/
int getType();
private:
float diameter;
float distance;
float rpm;
pros::ADIEncoder* encoder = nullptr;
pros::Rotation* rotation = nullptr;
pros::Motor_Group* motors = nullptr;
float gearRatio = 1;
};
} // namespace lemlib

View File

@ -1,209 +0,0 @@
#pragma once
#include <initializer_list>
#include "pros/rtos.hpp"
#define FMT_HEADER_ONLY
#include "fmt/core.h"
#include "fmt/args.h"
#include "lemlib/logger/message.hpp"
namespace lemlib {
/**
* @brief A base for any sink in LemLib to implement.
*
* Sinks are LemLib's abstraction for destinations that logged messages can be sent to. They are the backbone of the
* logging implementation. A sink could send information to anything, to stdout, to a file, or even the UI on the
* brain screen.
*/
class BaseSink {
public:
BaseSink() = default;
/**
* @brief Construct a new combined sink
*
* <h3> Example Usage </h3>
* @code
* lemlib::BaseSink combinedSink({lemlib::telemetrySink(), lemlib::infoSink()});
* combinedSink.info("This will be sent to both sinks!");
* @endcode
*
* @param sinks The sinks that will have messages sent to them when
*/
BaseSink(std::initializer_list<std::shared_ptr<BaseSink>> sinks);
/**
* @brief Set the lowest level.
* If this is a combined sink, this operation will
* apply for all the parent sinks.
* @param level
*
* If messages are logged that are below the lowest level, they will be ignored.
* The hierarchy of the levels is as follows:
* - INFO
* - DEBUG
* - WARN
* - ERROR
* - FATAL
*/
void setLowestLevel(Level level);
/**
* @brief Log a message at the given level
* If this is a combined sink, this operation will
* apply for all the parent sinks.
*
* @tparam T
* @param level The level at which to send the message.
* @param format The format that the message will use. Use "{}" as placeholders.
* @param args The values that will be substituted into the placeholders in the format.
*
* <h3> Example Usage </h3>
* @code
* sink.log(lemlib::Level::INFO, "{} from the logger!", "Hello");
* @endcode
*/
template <typename... T> void log(Level level, fmt::format_string<T...> format, T&&... args) {
if (!sinks.empty()) {
for (std::shared_ptr<BaseSink> sink : sinks) { sink->log(level, format, std::forward<T>(args)...); }
return;
}
if (level < lowestLevel) { return; }
// substitute the user's arguments into the format.
std::string messageString = fmt::format(format, std::forward<T>(args)...);
Message message = Message {.level = level, .time = pros::millis()};
// get the arguments
fmt::dynamic_format_arg_store<fmt::format_context> formattingArgs = getExtraFormattingArgs(message);
formattingArgs.push_back(fmt::arg("time", message.time));
formattingArgs.push_back(fmt::arg("level", message.level));
formattingArgs.push_back(fmt::arg("message", messageString));
std::string formattedString = fmt::vformat(logFormat, std::move(formattingArgs));
message.message = std::move(formattedString);
sendMessage(std::move(message));
}
/**
* @brief Log a message at the debug level.
* If this is a combined sink, this operation will
* apply for all the parent sinks.
* @tparam T
* @param format
* @param args
*/
template <typename... T> void debug(fmt::format_string<T...> format, T&&... args) {
log(Level::DEBUG, format, std::forward<T>(args)...);
}
/**
* @brief Log a message at the info level
* If this is a combined sink, this operation will
* apply for all the parent sinks.
* @tparam T
* @param format
* @param args
*/
template <typename... T> void info(fmt::format_string<T...> format, T&&... args) {
log(Level::INFO, format, std::forward<T>(args)...);
}
/**
* @brief Log a message at the warn level
* If this is a combined sink, this operation will
* apply for all the parent sinks.
* @tparam T
* @param format
* @param args
*/
template <typename... T> void warn(fmt::format_string<T...> format, T&&... args) {
log(Level::WARN, format, std::forward<T>(args)...);
}
/**
* @brief Log a message at the error level.
* If this is a combined sink, this operation will
* apply for all the parent sinks.
* @tparam T
* @param format
* @param args
*/
template <typename... T> void error(fmt::format_string<T...> format, T&&... args) {
log(Level::ERROR, format, std::forward<T>(args)...);
}
/**
* @brief Log a message at the fatal level
* If this is a combined sink, this operation will
* apply for all the parent sinks.
* @tparam T
* @param format
* @param args
*/
template <typename... T> void fatal(fmt::format_string<T...> format, T&&... args) {
log(Level::FATAL, format, std::forward<T>(args)...);
}
protected:
/**
* @brief Log the given message
*
* @param message
*/
virtual void sendMessage(const Message& message);
/**
* @brief Set the format of messages that the sink sends
*
* @param format
*
* Changing the format of the sink changes the way each logged message looks. The following named formatting
* specifiers can be used:
* - {time} The time the message was sent in milliseconds since the program started.
* - {level} The level of the logged message.
* - {message} The message itself.
*
* <h3> Example Usage </h3>
* @code
* infoSink()->setFormat("[LemLib] -- {time} -- {level}: {Message}");
* infoSink()->info("hello");
* // This will be formatted as:
* // "[LemLIb] -- 10 -- INFO: hello"
* @endcode
*/
void setFormat(const std::string& format);
/**
* @brief Get the extra named arguments for formatting
*
* Can be overridden to add extra named arguments to the sink's format.
* <h3> Example Usage </h3>
*
* The following code would add a {zero} formatting argument which could be used in setFormat method of this
* sink.
*
* @code
* fmt::dynamic_format_arg_store<fmt::format_context>
* ExampleSink::getExtraFormattingArgs(const Message& messageInfo) {
* fmt::dynamic_format_arg_store<fmt::format_context> args;
* args.push_back(fmt::arg("zero", 0);
* return args;
* }
* @endcode
*
* @return fmt::dynamic_format_arg_store<fmt::format_context>
*/
virtual fmt::dynamic_format_arg_store<fmt::format_context> getExtraFormattingArgs(const Message& messageInfo);
private:
Level lowestLevel = Level::DEBUG;
std::string logFormat;
std::vector<std::shared_ptr<BaseSink>> sinks {};
};
} // namespace lemlib

View File

@ -1,72 +0,0 @@
#pragma once
#include <deque>
#include <functional>
#include <string>
#include "pros/rtos.hpp"
namespace lemlib {
/**
* @brief A buffer implementation
*
* Asynchronously processes a backlog of strings at a given rate. The strings are processed in a first in last out
* order.
*/
class Buffer {
public:
/**
* @brief Construct a new Buffer object
*
*/
Buffer(std::function<void(const std::string&)> bufferFunc);
/**
* @brief Destroy the Buffer object
*
*/
~Buffer();
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
/**
* @brief Push to the buffer
*
* @param bufferData
*/
void pushToBuffer(const std::string& bufferData);
/**
* @brief Set the rate of the sink
*
* @param rate
*/
void setRate(uint32_t rate);
/**
* @brief Check to see if the internal buffer is empty
*
*/
bool buffersEmpty();
private:
/**
* @brief The function that will be run inside of the buffer's task.
*
*/
void taskLoop();
/**
* @brief The function that will be applied to each string in the buffer when it is removed.
*
*/
std::function<void(std::string)> bufferFunc;
std::deque<std::string> buffer = {};
pros::Mutex mutex;
pros::Task task;
uint32_t rate;
};
} // namespace lemlib

View File

@ -1,39 +0,0 @@
#pragma once
#include <deque>
#include "pros/rtos.hpp"
#include "lemlib/logger/message.hpp"
#include "lemlib/logger/baseSink.hpp"
namespace lemlib {
/**
* @brief Sink for sending messages to the terminal.
*
* This is the primary way of interacting with LemLib's logging implementation. This sink is used for printing useful
* information to the user's terminal.
* <h3> Example Usage </h3>
* @code
* lemlib::infoSink()->setLowestLevel(lemlib::Level::INFO);
* lemlib::infoSink()->info("info: {}!", "my cool info here");
* // Specify the order or placeholders
* lemlib::infoSink()->debug("{1} {0}!","world", "hello");
* // Specify the precision of floating point numbers
* lemlib::infoSink()->warn("Thingy exceeded value: {:.2f}!", 93.1234);
* @endcode
*/
class InfoSink : public BaseSink {
public:
/**
* @brief Construct a new Info Sink object
*/
InfoSink();
private:
/**
* @brief Log the given message
*
* @param message
*/
void sendMessage(const Message& message) override;
};
} // namespace lemlib

View File

@ -1,26 +0,0 @@
#pragma once
#include <memory>
#include <array>
#define FMT_HEADER_ONLY
#include "fmt/core.h"
#include "lemlib/logger/baseSink.hpp"
#include "lemlib/logger/infoSink.hpp"
#include "lemlib/logger/telemetrySink.hpp"
namespace lemlib {
/**
* @brief Get the info sink.
* @return std::shared_ptr<InfoSink>
*/
std::shared_ptr<InfoSink> infoSink();
/**
* @brief Get the telemetry sink.
* @return std::shared_ptr<TelemetrySink>
*/
std::shared_ptr<TelemetrySink> telemetrySink();
} // namespace lemlib

View File

@ -1,34 +0,0 @@
#pragma once
#include <string>
namespace lemlib {
/**
* @brief Level of the message
*
*/
enum class Level { INFO, DEBUG, WARN, ERROR, FATAL };
/**
* @brief A loggable message
*
*/
struct Message {
/* The message */
std::string message;
/** The level of the message */
Level level;
/** The time the message was logged, in milliseconds */
uint32_t time;
};
/**
* @brief Format a level
*
* @param level
* @return std::string
*/
std::string format_as(Level level);
} // namespace lemlib

View File

@ -1,34 +0,0 @@
#pragma once
#define FMT_HEADER_ONLY
#include "fmt/core.h"
#include "lemlib/logger/buffer.hpp"
namespace lemlib {
/**
* @brief Buffered printing to Stout.
*
* LemLib uses a buffered wrapper around stdout in order to guarantee that messages are printed at a constant
* rate, no matter how many different threads are trying to use the logger. This is a concern because not every type of
* connection to the brain has the same amount of bandwidth.
*/
class BufferedStdout : public Buffer {
public:
BufferedStdout();
/**
* @brief Print a string (thread-safe).
*
*/
template <typename... T> void print(fmt::format_string<T...> format, T&&... args) {
pushToBuffer(fmt::format(format, std::forward<T>(args)...));
}
};
/**
* @brief Get the buffered stdout.
*
*/
BufferedStdout& bufferedStdout();
} // namespace lemlib

View File

@ -1,34 +0,0 @@
#pragma once
#include "lemlib/logger/baseSink.hpp"
namespace lemlib {
/**
* @brief Sink for sending telemetry data.
*
* This is the primary way of interacting with the telemetry portion of LemLib's logging implementation. This sink is
* used for sending data that is not meant to be viewed by the user, but will still be used by something else, like a
* data visualization tool. Messages sent through this sink will not be cleared from the terminal and not be visible to
* the user.
* <h3> Example Usage </h3>
* @code
* lemlib::telemetrySink()->setLowestLevel(lemlib::Level::INFO);
* lemlib::telemetrySink()->info("{},{}", motor1.get_temperature(), motor2.get_temperature());
* @endcode
*/
class TelemetrySink : public BaseSink {
public:
/**
* @brief Construct a new Telemetry Sink object
*/
TelemetrySink();
private:
/**
* @brief Log the given message
*
* @param message
*/
void sendMessage(const Message& message) override;
};
} // namespace lemlib

View File

@ -1,125 +0,0 @@
/**
* @file include/lemlib/pid.hpp
* @author Lemlib Team
* @brief FAPID class header
* @version 0.4.5
* @date 2023-01-15
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include <string>
#include "pros/rtos.hpp"
namespace lemlib {
/**
* @brief Feedforward, Acceleration, Proportional, Integral, Derivative PID controller
*
* The controller does not loop on its own. It must be called in a loop.
* For example: while(!controller.settled) { controller.update(input, output); }
*
*/
class FAPID {
public:
/**
* @brief Construct a new FAPID
*
* @param kF feedfoward gain, multiplied by target and added to output. Set 0 if disabled
* @param kA acceleration gain, limits the change in output. Set 0 if disabled
* @param kP proportional gain, multiplied by error and added to output
* @param kI integral gain, multiplied by total error and added to output
* @param kD derivative gain, multiplied by change in error and added to output
* @param name name of the FAPID. Used for logging
*/
FAPID(float kF, float kA, float kP, float kI, float kD, std::string name);
/**
* @brief Set gains
*
* @param kF feedfoward gain, multiplied by target and added to output. Set 0 if disabled
* @param kA acceleration gain, limits the change in output. Set 0 if disabled
* @param kP proportional gain, multiplied by error and added to output
* @param kI integral gain, multiplied by total error and added to output
* @param kD derivative gain, multiplied by change in error and added to output
*/
void setGains(float kF, float kA, float kP, float kI, float kD);
/**
* @brief Set the exit conditions
*
* @param largeError range where error is considered large
* @param smallError range where error is considered small
* @param largeTime time in milliseconds t
* @param smallTime
* @param maxTime
*/
void setExit(float largeError, float smallError, int largeTime, int smallTime, int maxTime);
/**
* @brief Update the FAPID
*
* @param target the target value
* @param position the current value
* @param log whether to check the most recent terminal input for user input. Default is false because logging
* multiple PIDs could slow down the program.
* @return float - output
*/
float update(float target, float position, bool log = false);
/**
* @brief Reset the FAPID
*/
void reset();
/**
* @brief Check if the FAPID has settled
*
* If the exit conditions have not been set, this function will always return false
*
* @return true - the FAPID has settled
* @return false - the FAPID has not settled
*/
bool settled();
/**
* @brief initialize the FAPID logging system
*
* if this function is called, std::cin will be used to interact with the FAPID
*
* the user can interact with the FAPID through the terminal
* the user can access gains and other variables with the following format:
* <name>.<variable> to get the value of the variable
* <name>.<variable>_<value> to set the value of the variable
* for example:
* pid.kP_0.5 will set the kP value to 0.5
* list of variables thats value can be set:
* kF, kA, kP, kI, kD
* list of variables that can be accessed:
* kF, kA, kP, kI, kD, totalError
* list of functions that can be called:
* reset()
*/
static void init();
private:
float kF;
float kA;
float kP;
float kI;
float kD;
float largeError;
float smallError;
int largeTime = 0;
int smallTime = 0;
int maxTime = -1; // -1 means no max time set, run forever
int largeTimeCounter = 0;
int smallTimeCounter = 0;
int startTime = 0;
float prevError = 0;
float totalError = 0;
float prevOutput = 0;
void log();
std::string name;
static std::string input;
static pros::Task* logTask;
static pros::Mutex logMutex;
};
} // namespace lemlib

View File

@ -1,105 +0,0 @@
/**
* @file include/lemlib/pose.hpp
* @author LemLib Team
* @brief Pose class declarations
* @version 0.4.5
* @date 2023-01-23
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include <string>
namespace lemlib {
class Pose {
public:
/** @brief x value*/
float x;
/** @brief y value*/
float y;
/** @brief theta value*/
float theta;
/**
* @brief Create a new pose
*
* @param x component
* @param y component
* @param theta heading. Defaults to 0
*/
Pose(float x, float y, float theta = 0);
/**
* @brief Add a pose to this pose
*
* @param other other pose
* @return Pose
*/
Pose operator+(const Pose& other);
/**
* @brief Subtract a pose from this pose
*
* @param other other pose
* @return Pose
*/
Pose operator-(const Pose& other);
/**
* @brief Multiply a pose by this pose
*
* @param other other pose
* @return Pose
*/
float operator*(const Pose& other);
/**
* @brief Multiply a pose by a float
*
* @param other float
* @return Pose
*/
Pose operator*(const float& other);
/**
* @brief Divide a pose by a float
*
* @param other float
* @return Pose
*/
Pose operator/(const float& other);
/**
* @brief Linearly interpolate between two poses
*
* @param other the other pose
* @param t t value
* @return Pose
*/
Pose lerp(Pose other, float t);
/**
* @brief Get the distance between two poses
*
* @param other the other pose
* @return float
*/
float distance(Pose other);
/**
* @brief Get the angle between two poses
*
* @param other the other pose
* @return float in radians
*/
float angle(Pose other);
/**
* @brief Rotate a pose by an angle
*
* @param angle angle in radians
* @return Pose
*/
Pose rotate(float angle);
};
/**
* @brief Format a pose
*
* @param pose
* @return std::string
*/
std::string format_as(const Pose& pose);
} // namespace lemlib

View File

@ -1,71 +0,0 @@
#pragma once
#include <cstdint>
namespace lemlib {
class Timer {
public:
/**
* @brief Construct a new Timer
*
* @param time how long to wait, in milliseconds
*/
Timer(uint32_t time);
/**
* @brief Get the amount of time the timer was set to
*
* @return uint32_t time, in milliseconds
*/
uint32_t getTimeSet();
/**
* @brief Get the amount of time left on the timer
*
* @return uint32_t time in milliseconds
*/
uint32_t getTimeLeft();
/**
* @brief Get the amount of time passed on the timer
*
* @return uint32_t time in milliseconds
*/
uint32_t getTimePassed();
/**
* @brief Get whether the timer is done or not
*
* @return true the timer is done
* @return false the timer is not done
*/
bool isDone();
/**
* @brief Set the amount of time the timer should count down. Resets the timer
*
* @param time time in milliseconds
*/
void set(uint32_t time);
/**
* @brief reset the timer
*
*/
void reset();
/**
* @brief pause the timer
*
*/
void pause();
/**
* @brief resume the timer
*
*/
void resume();
/**
* @brief wait
*
*/
void waitUntilDone();
private:
uint32_t period;
uint32_t lastTime;
uint32_t timeWaited = 0;
bool paused = false;
};
} // namespace lemlib

View File

@ -1,95 +0,0 @@
/**
* @file include/lemlib/util.hpp
* @author LemLib Team
* @brief Utility functions declarations
* @version 0.4.5
* @date 2023-01-15
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include <vector>
#include <math.h>
#include "lemlib/pose.hpp"
namespace lemlib {
/**
* @brief Slew rate limiter
*
* @param target target value
* @param current current value
* @param maxChange maximum change. No maximum if set to 0
* @return float - the limited value
*/
float slew(float target, float current, float maxChange);
/**
* @brief Convert radians to degrees
*
* @param rad radians
* @return float degrees
*/
constexpr float radToDeg(float rad) { return rad * 180 / M_PI; }
/**
* @brief Convert degrees to radians
*
* @param deg degrees
* @return float radians
*/
constexpr float degToRad(float deg) { return deg * M_PI / 180; }
/**
* @brief Calculate the error between 2 angles. Useful when calculating the error between 2 headings
*
* @param angle1
* @param angle2
* @param radians true if angle is in radians, false if not. False by default
* @return float wrapped angle
*/
float angleError(float angle1, float angle2, bool radians = false);
/**
* @brief Return the sign of a number
*
* @param x the number to get the sign of
* @return int - -1 if negative, 1 if positive
*/
template <typename T> constexpr T sgn(T value) { return value < 0 ? -1 : 1; }
/**
* @brief Return the average of a vector of numbers
*
* @param values
* @return float
*/
float avg(std::vector<float> values);
/**
* @brief Exponential moving average
*
* @param current current measurement
* @param previous previous output
* @param smooth smoothing factor (0-1). 1 means no smoothing, 0 means no change
* @return float - the smoothed output
*/
float ema(float current, float previous, float smooth);
/**
* @brief Get the signed curvature of a circle that intersects the first pose and the second pose
*
* @note The circle will be tangent to the theta value of the first pose
* @note The curvature is signed. Positive curvature means the circle is going clockwise, negative means
* counter-clockwise
* @note Theta has to be in radians and in standard form. That means 0 is right and increases counter-clockwise
*
* @param pose the first pose
* @param other the second pose
* @return float curvature
*/
float getCurvature(Pose pose, Pose other);
} // namespace lemlib

View File

@ -1,80 +0,0 @@
/**
* \file main.h
*
* Contains common definitions and header files used throughout your PROS
* project.
*
* \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots.
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef _PROS_MAIN_H_
#define _PROS_MAIN_H_
/**
* If defined, some commonly used enums will have preprocessor macros which give
* a shorter, more convenient naming pattern. If this isn't desired, simply
* comment the following line out.
*
* For instance, E_CONTROLLER_MASTER has a shorter name: CONTROLLER_MASTER.
* E_CONTROLLER_MASTER is pedantically correct within the PROS styleguide, but
* not convenient for most student programmers.
*/
#define PROS_USE_SIMPLE_NAMES
/**
* If defined, C++ literals will be available for use. All literals are in the
* pros::literals namespace.
*
* For instance, you can do `4_mtr = 50` to set motor 4's target velocity to 50
*/
#define PROS_USE_LITERALS
#include "api.h"
#include "ary-lib/api.hpp"
#include "lemlib/api.hpp"
#include "globals.hpp"
#include "superstructure.hpp"
#include "autons.hpp"
#include "wings.h"
#include "Timer.h"
#include "okapi/api.hpp"
/**
* You should add more #includes here
*/
//#include "okapi/api.hpp"
//#include "pros/api_legacy.h"
/**
* If you find doing pros::Motor() to be tedious and you'd prefer just to do
* Motor, you can use the namespace with the following commented out line.
*
* IMPORTANT: Only the okapi or pros namespace may be used, not both
* concurrently! The okapi namespace will export all symbols inside the pros
* namespace.
*/
// using namespace pros;
// using namespace pros::literals;
// using namespace okapi;
/**
* Prototypes for the competition control tasks are redefined here to ensure
* that they can be called from user code (i.e. calling autonomous from a
* button press in opcontrol() for testing purposes).
*/
#ifdef __cplusplus
extern "C" {
#endif
void autonomous(void);
void initialize(void);
void disabled(void);
void competition_initialize(void);
void opcontrol(void);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
/**
* You can add C++-only headers here
*/
//#include <iostream>
#endif
#endif // _PROS_MAIN_H_

View File

@ -1,134 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
/** @mainpage OkapiLib Index Page
*
* @section intro_sec Introduction
*
* **OkapiLib** is a PROS library for programming VEX V5 robots. This library is intended to raise
* the floor for teams with all levels of experience. New teams should have an easier time getting
* their robot up and running, and veteran teams should find that OkapiLib doesn't get in the way or
* place any limits on functionality.
*
* For tutorials on how to get the most out of OkapiLib, see the
* [Tutorials](docs/tutorials/index.md) section. For documentation on using the OkapiLib API, see
* the [API](docs/api/index.md) section.
*
* @section getting_started Getting Started
* Not sure where to start? Take a look at the
* [Getting Started](docs/tutorials/walkthrough/gettingStarted.md) tutorial.
* Once you have OkapiLib set up, check out the
* [Clawbot](docs/tutorials/walkthrough/clawbot.md) tutorial.
*
* @section using_docs Using The Documentation
*
* Start with reading the [Tutorials](docs/tutorials/index.md). Use the [API](docs/api/index.md)
* section to explore the class hierarchy. To see a list of all available classes, use the
* [Classes](annotated.html) section.
*
* This documentation has a powerful search feature, which can be brought up with the keyboard
* shortcuts `Tab` or `T`. All exports to the `okapi` namespace such as enums, constants, units, or
* functions can be found [here](@ref okapi).
*/
#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp"
#include "okapi/api/chassis/controller/chassisControllerPid.hpp"
#include "okapi/api/chassis/controller/chassisScales.hpp"
#include "okapi/api/chassis/controller/defaultOdomChassisController.hpp"
#include "okapi/api/chassis/controller/odomChassisController.hpp"
#include "okapi/api/chassis/model/hDriveModel.hpp"
#include "okapi/api/chassis/model/readOnlyChassisModel.hpp"
#include "okapi/api/chassis/model/skidSteerModel.hpp"
#include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp"
#include "okapi/api/chassis/model/threeEncoderXDriveModel.hpp"
#include "okapi/api/chassis/model/xDriveModel.hpp"
#include "okapi/impl/chassis/controller/chassisControllerBuilder.hpp"
#include "okapi/api/control/async/asyncLinearMotionProfileController.hpp"
#include "okapi/api/control/async/asyncMotionProfileController.hpp"
#include "okapi/api/control/async/asyncPosIntegratedController.hpp"
#include "okapi/api/control/async/asyncPosPidController.hpp"
#include "okapi/api/control/async/asyncVelIntegratedController.hpp"
#include "okapi/api/control/async/asyncVelPidController.hpp"
#include "okapi/api/control/async/asyncWrapper.hpp"
#include "okapi/api/control/controllerInput.hpp"
#include "okapi/api/control/controllerOutput.hpp"
#include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp"
#include "okapi/api/control/iterative/iterativePosPidController.hpp"
#include "okapi/api/control/iterative/iterativeVelPidController.hpp"
#include "okapi/api/control/util/controllerRunner.hpp"
#include "okapi/api/control/util/flywheelSimulator.hpp"
#include "okapi/api/control/util/pidTuner.hpp"
#include "okapi/api/control/util/settledUtil.hpp"
#include "okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp"
#include "okapi/impl/control/async/asyncPosControllerBuilder.hpp"
#include "okapi/impl/control/async/asyncVelControllerBuilder.hpp"
#include "okapi/impl/control/iterative/iterativeControllerFactory.hpp"
#include "okapi/impl/control/util/controllerRunnerFactory.hpp"
#include "okapi/impl/control/util/pidTunerFactory.hpp"
#include "okapi/api/odometry/odomMath.hpp"
#include "okapi/api/odometry/odometry.hpp"
#include "okapi/api/odometry/threeEncoderOdometry.hpp"
#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp"
#include "okapi/api/device/rotarysensor/rotarySensor.hpp"
#include "okapi/impl/device/adiUltrasonic.hpp"
#include "okapi/impl/device/button/adiButton.hpp"
#include "okapi/impl/device/button/controllerButton.hpp"
#include "okapi/impl/device/controller.hpp"
#include "okapi/impl/device/distanceSensor.hpp"
#include "okapi/impl/device/motor/adiMotor.hpp"
#include "okapi/impl/device/motor/motor.hpp"
#include "okapi/impl/device/motor/motorGroup.hpp"
#include "okapi/impl/device/opticalSensor.hpp"
#include "okapi/impl/device/rotarysensor/IMU.hpp"
#include "okapi/impl/device/rotarysensor/adiEncoder.hpp"
#include "okapi/impl/device/rotarysensor/adiGyro.hpp"
#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp"
#include "okapi/impl/device/rotarysensor/potentiometer.hpp"
#include "okapi/impl/device/rotarysensor/rotationSensor.hpp"
#include "okapi/api/filter/averageFilter.hpp"
#include "okapi/api/filter/composableFilter.hpp"
#include "okapi/api/filter/demaFilter.hpp"
#include "okapi/api/filter/ekfFilter.hpp"
#include "okapi/api/filter/emaFilter.hpp"
#include "okapi/api/filter/filter.hpp"
#include "okapi/api/filter/filteredControllerInput.hpp"
#include "okapi/api/filter/medianFilter.hpp"
#include "okapi/api/filter/passthroughFilter.hpp"
#include "okapi/api/filter/velMath.hpp"
#include "okapi/impl/filter/velMathFactory.hpp"
#include "okapi/api/units/QAcceleration.hpp"
#include "okapi/api/units/QAngle.hpp"
#include "okapi/api/units/QAngularAcceleration.hpp"
#include "okapi/api/units/QAngularJerk.hpp"
#include "okapi/api/units/QAngularSpeed.hpp"
#include "okapi/api/units/QArea.hpp"
#include "okapi/api/units/QForce.hpp"
#include "okapi/api/units/QFrequency.hpp"
#include "okapi/api/units/QJerk.hpp"
#include "okapi/api/units/QLength.hpp"
#include "okapi/api/units/QMass.hpp"
#include "okapi/api/units/QPressure.hpp"
#include "okapi/api/units/QSpeed.hpp"
#include "okapi/api/units/QTime.hpp"
#include "okapi/api/units/QTorque.hpp"
#include "okapi/api/units/QVolume.hpp"
#include "okapi/api/units/RQuantityName.hpp"
#include "okapi/api/util/abstractRate.hpp"
#include "okapi/api/util/abstractTimer.hpp"
#include "okapi/api/util/mathUtil.hpp"
#include "okapi/api/util/supplier.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include "okapi/impl/util/configurableTimeUtilFactory.hpp"
#include "okapi/impl/util/rate.hpp"
#include "okapi/impl/util/timeUtilFactory.hpp"
#include "okapi/impl/util/timer.hpp"

View File

@ -1,142 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/controller/chassisScales.hpp"
#include "okapi/api/chassis/model/chassisModel.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include "okapi/api/units/QAngle.hpp"
#include "okapi/api/units/QLength.hpp"
#include <memory>
#include <valarray>
namespace okapi {
class ChassisController {
public:
/**
* A ChassisController adds a closed-loop layer on top of a ChassisModel. moveDistance and
* turnAngle both use closed-loop control to move the robot. There are passthrough functions for
* everything defined in ChassisModel.
*
* @param imodel underlying ChassisModel
*/
explicit ChassisController() = default;
virtual ~ChassisController() = default;
/**
* Drives the robot straight for a distance (using closed-loop control).
*
* @param itarget distance to travel
*/
virtual void moveDistance(QLength itarget) = 0;
/**
* Drives the robot straight for a distance (using closed-loop control).
*
* @param itarget distance to travel in motor degrees
*/
virtual void moveRaw(double itarget) = 0;
/**
* Sets the target distance for the robot to drive straight (using closed-loop control).
*
* @param itarget distance to travel
*/
virtual void moveDistanceAsync(QLength itarget) = 0;
/**
* Sets the target distance for the robot to drive straight (using closed-loop control).
*
* @param itarget distance to travel in motor degrees
*/
virtual void moveRawAsync(double itarget) = 0;
/**
* Turns the robot clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for
*/
virtual void turnAngle(QAngle idegTarget) = 0;
/**
* Turns the robot clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for in motor degrees
*/
virtual void turnRaw(double idegTarget) = 0;
/**
* Sets the target angle for the robot to turn clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for
*/
virtual void turnAngleAsync(QAngle idegTarget) = 0;
/**
* Sets the target angle for the robot to turn clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for in motor degrees
*/
virtual void turnRawAsync(double idegTarget) = 0;
/**
* Sets whether turns should be mirrored.
*
* @param ishouldMirror whether turns should be mirrored
*/
virtual void setTurnsMirrored(bool ishouldMirror) = 0;
/**
* Checks whether the internal controllers are currently settled.
*
* @return Whether this ChassisController is settled.
*/
virtual bool isSettled() = 0;
/**
* Delays until the currently executing movement completes.
*/
virtual void waitUntilSettled() = 0;
/**
* Interrupts the current movement to stop the robot.
*/
virtual void stop() = 0;
/**
* Sets a new maximum velocity in RPM [0-600].
*
* @param imaxVelocity The new maximum velocity.
*/
virtual void setMaxVelocity(double imaxVelocity) = 0;
/**
* @return The maximum velocity in RPM [0-600].
*/
virtual double getMaxVelocity() const = 0;
/**
* Get the ChassisScales.
*/
virtual ChassisScales getChassisScales() const = 0;
/**
* Get the GearsetRatioPair.
*/
virtual AbstractMotor::GearsetRatioPair getGearsetRatioPair() const = 0;
/**
* @return The internal ChassisModel.
*/
virtual std::shared_ptr<ChassisModel> getModel() = 0;
/**
* @return The internal ChassisModel.
*/
virtual ChassisModel &model() = 0;
};
} // namespace okapi

View File

@ -1,184 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/controller/chassisController.hpp"
#include "okapi/api/control/async/asyncPosIntegratedController.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
namespace okapi {
class ChassisControllerIntegrated : public ChassisController {
public:
/**
* ChassisController using the V5 motor's integrated control. Puts the motors into encoder count
* units. Throws a `std::invalid_argument` exception if the gear ratio is zero. The initial
* model's max velocity will be propagated to the controllers.
*
* @param itimeUtil The TimeUtil.
* @param imodel The ChassisModel used to read from sensors/write to motors.
* @param ileftController The controller used for the left side motors.
* @param irightController The controller used for the right side motors.
* @param igearset The internal gearset and external ratio used on the drive motors.
* @param iscales The ChassisScales.
* @param ilogger The logger this instance will log to.
*/
ChassisControllerIntegrated(
const TimeUtil &itimeUtil,
std::shared_ptr<ChassisModel> imodel,
std::unique_ptr<AsyncPosIntegratedController> ileftController,
std::unique_ptr<AsyncPosIntegratedController> irightController,
const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green,
const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR),
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
/**
* Drives the robot straight for a distance (using closed-loop control).
*
* ```cpp
* // Drive forward 6 inches
* chassis->moveDistance(6_in);
*
* // Drive backward 0.2 meters
* chassis->moveDistance(-0.2_m);
* ```
*
* @param itarget distance to travel
*/
void moveDistance(QLength itarget) override;
/**
* Drives the robot straight for a distance (using closed-loop control).
*
* ```cpp
* // Drive forward by spinning the motors 400 degrees
* chassis->moveRaw(400);
* ```
*
* @param itarget distance to travel in motor degrees
*/
void moveRaw(double itarget) override;
/**
* Sets the target distance for the robot to drive straight (using closed-loop control).
*
* @param itarget distance to travel
*/
void moveDistanceAsync(QLength itarget) override;
/**
* Sets the target distance for the robot to drive straight (using closed-loop control).
*
* @param itarget distance to travel in motor degrees
*/
void moveRawAsync(double itarget) override;
/**
* Turns the robot clockwise in place (using closed-loop control).
*
* ```cpp
* // Turn 90 degrees clockwise
* chassis->turnAngle(90_deg);
* ```
*
* @param idegTarget angle to turn for
*/
void turnAngle(QAngle idegTarget) override;
/**
* Turns the robot clockwise in place (using closed-loop control).
*
* ```cpp
* // Turn clockwise by spinning the motors 200 degrees
* chassis->turnRaw(200);
* ```
*
* @param idegTarget angle to turn for in motor degrees
*/
void turnRaw(double idegTarget) override;
/**
* Sets the target angle for the robot to turn clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for
*/
void turnAngleAsync(QAngle idegTarget) override;
/**
* Sets the target angle for the robot to turn clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for in motor degrees
*/
void turnRawAsync(double idegTarget) override;
/**
* Sets whether turns should be mirrored.
*
* @param ishouldMirror whether turns should be mirrored
*/
void setTurnsMirrored(bool ishouldMirror) override;
/**
* Checks whether the internal controllers are currently settled.
*
* @return Whether this ChassisController is settled.
*/
bool isSettled() override;
/**
* Delays until the currently executing movement completes.
*/
void waitUntilSettled() override;
/**
* Interrupts the current movement to stop the robot.
*/
void stop() override;
/**
* Get the ChassisScales.
*/
ChassisScales getChassisScales() const override;
/**
* Get the GearsetRatioPair.
*/
AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override;
/**
* @return The internal ChassisModel.
*/
std::shared_ptr<ChassisModel> getModel() override;
/**
* @return The internal ChassisModel.
*/
ChassisModel &model() override;
/**
* Sets a new maximum velocity in RPM [0-600].
*
* @param imaxVelocity The new maximum velocity.
*/
void setMaxVelocity(double imaxVelocity) override;
/**
* @return The maximum velocity in RPM [0-600].
*/
double getMaxVelocity() const override;
protected:
std::shared_ptr<Logger> logger;
bool normalTurns{true};
std::shared_ptr<ChassisModel> chassisModel;
TimeUtil timeUtil;
std::unique_ptr<AsyncPosIntegratedController> leftController;
std::unique_ptr<AsyncPosIntegratedController> rightController;
int lastTarget;
ChassisScales scales;
AbstractMotor::GearsetRatioPair gearsetRatioPair;
};
} // namespace okapi

View File

@ -1,275 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/controller/chassisController.hpp"
#include "okapi/api/control/iterative/iterativePosPidController.hpp"
#include "okapi/api/util/abstractRate.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <atomic>
#include <memory>
#include <tuple>
namespace okapi {
class ChassisControllerPID : public ChassisController {
public:
/**
* ChassisController using PID control. Puts the motors into encoder count units. Throws a
* `std::invalid_argument` exception if the gear ratio is zero.
*
* @param itimeUtil The TimeUtil.
* @param imodel The ChassisModel used to read from sensors/write to motors.
* @param idistanceController The PID controller that controls chassis distance for driving
* straight.
* @param iturnController The PID controller that controls chassis angle for turning.
* @param iangleController The PID controller that controls chassis angle for driving straight.
* @param igearset The internal gearset and external ratio used on the drive motors.
* @param iscales The ChassisScales.
* @param ilogger The logger this instance will log to.
*/
ChassisControllerPID(
TimeUtil itimeUtil,
std::shared_ptr<ChassisModel> imodel,
std::unique_ptr<IterativePosPIDController> idistanceController,
std::unique_ptr<IterativePosPIDController> iturnController,
std::unique_ptr<IterativePosPIDController> iangleController,
const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green,
const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR),
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
ChassisControllerPID(const ChassisControllerPID &) = delete;
ChassisControllerPID(ChassisControllerPID &&other) = delete;
ChassisControllerPID &operator=(const ChassisControllerPID &other) = delete;
ChassisControllerPID &operator=(ChassisControllerPID &&other) = delete;
~ChassisControllerPID() override;
/**
* Drives the robot straight for a distance (using closed-loop control).
*
* ```cpp
* // Drive forward 6 inches
* chassis->moveDistance(6_in);
*
* // Drive backward 0.2 meters
* chassis->moveDistance(-0.2_m);
* ```
*
* @param itarget distance to travel
*/
void moveDistance(QLength itarget) override;
/**
* Drives the robot straight for a distance (using closed-loop control).
*
* ```cpp
* // Drive forward by spinning the motors 400 degrees
* chassis->moveRaw(400);
* ```
*
* @param itarget distance to travel in motor degrees
*/
void moveRaw(double itarget) override;
/**
* Sets the target distance for the robot to drive straight (using closed-loop control).
*
* @param itarget distance to travel
*/
void moveDistanceAsync(QLength itarget) override;
/**
* Sets the target distance for the robot to drive straight (using closed-loop control).
*
* @param itarget distance to travel in motor degrees
*/
void moveRawAsync(double itarget) override;
/**
* Turns the robot clockwise in place (using closed-loop control).
*
* ```cpp
* // Turn 90 degrees clockwise
* chassis->turnAngle(90_deg);
* ```
*
* @param idegTarget angle to turn for
*/
void turnAngle(QAngle idegTarget) override;
/**
* Turns the robot clockwise in place (using closed-loop control).
*
* ```cpp
* // Turn clockwise by spinning the motors 200 degrees
* chassis->turnRaw(200);
* ```
*
* @param idegTarget angle to turn for in motor degrees
*/
void turnRaw(double idegTarget) override;
/**
* Sets the target angle for the robot to turn clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for
*/
void turnAngleAsync(QAngle idegTarget) override;
/**
* Sets the target angle for the robot to turn clockwise in place (using closed-loop control).
*
* @param idegTarget angle to turn for in motor degrees
*/
void turnRawAsync(double idegTarget) override;
/**
* Sets whether turns should be mirrored.
*
* @param ishouldMirror whether turns should be mirrored
*/
void setTurnsMirrored(bool ishouldMirror) override;
/**
* Checks whether the internal controllers are currently settled.
*
* @return Whether this ChassisController is settled.
*/
bool isSettled() override;
/**
* Delays until the currently executing movement completes.
*/
void waitUntilSettled() override;
/**
* Gets the ChassisScales.
*/
ChassisScales getChassisScales() const override;
/**
* Gets the GearsetRatioPair.
*/
AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override;
/**
* Sets the velocity mode flag. When the controller is in velocity mode, the control loop will
* set motor velocities. When the controller is in voltage mode (`ivelocityMode = false`), the
* control loop will set motor voltages. Additionally, when the controller is in voltage mode,
* it will not obey maximum velocity limits.
*
* @param ivelocityMode Whether the controller should be in velocity or voltage mode.
*/
void setVelocityMode(bool ivelocityMode);
/**
* Sets the gains for all controllers.
*
* @param idistanceGains The distance controller gains.
* @param iturnGains The turn controller gains.
* @param iangleGains The angle controller gains.
*/
void setGains(const IterativePosPIDController::Gains &idistanceGains,
const IterativePosPIDController::Gains &iturnGains,
const IterativePosPIDController::Gains &iangleGains);
/**
* Gets the current controller gains.
*
* @return The current controller gains in the order: distance, turn, angle.
*/
std::tuple<IterativePosPIDController::Gains,
IterativePosPIDController::Gains,
IterativePosPIDController::Gains>
getGains() const;
/**
* Starts the internal thread. This method is called by the ChassisControllerBuilder when making a
* new instance of this class.
*/
void startThread();
/**
* Returns the underlying thread handle.
*
* @return The underlying thread handle.
*/
CrossplatformThread *getThread() const;
/**
* Interrupts the current movement to stop the robot.
*/
void stop() override;
/**
* Sets a new maximum velocity in RPM [0-600]. In voltage mode, the max velocity is ignored and a
* max voltage should be set on the underlying ChassisModel instead.
*
* @param imaxVelocity The new maximum velocity.
*/
void setMaxVelocity(double imaxVelocity) override;
/**
* @return The maximum velocity in RPM [0-600].
*/
double getMaxVelocity() const override;
/**
* @return The internal ChassisModel.
*/
std::shared_ptr<ChassisModel> getModel() override;
/**
* @return The internal ChassisModel.
*/
ChassisModel &model() override;
protected:
std::shared_ptr<Logger> logger;
bool normalTurns{true};
std::shared_ptr<ChassisModel> chassisModel;
TimeUtil timeUtil;
std::unique_ptr<IterativePosPIDController> distancePid;
std::unique_ptr<IterativePosPIDController> turnPid;
std::unique_ptr<IterativePosPIDController> anglePid;
ChassisScales scales;
AbstractMotor::GearsetRatioPair gearsetRatioPair;
bool velocityMode{true};
std::atomic_bool doneLooping{true};
std::atomic_bool doneLoopingSeen{true};
std::atomic_bool newMovement{false};
std::atomic_bool dtorCalled{false};
QTime threadSleepTime{10_ms};
static void trampoline(void *context);
void loop();
/**
* Wait for the distance setup (distancePid and anglePid) to settle.
*
* @return true if done settling; false if settling should be tried again
*/
bool waitForDistanceSettled();
/**
* Wait for the angle setup (anglePid) to settle.
*
* @return true if done settling; false if settling should be tried again
*/
bool waitForAngleSettled();
/**
* Stops all the controllers and the ChassisModel.
*/
void stopAfterSettled();
typedef enum { distance, angle, none } modeType;
modeType mode{none};
CrossplatformThread *task{nullptr};
};
} // namespace okapi

View File

@ -1,88 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/units/QAngle.hpp"
#include "okapi/api/units/QLength.hpp"
#include "okapi/api/units/RQuantity.hpp"
#include "okapi/api/util/logging.hpp"
#include <initializer_list>
#include <stdexcept>
#include <vector>
namespace okapi {
class ChassisScales {
public:
/**
* The scales a ChassisController needs to do all of its closed-loop control. The first element is
* the wheel diameter, the second element is the wheel track. For three-encoder configurations,
* the length from the center of rotation to the middle wheel and the middle wheel diameter are
* passed as the third and fourth elements.
*
* The wheel track is the center-to-center distance between the wheels (center-to-center
* meaning the width between the centers of both wheels). For example, if you are using four inch
* omni wheels and there are 11.5 inches between the centers of each wheel, you would call the
* constructor like so:
* `ChassisScales scales({4_in, 11.5_in}, imev5GreenTPR); // imev5GreenTPR for a green gearset`
*
* Wheel diameter
*
* +-+ Center of rotation
* | | |
* v v +----------+ Length to middle wheel
* | | from center of rotation
* +---> === | === |
* | + v + |
* | ++---------------++ |
* | | | v
* Wheel track | | |
* | | x |+| <-- Middle wheel
* | | |
* | | |
* | ++---------------++
* | + +
* +---> === ===
*
*
* @param idimensions {wheel diameter, wheel track} or {wheel diameter, wheel track, length to
* middle wheel, middle wheel diameter}.
* @param itpr The ticks per revolution of the encoders.
* @param ilogger The logger this instance will log to.
*/
ChassisScales(const std::initializer_list<QLength> &idimensions,
double itpr,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
/**
* The scales a ChassisController needs to do all of its closed-loop control. The first element is
* the straight scale, the second element is the turn scale. Optionally, the length from the
* center of rotation to the middle wheel and the middle scale can be passed as the third and
* fourth elements. The straight scale converts motor degrees to meters, the turn scale converts
* motor degrees to robot turn degrees, and the middle scale converts middle wheel degrees to
* meters.
*
* @param iscales {straight scale, turn scale} or {straight scale, turn scale, length to middle
* wheel in meters, middle scale}.
* @param itpr The ticks per revolution of the encoders.
* @param ilogger The logger this instance will log to.
*/
ChassisScales(const std::initializer_list<double> &iscales,
double itpr,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
QLength wheelDiameter;
QLength wheelTrack;
QLength middleWheelDistance;
QLength middleWheelDiameter;
double straight;
double turn;
double middle;
double tpr;
protected:
static void validateInputSize(std::size_t inputSize, const std::shared_ptr<Logger> &logger);
};
} // namespace okapi

View File

@ -1,183 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp"
#include "okapi/api/chassis/controller/odomChassisController.hpp"
#include "okapi/api/chassis/model/skidSteerModel.hpp"
#include "okapi/api/odometry/odometry.hpp"
#include <memory>
namespace okapi {
class DefaultOdomChassisController : public OdomChassisController {
public:
/**
* Odometry based chassis controller that moves using a separately constructed chassis controller.
* Spins up a task at the default priority plus 1 for odometry when constructed.
*
* Moves the robot around in the odom frame. Instead of telling the robot to drive forward or
* turn some amount, you instead tell it to drive to a specific point on the field or turn to
* a specific angle, relative to its starting position.
*
* @param itimeUtil The TimeUtil.
* @param iodometry The odometry to read state estimates from.
* @param icontroller The chassis controller to delegate to.
* @param imode The new default StateMode used to interpret target points and query the Odometry
* state.
* @param imoveThreshold minimum length movement (smaller movements will be skipped)
* @param iturnThreshold minimum angle turn (smaller turns will be skipped)
* @param ilogger The logger this instance will log to.
*/
DefaultOdomChassisController(const TimeUtil &itimeUtil,
std::shared_ptr<Odometry> iodometry,
std::shared_ptr<ChassisController> icontroller,
const StateMode &imode = StateMode::FRAME_TRANSFORMATION,
QLength imoveThreshold = 0_mm,
QAngle iturnThreshold = 0_deg,
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
DefaultOdomChassisController(const DefaultOdomChassisController &) = delete;
DefaultOdomChassisController(DefaultOdomChassisController &&other) = delete;
DefaultOdomChassisController &operator=(const DefaultOdomChassisController &other) = delete;
DefaultOdomChassisController &operator=(DefaultOdomChassisController &&other) = delete;
/**
* Drives the robot straight to a point in the odom frame.
*
* @param ipoint The target point to navigate to.
* @param ibackwards Whether to drive to the target point backwards.
* @param ioffset An offset from the target point in the direction pointing towards the robot. The
* robot will stop this far away from the target point.
*/
void driveToPoint(const Point &ipoint,
bool ibackwards = false,
const QLength &ioffset = 0_mm) override;
/**
* Turns the robot to face a point in the odom frame.
*
* @param ipoint The target point to turn to face.
*/
void turnToPoint(const Point &ipoint) override;
/**
* @return The internal ChassisController.
*/
std::shared_ptr<ChassisController> getChassisController();
/**
* @return The internal ChassisController.
*/
ChassisController &chassisController();
/**
* This delegates to the input ChassisController.
*/
void turnToAngle(const QAngle &iangle) override;
/**
* This delegates to the input ChassisController.
*/
void moveDistance(QLength itarget) override;
/**
* This delegates to the input ChassisController.
*/
void moveRaw(double itarget) override;
/**
* This delegates to the input ChassisController.
*/
void moveDistanceAsync(QLength itarget) override;
/**
* This delegates to the input ChassisController.
*/
void moveRawAsync(double itarget) override;
/**
* Turns chassis to desired angle (turns in the direction of smallest angle)
* (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees)
*
* @param idegTarget target angle
*/
void turnAngle(QAngle idegTarget) override;
/**
* This delegates to the input ChassisController.
*/
void turnRaw(double idegTarget) override;
/**
* Turns chassis to desired angle (turns in the direction of smallest angle)
* (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees)
*
* @param idegTarget target angle
*/
void turnAngleAsync(QAngle idegTarget) override;
/**
* This delegates to the input ChassisController.
*/
void turnRawAsync(double idegTarget) override;
/**
* This delegates to the input ChassisController.
*/
void setTurnsMirrored(bool ishouldMirror) override;
/**
* This delegates to the input ChassisController.
*/
bool isSettled() override;
/**
* This delegates to the input ChassisController.
*/
void waitUntilSettled() override;
/**
* This delegates to the input ChassisController.
*/
void stop() override;
/**
* This delegates to the input ChassisController.
*/
void setMaxVelocity(double imaxVelocity) override;
/**
* This delegates to the input ChassisController.
*/
double getMaxVelocity() const override;
/**
* This delegates to the input ChassisController.
*/
ChassisScales getChassisScales() const override;
/**
* This delegates to the input ChassisController.
*/
AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override;
/**
* This delegates to the input ChassisController.
*/
std::shared_ptr<ChassisModel> getModel() override;
/**
* This delegates to the input ChassisController.
*/
ChassisModel &model() override;
protected:
std::shared_ptr<Logger> logger;
std::shared_ptr<ChassisController> controller;
void waitForOdomTask();
};
} // namespace okapi

View File

@ -1,154 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/controller/chassisController.hpp"
#include "okapi/api/chassis/model/skidSteerModel.hpp"
#include "okapi/api/coreProsAPI.hpp"
#include "okapi/api/odometry/odometry.hpp"
#include "okapi/api/odometry/point.hpp"
#include "okapi/api/units/QSpeed.hpp"
#include "okapi/api/util/abstractRate.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <atomic>
#include <memory>
#include <valarray>
namespace okapi {
class OdomChassisController : public ChassisController {
public:
/**
* Odometry based chassis controller. Starts task at the default for odometry when constructed,
* which calls `Odometry::step` every `10ms`. The default StateMode is
* `StateMode::FRAME_TRANSFORMATION`.
*
* Moves the robot around in the odom frame. Instead of telling the robot to drive forward or
* turn some amount, you instead tell it to drive to a specific point on the field or turn to
* a specific angle relative to its starting position.
*
* @param itimeUtil The TimeUtil.
* @param iodometry The Odometry instance to run in a new task.
* @param imode The new default StateMode used to interpret target points and query the Odometry
* state.
* @param imoveThreshold minimum length movement (smaller movements will be skipped)
* @param iturnThreshold minimum angle turn (smaller turns will be skipped)
*/
OdomChassisController(TimeUtil itimeUtil,
std::shared_ptr<Odometry> iodometry,
const StateMode &imode = StateMode::FRAME_TRANSFORMATION,
const QLength &imoveThreshold = 0_mm,
const QAngle &iturnThreshold = 0_deg,
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
~OdomChassisController() override;
OdomChassisController(const OdomChassisController &) = delete;
OdomChassisController(OdomChassisController &&other) = delete;
OdomChassisController &operator=(const OdomChassisController &other) = delete;
OdomChassisController &operator=(OdomChassisController &&other) = delete;
/**
* Drives the robot straight to a point in the odom frame.
*
* @param ipoint The target point to navigate to.
* @param ibackwards Whether to drive to the target point backwards.
* @param ioffset An offset from the target point in the direction pointing towards the robot. The
* robot will stop this far away from the target point.
*/
virtual void
driveToPoint(const Point &ipoint, bool ibackwards = false, const QLength &ioffset = 0_mm) = 0;
/**
* Turns the robot to face a point in the odom frame.
*
* @param ipoint The target point to turn to face.
*/
virtual void turnToPoint(const Point &ipoint) = 0;
/**
* Turns the robot to face an angle in the odom frame.
*
* @param iangle The angle to turn to.
*/
virtual void turnToAngle(const QAngle &iangle) = 0;
/**
* @return The current state.
*/
virtual OdomState getState() const;
/**
* Set a new state to be the current state. The default StateMode is
* `StateMode::FRAME_TRANSFORMATION`.
*
* @param istate The new state in the given format.
* @param imode The mode to treat the input state as.
*/
virtual void setState(const OdomState &istate);
/**
* Sets a default StateMode that will be used to interpret target points and query the Odometry
* state.
*
* @param imode The new default StateMode.
*/
void setDefaultStateMode(const StateMode &imode);
/**
* Set a new move threshold. Any requested movements smaller than this threshold will be skipped.
*
* @param imoveThreshold new move threshold
*/
virtual void setMoveThreshold(const QLength &imoveThreshold);
/**
* Set a new turn threshold. Any requested turns smaller than this threshold will be skipped.
*
* @param iturnTreshold new turn threshold
*/
virtual void setTurnThreshold(const QAngle &iturnTreshold);
/**
* @return The current move threshold.
*/
virtual QLength getMoveThreshold() const;
/**
* @return The current turn threshold.
*/
virtual QAngle getTurnThreshold() const;
/**
* Starts the internal odometry thread. This should not be called by normal users.
*/
void startOdomThread();
/**
* @return The underlying thread handle.
*/
CrossplatformThread *getOdomThread() const;
/**
* @return The internal odometry.
*/
std::shared_ptr<Odometry> getOdometry();
protected:
std::shared_ptr<Logger> logger;
TimeUtil timeUtil;
QLength moveThreshold;
QAngle turnThreshold;
std::shared_ptr<Odometry> odom;
CrossplatformThread *odomTask{nullptr};
std::atomic_bool dtorCalled{false};
StateMode defaultStateMode{StateMode::FRAME_TRANSFORMATION};
std::atomic_bool odomTaskRunning{false};
static void trampoline(void *context);
void loop();
};
} // namespace okapi

View File

@ -1,165 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/model/readOnlyChassisModel.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include <array>
#include <initializer_list>
#include <memory>
#include <vector>
namespace okapi {
/**
* A version of the ReadOnlyChassisModel that also supports write methods, such as setting motor
* speed. Because this class can write to motors, there can only be one owner and as such copying
* is disabled.
*/
class ChassisModel : public ReadOnlyChassisModel {
public:
explicit ChassisModel() = default;
ChassisModel(const ChassisModel &) = delete;
ChassisModel &operator=(const ChassisModel &) = delete;
/**
* Drive the robot forwards (using open-loop control). Uses velocity mode.
*
* @param ipower motor power
*/
virtual void forward(double ispeed) = 0;
/**
* Drive the robot in an arc (using open-loop control). Uses velocity mode.
* The algorithm is (approximately):
* leftPower = forwardSpeed + yaw
* rightPower = forwardSpeed - yaw
*
* @param iforwadSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
*/
virtual void driveVector(double iforwardSpeed, double iyaw) = 0;
/**
* Drive the robot in an arc. Uses voltage mode.
* The algorithm is (approximately):
* leftPower = forwardSpeed + yaw
* rightPower = forwardSpeed - yaw
*
* @param iforwadSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
*/
virtual void driveVectorVoltage(double iforwardSpeed, double iyaw) = 0;
/**
* Turn the robot clockwise (using open-loop control). Uses velocity mode.
*
* @param ispeed motor power
*/
virtual void rotate(double ispeed) = 0;
/**
* Stop the robot (set all the motors to 0). Uses velocity mode.
*/
virtual void stop() = 0;
/**
* Drive the robot with a tank drive layout. Uses voltage mode.
*
* @param ileftSpeed left side speed
* @param irightSpeed right side speed
* @param ithreshold deadband on joystick values
*/
virtual void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) = 0;
/**
* Drive the robot with an arcade drive layout. Uses voltage mode.
*
* @param iforwardSpeed speed forward direction
* @param iyaw speed around the vertical axis
* @param ithreshold deadband on joystick values
*/
virtual void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) = 0;
/**
* Drive the robot with a curvature drive layout. The robot drives in constant radius turns
* where you control the curvature (inverse of radius) you drive in. This is advantageous
* because the forward speed will not affect the rate of turning. The algorithm switches to
* arcade if the forward speed is 0. Uses voltage mode.
*
* @param iforwardSpeed speed in the forward direction
* @param icurvature curvature (inverse of radius) to drive in
* @param ithreshold deadband on joystick values
*/
virtual void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) = 0;
/**
* Power the left side motors. Uses velocity mode.
*
* @param ipower motor power
*/
virtual void left(double ispeed) = 0;
/**
* Power the right side motors. Uses velocity mode.
*
* @param ipower motor power
*/
virtual void right(double ispeed) = 0;
/**
* Reset the sensors to their zero point.
*/
virtual void resetSensors() = 0;
/**
* Set the brake mode for each motor.
*
* @param mode new brake mode
*/
virtual void setBrakeMode(AbstractMotor::brakeMode mode) = 0;
/**
* Set the encoder units for each motor.
*
* @param units new motor encoder units
*/
virtual void setEncoderUnits(AbstractMotor::encoderUnits units) = 0;
/**
* Set the gearset for each motor.
*
* @param gearset new motor gearset
*/
virtual void setGearing(AbstractMotor::gearset gearset) = 0;
/**
* Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the
* currently installed gearset. If the configured maximum velocity is greater than the attainable
* maximum velocity from the currently installed gearset, the ChassisModel will still scale to
* that velocity.
*
* @param imaxVelocity The new maximum velocity.
*/
virtual void setMaxVelocity(double imaxVelocity) = 0;
/**
* @return The current maximum velocity.
*/
virtual double getMaxVelocity() const = 0;
/**
* Sets a new maximum voltage in mV in the range `[0-12000]`.
*
* @param imaxVoltage The new maximum voltage.
*/
virtual void setMaxVoltage(double imaxVoltage) = 0;
/**
* @return The maximum voltage in mV `[0-12000]`.
*/
virtual double getMaxVoltage() const = 0;
};
} // namespace okapi

View File

@ -1,247 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/model/chassisModel.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp"
namespace okapi {
class HDriveModel : public ChassisModel {
public:
/**
* Model for an h-drive (wheels parallel with robot's direction of motion, with an additional
* wheel perpendicular to those). When the left and right side motors are powered +100%, the robot
* should move forward in a straight line. When the middle motor is powered +100%, the robot
* should strafe right in a straight line.
*
* @param ileftSideMotor The left side motor.
* @param irightSideMotor The right side motor.
* @param imiddleMotor The middle (perpendicular) motor.
* @param ileftEnc The left side encoder.
* @param irightEnc The right side encoder.
* @param imiddleEnc The middle encoder.
*/
HDriveModel(std::shared_ptr<AbstractMotor> ileftSideMotor,
std::shared_ptr<AbstractMotor> irightSideMotor,
std::shared_ptr<AbstractMotor> imiddleMotor,
std::shared_ptr<ContinuousRotarySensor> ileftEnc,
std::shared_ptr<ContinuousRotarySensor> irightEnc,
std::shared_ptr<ContinuousRotarySensor> imiddleEnc,
double imaxVelocity,
double imaxVoltage);
/**
* Drive the robot forwards (using open-loop control). Uses velocity mode. Sets the middle motor
* to zero velocity.
*
* @param ispeed motor power
*/
void forward(double ispeed) override;
/**
* Drive the robot in an arc (using open-loop control). Uses velocity mode. Sets the middle motor
* to zero velocity.
*
* The algorithm is (approximately):
* leftPower = ySpeed + zRotation
* rightPower = ySpeed - zRotation
*
* @param iySpeed speed on y axis (forward)
* @param izRotation speed around z axis (up)
*/
void driveVector(double iySpeed, double izRotation) override;
/**
* Drive the robot in an arc. Uses voltage mode. Sets the middle motor to zero velocity.
*
* The algorithm is (approximately):
* leftPower = forwardSpeed + yaw
* rightPower = forwardSpeed - yaw
*
* @param iforwadSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
*/
void driveVectorVoltage(double iforwardSpeed, double iyaw) override;
/**
* Turn the robot clockwise (using open-loop control). Uses velocity mode. Sets the middle motor
* to zero velocity.
*
* @param ispeed motor power
*/
void rotate(double ispeed) override;
/**
* Stop the robot (set all the motors to 0). Uses velocity mode.
*/
void stop() override;
/**
* Drive the robot with a tank drive layout. Uses voltage mode. Sets the middle motor to zero
* velocity.
*
* @param ileftSpeed left side speed
* @param irightSpeed right side speed
* @param ithreshold deadband on joystick values
*/
void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override;
/**
* Drive the robot with an arcade drive layout. Uses voltage mode. Sets the middle motor to zero
* velocity.
*
* @param iforwardSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
* @param ithreshold deadband on joystick values
*/
void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override;
/**
* Drive the robot with a curvature drive layout. The robot drives in constant radius turns
* where you control the curvature (inverse of radius) you drive in. This is advantageous
* because the forward speed will not affect the rate of turning. The algorithm switches to
* arcade if the forward speed is 0. Uses voltage mode. Sets the middle motor to zero velocity.
*
* @param iforwardSpeed speed in the forward direction
* @param icurvature curvature (inverse of radius) to drive in
* @param ithreshold deadband on joystick values
*/
void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override;
/**
* Drive the robot with an arcade drive layout. Uses voltage mode.
*
* @param irightSpeed speed to the right
* @param iforwardSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
* @param ithreshold deadband on joystick values
*/
virtual void
hArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0);
/**
* Drive the robot with an curvature drive layout. Uses voltage mode.
*
* @param irightSpeed speed to the right
* @param iforwardSpeed speed in the forward direction
* @param icurvature curvature (inverse of radius) to drive in
* @param ithreshold deadband on joystick values
*/
virtual void
hCurvature(double irightSpeed, double iforwardSpeed, double icurvature, double ithreshold = 0);
/**
* Power the left side motors. Uses velocity mode.
*
* @param ispeed The motor power.
*/
void left(double ispeed) override;
/**
* Power the right side motors. Uses velocity mode.
*
* @param ispeed The motor power.
*/
void right(double ispeed) override;
/**
* Power the middle motors. Uses velocity mode.
*
* @param ispeed The motor power.
*/
virtual void middle(double ispeed);
/**
* Read the sensors.
*
* @return sensor readings in the format {left, right, middle}
*/
std::valarray<std::int32_t> getSensorVals() const override;
/**
* Reset the sensors to their zero point.
*/
void resetSensors() override;
/**
* Set the brake mode for each motor.
*
* @param mode new brake mode
*/
void setBrakeMode(AbstractMotor::brakeMode mode) override;
/**
* Set the encoder units for each motor.
*
* @param units new motor encoder units
*/
void setEncoderUnits(AbstractMotor::encoderUnits units) override;
/**
* Set the gearset for each motor.
*
* @param gearset new motor gearset
*/
void setGearing(AbstractMotor::gearset gearset) override;
/**
* Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the
* currently installed gearset. If the configured maximum velocity is greater than the attainable
* maximum velocity from the currently installed gearset, the ChassisModel will still scale to
* that velocity.
*
* @param imaxVelocity The new maximum velocity.
*/
void setMaxVelocity(double imaxVelocity) override;
/**
* @return The current maximum velocity.
*/
double getMaxVelocity() const override;
/**
* Sets a new maximum voltage in mV in the range `[0-12000]`.
*
* @param imaxVoltage The new maximum voltage.
*/
void setMaxVoltage(double imaxVoltage) override;
/**
* @return The maximum voltage in mV in the range `[0-12000]`.
*/
double getMaxVoltage() const override;
/**
* Returns the left side motor.
*
* @return the left side motor
*/
std::shared_ptr<AbstractMotor> getLeftSideMotor() const;
/**
* Returns the left side motor.
*
* @return the left side motor
*/
std::shared_ptr<AbstractMotor> getRightSideMotor() const;
/**
* @return The middle motor.
*/
std::shared_ptr<AbstractMotor> getMiddleMotor() const;
protected:
double maxVelocity;
double maxVoltage;
std::shared_ptr<AbstractMotor> leftSideMotor;
std::shared_ptr<AbstractMotor> rightSideMotor;
std::shared_ptr<AbstractMotor> middleMotor;
std::shared_ptr<ContinuousRotarySensor> leftSensor;
std::shared_ptr<ContinuousRotarySensor> rightSensor;
std::shared_ptr<ContinuousRotarySensor> middleSensor;
};
} // namespace okapi

View File

@ -1,28 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/coreProsAPI.hpp"
#include <valarray>
namespace okapi {
/**
* A version of the ChassisModel that only supports read methods, such as querying sensor values.
* This class does not let you write to motors, so it supports having multiple owners and as a
* result copying is enabled.
*/
class ReadOnlyChassisModel {
public:
virtual ~ReadOnlyChassisModel() = default;
/**
* Read the sensors.
*
* @return sensor readings (format is implementation dependent)
*/
virtual std::valarray<std::int32_t> getSensorVals() const = 0;
};
} // namespace okapi

View File

@ -1,198 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/model/chassisModel.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp"
namespace okapi {
class SkidSteerModel : public ChassisModel {
public:
/**
* Model for a skid steer drive (wheels parallel with robot's direction of motion). When all
* motors are powered +100%, the robot should move forward in a straight line.
*
* @param ileftSideMotor The left side motor.
* @param irightSideMotor The right side motor.
* @param ileftEnc The left side encoder.
* @param irightEnc The right side encoder.
*/
SkidSteerModel(std::shared_ptr<AbstractMotor> ileftSideMotor,
std::shared_ptr<AbstractMotor> irightSideMotor,
std::shared_ptr<ContinuousRotarySensor> ileftEnc,
std::shared_ptr<ContinuousRotarySensor> irightEnc,
double imaxVelocity,
double imaxVoltage);
/**
* Drive the robot forwards (using open-loop control). Uses velocity mode.
*
* @param ispeed motor power
*/
void forward(double ispeed) override;
/**
* Drive the robot in an arc (using open-loop control). Uses velocity mode.
* The algorithm is (approximately):
* leftPower = ySpeed + zRotation
* rightPower = ySpeed - zRotation
*
* @param iySpeed speed on y axis (forward)
* @param izRotation speed around z axis (up)
*/
void driveVector(double iySpeed, double izRotation) override;
/**
* Drive the robot in an arc. Uses voltage mode.
* The algorithm is (approximately):
* leftPower = forwardSpeed + yaw
* rightPower = forwardSpeed - yaw
*
* @param iforwadSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
*/
void driveVectorVoltage(double iforwardSpeed, double iyaw) override;
/**
* Turn the robot clockwise (using open-loop control). Uses velocity mode.
*
* @param ispeed motor power
*/
void rotate(double ispeed) override;
/**
* Stop the robot (set all the motors to 0). Uses velocity mode.
*/
void stop() override;
/**
* Drive the robot with a tank drive layout. Uses voltage mode.
*
* @param ileftSpeed left side speed
* @param irightSpeed right side speed
* @param ithreshold deadband on joystick values
*/
void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override;
/**
* Drive the robot with an arcade drive layout. Uses voltage mode.
*
* @param iforwardSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
* @param ithreshold deadband on joystick values
*/
void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override;
/**
* Drive the robot with a curvature drive layout. The robot drives in constant radius turns
* where you control the curvature (inverse of radius) you drive in. This is advantageous
* because the forward speed will not affect the rate of turning. The algorithm switches to
* arcade if the forward speed is 0. Uses voltage mode.
*
* @param iforwardSpeed speed in the forward direction
* @param icurvature curvature (inverse of radius) to drive in
* @param ithreshold deadband on joystick values
*/
void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override;
/**
* Power the left side motors. Uses velocity mode.
*
* @param ispeed The motor power.
*/
void left(double ispeed) override;
/**
* Power the right side motors. Uses velocity mode.
*
* @param ispeed The motor power.
*/
void right(double ispeed) override;
/**
* Read the sensors.
*
* @return sensor readings in the format {left, right}
*/
std::valarray<std::int32_t> getSensorVals() const override;
/**
* Reset the sensors to their zero point.
*/
void resetSensors() override;
/**
* Set the brake mode for each motor.
*
* @param mode new brake mode
*/
void setBrakeMode(AbstractMotor::brakeMode mode) override;
/**
* Set the encoder units for each motor.
*
* @param units new motor encoder units
*/
void setEncoderUnits(AbstractMotor::encoderUnits units) override;
/**
* Set the gearset for each motor.
*
* @param gearset new motor gearset
*/
void setGearing(AbstractMotor::gearset gearset) override;
/**
* Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the
* currently installed gearset. If the configured maximum velocity is greater than the attainable
* maximum velocity from the currently installed gearset, the ChassisModel will still scale to
* that velocity.
*
* @param imaxVelocity The new maximum velocity.
*/
void setMaxVelocity(double imaxVelocity) override;
/**
* @return The current maximum velocity.
*/
double getMaxVelocity() const override;
/**
* Sets a new maximum voltage in mV in the range `[0-12000]`.
*
* @param imaxVoltage The new maximum voltage.
*/
void setMaxVoltage(double imaxVoltage) override;
/**
* @return The maximum voltage in mV in the range `[0-12000]`.
*/
double getMaxVoltage() const override;
/**
* Returns the left side motor.
*
* @return the left side motor
*/
std::shared_ptr<AbstractMotor> getLeftSideMotor() const;
/**
* Returns the left side motor.
*
* @return the left side motor
*/
std::shared_ptr<AbstractMotor> getRightSideMotor() const;
protected:
double maxVelocity;
double maxVoltage;
std::shared_ptr<AbstractMotor> leftSideMotor;
std::shared_ptr<AbstractMotor> rightSideMotor;
std::shared_ptr<ContinuousRotarySensor> leftSensor;
std::shared_ptr<ContinuousRotarySensor> rightSensor;
};
} // namespace okapi

View File

@ -1,46 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/model/skidSteerModel.hpp"
namespace okapi {
class ThreeEncoderSkidSteerModel : public SkidSteerModel {
public:
/**
* Model for a skid steer drive (wheels parallel with robot's direction of motion). When all
* motors are powered +127, the robot should move forward in a straight line.
*
* @param ileftSideMotor left side motor
* @param irightSideMotor right side motor
* @param ileftEnc left side encoder
* @param imiddleEnc middle encoder (mounted perpendicular to the left and right side encoders)
* @param irightEnc right side encoder
*/
ThreeEncoderSkidSteerModel(std::shared_ptr<AbstractMotor> ileftSideMotor,
std::shared_ptr<AbstractMotor> irightSideMotor,
std::shared_ptr<ContinuousRotarySensor> ileftEnc,
std::shared_ptr<ContinuousRotarySensor> irightEnc,
std::shared_ptr<ContinuousRotarySensor> imiddleEnc,
double imaxVelocity,
double imaxVoltage);
/**
* Read the sensors.
*
* @return sensor readings in the format {left, right, middle}
*/
std::valarray<std::int32_t> getSensorVals() const override;
/**
* Reset the sensors to their zero point.
*/
void resetSensors() override;
protected:
std::shared_ptr<ContinuousRotarySensor> middleSensor;
};
} // namespace okapi

View File

@ -1,50 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/model/xDriveModel.hpp"
namespace okapi {
class ThreeEncoderXDriveModel : public XDriveModel {
public:
/**
* Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered
* +100%, the robot should move forward in a straight line.
*
* @param itopLeftMotor The top left motor.
* @param itopRightMotor The top right motor.
* @param ibottomRightMotor The bottom right motor.
* @param ibottomLeftMotor The bottom left motor.
* @param ileftEnc The left side encoder.
* @param irightEnc The right side encoder.
* @param imiddleEnc The middle encoder.
*/
ThreeEncoderXDriveModel(std::shared_ptr<AbstractMotor> itopLeftMotor,
std::shared_ptr<AbstractMotor> itopRightMotor,
std::shared_ptr<AbstractMotor> ibottomRightMotor,
std::shared_ptr<AbstractMotor> ibottomLeftMotor,
std::shared_ptr<ContinuousRotarySensor> ileftEnc,
std::shared_ptr<ContinuousRotarySensor> irightEnc,
std::shared_ptr<ContinuousRotarySensor> imiddleEnc,
double imaxVelocity,
double imaxVoltage);
/**
* Read the sensors.
*
* @return sensor readings in the format {left, right, middle}
*/
std::valarray<std::int32_t> getSensorVals() const override;
/**
* Reset the sensors to their zero point.
*/
void resetSensors() override;
protected:
std::shared_ptr<ContinuousRotarySensor> middleSensor;
};
} // namespace okapi

View File

@ -1,273 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/model/chassisModel.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp"
#include "okapi/api/units/QAngle.hpp"
namespace okapi {
class XDriveModel : public ChassisModel {
public:
/**
* Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered
* +100%, the robot should move forward in a straight line.
*
* @param itopLeftMotor The top left motor.
* @param itopRightMotor The top right motor.
* @param ibottomRightMotor The bottom right motor.
* @param ibottomLeftMotor The bottom left motor.
* @param ileftEnc The left side encoder.
* @param irightEnc The right side encoder.
*/
XDriveModel(std::shared_ptr<AbstractMotor> itopLeftMotor,
std::shared_ptr<AbstractMotor> itopRightMotor,
std::shared_ptr<AbstractMotor> ibottomRightMotor,
std::shared_ptr<AbstractMotor> ibottomLeftMotor,
std::shared_ptr<ContinuousRotarySensor> ileftEnc,
std::shared_ptr<ContinuousRotarySensor> irightEnc,
double imaxVelocity,
double imaxVoltage);
/**
* Drive the robot forwards (using open-loop control). Uses velocity mode.
*
* @param ispeed motor power
*/
void forward(double ipower) override;
/**
* Drive the robot in an arc (using open-loop control). Uses velocity mode.
* The algorithm is (approximately):
* leftPower = forwardSpeed + yaw
* rightPower = forwardSpeed - yaw
*
* @param iforwardSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
*/
void driveVector(double iforwardSpeed, double iyaw) override;
/**
* Drive the robot in an arc. Uses voltage mode.
* The algorithm is (approximately):
* leftPower = forwardSpeed + yaw
* rightPower = forwardSpeed - yaw
*
* @param iforwadSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
*/
void driveVectorVoltage(double iforwardSpeed, double iyaw) override;
/**
* Turn the robot clockwise (using open-loop control). Uses velocity mode.
*
* @param ipower motor power
*/
void rotate(double ipower) override;
/**
* Drive the robot side-ways (using open-loop control) where positive ipower is
* to the right and negative ipower is to the left. Uses velocity mode.
*
* @param ispeed motor power
*/
void strafe(double ipower);
/**
* Strafe the robot in an arc (using open-loop control) where positive istrafeSpeed is
* to the right and negative istrafeSpeed is to the left. Uses velocity mode.
* The algorithm is (approximately):
* topLeftPower = -1 * istrafeSpeed + yaw
* topRightPower = istrafeSpeed - yaw
* bottomRightPower = -1 * istrafeSpeed - yaw
* bottomLeftPower = istrafeSpeed + yaw
*
* @param istrafeSpeed speed to the right
* @param iyaw speed around the vertical axis
*/
void strafeVector(double istrafeSpeed, double iyaw);
/**
* Stop the robot (set all the motors to 0). Uses velocity mode.
*/
void stop() override;
/**
* Drive the robot with a tank drive layout. Uses voltage mode.
*
* @param ileftSpeed left side speed
* @param irightSpeed right side speed
* @param ithreshold deadband on joystick values
*/
void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override;
/**
* Drive the robot with an arcade drive layout. Uses voltage mode.
*
* @param iforwardSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
* @param ithreshold deadband on joystick values
*/
void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override;
/**
* Drive the robot with a curvature drive layout. The robot drives in constant radius turns
* where you control the curvature (inverse of radius) you drive in. This is advantageous
* because the forward speed will not affect the rate of turning. The algorithm switches to
* arcade if the forward speed is 0. Uses voltage mode.
*
* @param iforwardSpeed speed forward direction
* @param icurvature curvature (inverse of radius) to drive in
* @param ithreshold deadband on joystick values
*/
void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override;
/**
* Drive the robot with an arcade drive layout. Uses voltage mode.
*
* @param irightSpeed speed to the right
* @param iforwardSpeed speed in the forward direction
* @param iyaw speed around the vertical axis
* @param ithreshold deadband on joystick values
*/
virtual void
xArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0);
/**
* Drive the robot with a field-oriented arcade drive layout. Uses voltage mode.
* For example:
* Both `fieldOrientedXArcade(1, 0, 0, 0_deg)` and `fieldOrientedXArcade(1, 0, 0, 90_deg)`
* will drive the chassis in the forward/north direction. In other words, no matter
* the robot's heading, the robot will move forward/north when you tell it
* to move forward/north and will move right/east when you tell it to move right/east.
*
*
* @param ixSpeed forward speed -- (`+1`) forward, (`-1`) backward
* @param iySpeed sideways speed -- (`+1`) right, (`-1`) left
* @param iyaw turn speed -- (`+1`) clockwise, (`-1`) counter-clockwise
* @param iangle current chassis angle (`0_deg` = no correction, winds clockwise)
* @param ithreshold deadband on joystick values
*/
virtual void fieldOrientedXArcade(double ixSpeed,
double iySpeed,
double iyaw,
QAngle iangle,
double ithreshold = 0);
/**
* Power the left side motors. Uses velocity mode.
*
* @param ispeed The motor power.
*/
void left(double ispeed) override;
/**
* Power the right side motors. Uses velocity mode.
*
* @param ispeed The motor power.
*/
void right(double ispeed) override;
/**
* Read the sensors.
*
* @return sensor readings in the format {left, right}
*/
std::valarray<std::int32_t> getSensorVals() const override;
/**
* Reset the sensors to their zero point.
*/
void resetSensors() override;
/**
* Set the brake mode for each motor.
*
* @param mode new brake mode
*/
void setBrakeMode(AbstractMotor::brakeMode mode) override;
/**
* Set the encoder units for each motor.
*
* @param units new motor encoder units
*/
void setEncoderUnits(AbstractMotor::encoderUnits units) override;
/**
* Set the gearset for each motor.
*
* @param gearset new motor gearset
*/
void setGearing(AbstractMotor::gearset gearset) override;
/**
* Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the
* currently installed gearset. If the configured maximum velocity is greater than the attainable
* maximum velocity from the currently installed gearset, the ChassisModel will still scale to
* that velocity.
*
* @param imaxVelocity The new maximum velocity.
*/
void setMaxVelocity(double imaxVelocity) override;
/**
* @return The current maximum velocity.
*/
double getMaxVelocity() const override;
/**
* Sets a new maximum voltage in mV in the range `[0-12000]`.
*
* @param imaxVoltage The new maximum voltage.
*/
void setMaxVoltage(double imaxVoltage) override;
/**
* @return The maximum voltage in mV in the range `[0-12000]`.
*/
double getMaxVoltage() const override;
/**
* Returns the top left motor.
*
* @return the top left motor
*/
std::shared_ptr<AbstractMotor> getTopLeftMotor() const;
/**
* Returns the top right motor.
*
* @return the top right motor
*/
std::shared_ptr<AbstractMotor> getTopRightMotor() const;
/**
* Returns the bottom right motor.
*
* @return the bottom right motor
*/
std::shared_ptr<AbstractMotor> getBottomRightMotor() const;
/**
* Returns the bottom left motor.
*
* @return the bottom left motor
*/
std::shared_ptr<AbstractMotor> getBottomLeftMotor() const;
protected:
double maxVelocity;
double maxVoltage;
std::shared_ptr<AbstractMotor> topLeftMotor;
std::shared_ptr<AbstractMotor> topRightMotor;
std::shared_ptr<AbstractMotor> bottomRightMotor;
std::shared_ptr<AbstractMotor> bottomLeftMotor;
std::shared_ptr<ContinuousRotarySensor> leftSensor;
std::shared_ptr<ContinuousRotarySensor> rightSensor;
};
} // namespace okapi

View File

@ -1,24 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/closedLoopController.hpp"
namespace okapi {
/**
* Closed-loop controller that steps on its own in another thread and automatically writes to the
* output.
*/
template <typename Input, typename Output>
class AsyncController : public ClosedLoopController<Input, Output> {
public:
/**
* Blocks the current task until the controller has settled. Determining what settling means is
* implementation-dependent.
*/
virtual void waitUntilSettled() = 0;
};
} // namespace okapi

View File

@ -1,291 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncPositionController.hpp"
#include "okapi/api/control/util/pathfinderUtil.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include "okapi/api/units/QAngularSpeed.hpp"
#include "okapi/api/units/QSpeed.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <atomic>
#include <map>
#include "squiggles.hpp"
namespace okapi {
class AsyncLinearMotionProfileController : public AsyncPositionController<std::string, double> {
public:
/**
* An Async Controller which generates and follows 1D motion profiles.
*
* @param itimeUtil The TimeUtil.
* @param ilimits The default limits.
* @param ioutput The output to write velocity targets to.
* @param idiameter The effective diameter for whatever the motor spins.
* @param ipair The gearset.
* @param ilogger The logger this instance will log to.
*/
AsyncLinearMotionProfileController(
const TimeUtil &itimeUtil,
const PathfinderLimits &ilimits,
const std::shared_ptr<ControllerOutput<double>> &ioutput,
const QLength &idiameter,
const AbstractMotor::GearsetRatioPair &ipair,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
AsyncLinearMotionProfileController(AsyncLinearMotionProfileController &&other) = delete;
AsyncLinearMotionProfileController &
operator=(AsyncLinearMotionProfileController &&other) = delete;
~AsyncLinearMotionProfileController() override;
/**
* Generates a path which intersects the given waypoints and saves it internally with a key of
* pathId. Call `executePath()` with the same `pathId` to run it.
*
* If the waypoints form a path which is impossible to achieve, an instance of
* `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there
* are no waypoints, no path is generated.
*
* @param iwaypoints The waypoints to hit on the path.
* @param ipathId A unique identifier to save the path with.
*/
void generatePath(std::initializer_list<QLength> iwaypoints, const std::string &ipathId);
/**
* Generates a path which intersects the given waypoints and saves it internally with a key of
* pathId. Call `executePath()` with the same pathId to run it.
*
* If the waypoints form a path which is impossible to achieve, an instance of
* `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there
* are no waypoints, no path is generated.
*
* @param iwaypoints The waypoints to hit on the path.
* @param ipathId A unique identifier to save the path with.
* @param ilimits The limits to use for this path only.
*/
void generatePath(std::initializer_list<QLength> iwaypoints,
const std::string &ipathId,
const PathfinderLimits &ilimits);
/**
* Removes a path and frees the memory it used. This function returns `true` if the path was
* either deleted or didn't exist in the first place. It returns `false` if the path could not be
* removed because it is running.
*
* @param ipathId A unique identifier for the path, previously passed to generatePath()
* @return `true` if the path no longer exists
*/
bool removePath(const std::string &ipathId);
/**
* Gets the identifiers of all paths saved in this `AsyncMotionProfileController`.
*
* @return The identifiers of all paths
*/
std::vector<std::string> getPaths();
/**
* Executes a path with the given ID. If there is no path matching the ID, the method will
* return. Any targets set while a path is being followed will be ignored.
*
* @param ipathId A unique identifier for the path, previously passed to `generatePath()`.
*/
void setTarget(std::string ipathId) override;
/**
* Executes a path with the given ID. If there is no path matching the ID, the method will
* return. Any targets set while a path is being followed will be ignored.
*
* @param ipathId A unique identifier for the path, previously passed to `generatePath()`.
* @param ibackwards Whether to follow the profile backwards.
*/
void setTarget(std::string ipathId, bool ibackwards);
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller.
*
* This just calls `setTarget()`.
*/
void controllerSet(std::string ivalue) override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
std::string getTarget() override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
virtual std::string getTarget() const;
/**
* This is overridden to return the current path.
*
* @return The most recent value of the process variable.
*/
std::string getProcessValue() const override;
/**
* Blocks the current task until the controller has settled. This controller is settled when
* it has finished following a path. If no path is being followed, it is settled.
*/
void waitUntilSettled() override;
/**
* Generates a new path from the position (typically the current position) to the target and
* blocks until the controller has settled. Does not save the path which was generated.
*
* @param iposition The starting position.
* @param itarget The target position.
* @param ibackwards Whether to follow the profile backwards.
*/
void moveTo(const QLength &iposition, const QLength &itarget, bool ibackwards = false);
/**
* Generates a new path from the position (typically the current position) to the target and
* blocks until the controller has settled. Does not save the path which was generated.
*
* @param iposition The starting position.
* @param itarget The target position.
* @param ilimits The limits to use for this path only.
* @param ibackwards Whether to follow the profile backwards.
*/
void moveTo(const QLength &iposition,
const QLength &itarget,
const PathfinderLimits &ilimits,
bool ibackwards = false);
/**
* Returns the last error of the controller. Does not update when disabled. Returns zero if there
* is no path currently being followed.
*
* @return the last error
*/
double getError() const override;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return `true`.
*
* @return whether the controller is settled
*/
bool isSettled() override;
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information. This implementation also stops movement.
*/
void reset() override;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* NOT cause the controller to move to its last set target.
*/
void flipDisable() override;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* NOT cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(bool iisDisabled) override;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override;
/**
* This implementation does nothing because the API always requires the starting position to be
* specified.
*/
void tarePosition() override;
/**
* This implementation does nothing because the maximum velocity is configured using
* PathfinderLimits elsewhere.
*
* @param imaxVelocity Ignored.
*/
void setMaxVelocity(std::int32_t imaxVelocity) override;
/**
* Starts the internal thread. This should not be called by normal users. This method is called
* by the AsyncControllerFactory when making a new instance of this class.
*/
void startThread();
/**
* Returns the underlying thread handle.
*
* @return The underlying thread handle.
*/
CrossplatformThread *getThread() const;
/**
* Attempts to remove a path without stopping execution, then if that fails, disables the
* controller and removes the path.
*
* @param ipathId The path ID that will be removed
*/
void forceRemovePath(const std::string &ipathId);
protected:
std::shared_ptr<Logger> logger;
std::map<std::string, std::vector<squiggles::ProfilePoint>> paths{};
PathfinderLimits limits;
std::shared_ptr<ControllerOutput<double>> output;
QLength diameter;
AbstractMotor::GearsetRatioPair pair;
double currentProfilePosition{0};
TimeUtil timeUtil;
// This must be locked when accessing the current path
CrossplatformMutex currentPathMutex;
std::string currentPath{""};
std::atomic_bool isRunning{false};
std::atomic_int direction{1};
std::atomic_bool disabled{false};
std::atomic_bool dtorCalled{false};
CrossplatformThread *task{nullptr};
static void trampoline(void *context);
void loop();
/**
* Follow the supplied path. Must follow the disabled lifecycle.
*/
virtual void executeSinglePath(const std::vector<squiggles::ProfilePoint> &path,
std::unique_ptr<AbstractRate> rate);
/**
* Converts linear "chassis" speed to rotational motor speed.
*
* @param linear "chassis" frame speed
* @return motor frame speed
*/
QAngularSpeed convertLinearToRotational(QSpeed linear) const;
std::string getPathErrorMessage(const std::vector<PathfinderPoint> &points,
const std::string &ipathId,
int length);
};
} // namespace okapi

View File

@ -1,326 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/chassis/controller/chassisScales.hpp"
#include "okapi/api/chassis/model/skidSteerModel.hpp"
#include "okapi/api/control/async/asyncPositionController.hpp"
#include "okapi/api/control/util/pathfinderUtil.hpp"
#include "okapi/api/units/QAngularSpeed.hpp"
#include "okapi/api/units/QSpeed.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <atomic>
#include <iostream>
#include <map>
#include "squiggles.hpp"
namespace okapi {
class AsyncMotionProfileController : public AsyncPositionController<std::string, PathfinderPoint> {
public:
/**
* An Async Controller which generates and follows 2D motion profiles. Throws a
* `std::invalid_argument` exception if the gear ratio is zero.
*
* @param itimeUtil The TimeUtil.
* @param ilimits The default limits.
* @param imodel The chassis model to control.
* @param iscales The chassis dimensions.
* @param ipair The gearset.
* @param ilogger The logger this instance will log to.
*/
AsyncMotionProfileController(const TimeUtil &itimeUtil,
const PathfinderLimits &ilimits,
const std::shared_ptr<ChassisModel> &imodel,
const ChassisScales &iscales,
const AbstractMotor::GearsetRatioPair &ipair,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
AsyncMotionProfileController(AsyncMotionProfileController &&other) = delete;
AsyncMotionProfileController &operator=(AsyncMotionProfileController &&other) = delete;
~AsyncMotionProfileController() override;
/**
* Generates a path which intersects the given waypoints and saves it internally with a key of
* pathId. Call `executePath()` with the same pathId to run it.
*
* If the waypoints form a path which is impossible to achieve, an instance of
* `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there
* are no waypoints, no path is generated.
*
* @param iwaypoints The waypoints to hit on the path.
* @param ipathId A unique identifier to save the path with.
*/
void generatePath(std::initializer_list<PathfinderPoint> iwaypoints, const std::string &ipathId);
/**
* Generates a path which intersects the given waypoints and saves it internally with a key of
* pathId. Call `executePath()` with the same pathId to run it.
*
* If the waypoints form a path which is impossible to achieve, an instance of
* `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there
* are no waypoints, no path is generated.
*
* NOTE: The waypoints are expected to be in the
* okapi::State::FRAME_TRANSFORMATION format where +x is forward, +y is right,
* and 0 theta is measured from the +x axis to the +y axis.
*
* @param iwaypoints The waypoints to hit on the path.
* @param ipathId A unique identifier to save the path with.
* @param ilimits The limits to use for this path only.
*/
void generatePath(std::initializer_list<PathfinderPoint> iwaypoints,
const std::string &ipathId,
const PathfinderLimits &ilimits);
/**
* Removes a path and frees the memory it used. This function returns true if the path was either
* deleted or didn't exist in the first place. It returns false if the path could not be removed
* because it is running.
*
* @param ipathId A unique identifier for the path, previously passed to `generatePath()`
* @return True if the path no longer exists
*/
bool removePath(const std::string &ipathId);
/**
* Gets the identifiers of all paths saved in this `AsyncMotionProfileController`.
*
* @return The identifiers of all paths
*/
std::vector<std::string> getPaths();
/**
* Executes a path with the given ID. If there is no path matching the ID, the method will
* return. Any targets set while a path is being followed will be ignored.
*
* @param ipathId A unique identifier for the path, previously passed to `generatePath()`.
*/
void setTarget(std::string ipathId) override;
/**
* Executes a path with the given ID. If there is no path matching the ID, the method will
* return. Any targets set while a path is being followed will be ignored.
*
* @param ipathId A unique identifier for the path, previously passed to `generatePath()`.
* @param ibackwards Whether to follow the profile backwards.
* @param imirrored Whether to follow the profile mirrored.
*/
void setTarget(std::string ipathId, bool ibackwards, bool imirrored = false);
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller. This just calls `setTarget()`.
*/
void controllerSet(std::string ivalue) override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
std::string getTarget() override;
/**
* This is overridden to return the current path.
*
* @return The most recent value of the process variable.
*/
std::string getProcessValue() const override;
/**
* Blocks the current task until the controller has settled. This controller is settled when
* it has finished following a path. If no path is being followed, it is settled.
*/
void waitUntilSettled() override;
/**
* Generates a new path from the position (typically the current position) to the target and
* blocks until the controller has settled. Does not save the path which was generated.
*
* @param iwaypoints The waypoints to hit on the path.
* @param ibackwards Whether to follow the profile backwards.
* @param imirrored Whether to follow the profile mirrored.
*/
void moveTo(std::initializer_list<PathfinderPoint> iwaypoints,
bool ibackwards = false,
bool imirrored = false);
/**
* Generates a new path from the position (typically the current position) to the target and
* blocks until the controller has settled. Does not save the path which was generated.
*
* @param iwaypoints The waypoints to hit on the path.
* @param ilimits The limits to use for this path only.
* @param ibackwards Whether to follow the profile backwards.
* @param imirrored Whether to follow the profile mirrored.
*/
void moveTo(std::initializer_list<PathfinderPoint> iwaypoints,
const PathfinderLimits &ilimits,
bool ibackwards = false,
bool imirrored = false);
/**
* Returns the last error of the controller. Does not update when disabled. This implementation
* always returns zero since the robot is assumed to perfectly follow the path. Subclasses can
* override this to be more accurate using odometry information.
*
* @return the last error
*/
PathfinderPoint getError() const override;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return true.
*
* @return whether the controller is settled
*/
bool isSettled() override;
/**
* Resets the controller so it can start from 0 again properly. Keeps configuration from
* before. This implementation also stops movement.
*/
void reset() override;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* NOT cause the controller to move to its last set target.
*/
void flipDisable() override;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* NOT cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(bool iisDisabled) override;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override;
/**
* This implementation does nothing because the API always requires the starting position to be
* specified.
*/
void tarePosition() override;
/**
* This implementation does nothing because the maximum velocity is configured using
* PathfinderLimits elsewhere.
*
* @param imaxVelocity Ignored.
*/
void setMaxVelocity(std::int32_t imaxVelocity) override;
/**
* Starts the internal thread. This should not be called by normal users. This method is called
* by the `AsyncMotionProfileControllerBuilder` when making a new instance of this class.
*/
void startThread();
/**
* @return The underlying thread handle.
*/
CrossplatformThread *getThread() const;
/**
* Saves a generated path to a file. Paths are stored as `<ipathId>.csv`. An SD card
* must be inserted into the brain and the directory must exist. `idirectory` can be prefixed with
* `/usd/`, but it this is not required.
*
* @param idirectory The directory to store the path file in
* @param ipathId The path ID of the generated path
*/
void storePath(const std::string &idirectory, const std::string &ipathId);
/**
* Loads a path from a directory on the SD card containing a path CSV file. `/usd/` is
* automatically prepended to `idirectory` if it is not specified.
*
* @param idirectory The directory that the path files are stored in
* @param ipathId The path ID that the paths are stored under (and will be loaded into)
*/
void loadPath(const std::string &idirectory, const std::string &ipathId);
/**
* Attempts to remove a path without stopping execution. If that fails, disables the controller
* and removes the path.
*
* @param ipathId The path ID that will be removed
*/
void forceRemovePath(const std::string &ipathId);
protected:
std::shared_ptr<Logger> logger;
std::map<std::string, std::vector<squiggles::ProfilePoint>> paths{};
PathfinderLimits limits;
std::shared_ptr<ChassisModel> model;
ChassisScales scales;
AbstractMotor::GearsetRatioPair pair;
TimeUtil timeUtil;
// This must be locked when accessing the current path
CrossplatformMutex currentPathMutex;
std::string currentPath{""};
std::atomic_bool isRunning{false};
std::atomic_int direction{1};
std::atomic_bool mirrored{false};
std::atomic_bool disabled{false};
std::atomic_bool dtorCalled{false};
CrossplatformThread *task{nullptr};
static void trampoline(void *context);
void loop();
/**
* Follow the supplied path. Must follow the disabled lifecycle.
*/
virtual void executeSinglePath(const std::vector<squiggles::ProfilePoint> &path,
std::unique_ptr<AbstractRate> rate);
/**
* Converts linear chassis speed to rotational motor speed.
*
* @param linear chassis frame speed
* @return motor frame speed
*/
QAngularSpeed convertLinearToRotational(QSpeed linear) const;
std::string getPathErrorMessage(const std::vector<PathfinderPoint> &points,
const std::string &ipathId,
int length);
/**
* Joins and escapes a directory and file name
*
* @param directory The directory path, separated by forward slashes (/) and with or without a
* trailing slash
* @param filename The file name in the directory
* @return the fully qualified and legal path name
*/
static std::string makeFilePath(const std::string &directory, const std::string &filename);
void internalStorePath(std::ostream &file, const std::string &ipathId);
void internalLoadPath(std::istream &file, const std::string &ipathId);
void internalLoadPathfinderPath(std::istream &leftFile,
std::istream &rightFile,
const std::string &ipathId);
static constexpr double DT = 0.01;
};
} // namespace okapi

View File

@ -1,145 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncPositionController.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
namespace okapi {
/**
* Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever
* units the motor is in.
*/
class AsyncPosIntegratedController : public AsyncPositionController<double, double> {
public:
/**
* Closed-loop controller that uses the V5 motor's onboard control to move. Input units are
* whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is
* zero.
*
* @param imotor The motor to control.
* @param ipair The gearset.
* @param imaxVelocity The maximum velocity after gearing.
* @param itimeUtil The TimeUtil.
* @param ilogger The logger this instance will log to.
*/
AsyncPosIntegratedController(const std::shared_ptr<AbstractMotor> &imotor,
const AbstractMotor::GearsetRatioPair &ipair,
std::int32_t imaxVelocity,
const TimeUtil &itimeUtil,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
/**
* Sets the target for the controller.
*/
void setTarget(double itarget) override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
double getTarget() override;
/**
* @return The most recent value of the process variable.
*/
double getProcessValue() const override;
/**
* Returns the last error of the controller. Does not update when disabled.
*/
double getError() const override;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return true.
*
* @return whether the controller is settled
*/
bool isSettled() override;
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information.
*/
void reset() override;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*/
void flipDisable() override;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(bool iisDisabled) override;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override;
/**
* Blocks the current task until the controller has settled. Determining what settling means is
* implementation-dependent.
*/
void waitUntilSettled() override;
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller. The range of input values is expected to be [-1, 1].
*
* @param ivalue the controller's output in the range [-1, 1]
*/
void controllerSet(double ivalue) override;
/**
* Sets the "absolute" zero position of the controller to its current position.
*/
void tarePosition() override;
/**
* Sets a new maximum velocity in motor RPM [0-600].
*
* @param imaxVelocity The new maximum velocity in motor RPM [0-600].
*/
void setMaxVelocity(std::int32_t imaxVelocity) override;
/**
* Stops the motor mid-movement. Does not change the last set target.
*/
virtual void stop();
protected:
std::shared_ptr<Logger> logger;
TimeUtil timeUtil;
std::shared_ptr<AbstractMotor> motor;
AbstractMotor::GearsetRatioPair pair;
std::int32_t maxVelocity;
double lastTarget{0};
double offset{0};
bool controllerIsDisabled{false};
bool hasFirstTarget{false};
std::unique_ptr<SettledUtil> settledUtil;
/**
* Resumes moving after the controller is reset. Should not cause movement if the controller is
* turned off, reset, and turned back on.
*/
virtual void resumeMovement();
};
} // namespace okapi

View File

@ -1,100 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncPositionController.hpp"
#include "okapi/api/control/async/asyncWrapper.hpp"
#include "okapi/api/control/controllerOutput.hpp"
#include "okapi/api/control/iterative/iterativePosPidController.hpp"
#include "okapi/api/control/offsettableControllerInput.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <memory>
namespace okapi {
class AsyncPosPIDController : public AsyncWrapper<double, double>,
public AsyncPositionController<double, double> {
public:
/**
* An async position PID controller.
*
* @param iinput The controller input. Will be turned into an OffsettableControllerInput.
* @param ioutput The controller output.
* @param itimeUtil The TimeUtil.
* @param ikP The proportional gain.
* @param ikI The integral gain.
* @param ikD The derivative gain.
* @param ikBias The controller bias.
* @param iratio Any external gear ratio.
* @param iderivativeFilter The derivative filter.
*/
AsyncPosPIDController(
const std::shared_ptr<ControllerInput<double>> &iinput,
const std::shared_ptr<ControllerOutput<double>> &ioutput,
const TimeUtil &itimeUtil,
double ikP,
double ikI,
double ikD,
double ikBias = 0,
double iratio = 1,
std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(),
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
/**
* An async position PID controller.
*
* @param iinput The controller input.
* @param ioutput The controller output.
* @param itimeUtil The TimeUtil.
* @param ikP The proportional gain.
* @param ikI The integral gain.
* @param ikD The derivative gain.
* @param ikBias The controller bias.
* @param iratio Any external gear ratio.
* @param iderivativeFilter The derivative filter.
*/
AsyncPosPIDController(
const std::shared_ptr<OffsetableControllerInput> &iinput,
const std::shared_ptr<ControllerOutput<double>> &ioutput,
const TimeUtil &itimeUtil,
double ikP,
double ikI,
double ikD,
double ikBias = 0,
double iratio = 1,
std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(),
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
/**
* Sets the "absolute" zero position of the controller to its current position.
*/
void tarePosition() override;
/**
* This implementation does not respect the maximum velocity.
*
* @param imaxVelocity Ignored.
*/
void setMaxVelocity(std::int32_t imaxVelocity) override;
/**
* Set controller gains.
*
* @param igains The new gains.
*/
void setGains(const IterativePosPIDController::Gains &igains);
/**
* Gets the current gains.
*
* @return The current gains.
*/
IterativePosPIDController::Gains getGains() const;
protected:
std::shared_ptr<OffsetableControllerInput> offsettableInput;
std::shared_ptr<IterativePosPIDController> internalController;
};
} // namespace okapi

View File

@ -1,28 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncController.hpp"
#include <memory>
namespace okapi {
template <typename Input, typename Output>
class AsyncPositionController : virtual public AsyncController<Input, Output> {
public:
/**
* Sets the "absolute" zero position of the controller to its current position.
*/
virtual void tarePosition() = 0;
/**
* Sets a new maximum velocity (typically motor RPM [0-600]). The interpretation of the units
* of this velocity and whether it will be respected is implementation-dependent.
*
* @param imaxVelocity The new maximum velocity.
*/
virtual void setMaxVelocity(std::int32_t imaxVelocity) = 0;
};
} // namespace okapi

View File

@ -1,124 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncVelocityController.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <memory>
namespace okapi {
/**
* Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever
* units the motor is in.
*/
class AsyncVelIntegratedController : public AsyncVelocityController<double, double> {
public:
/**
* Closed-loop controller that uses the V5 motor's onboard control to move. Input units are
* whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is
* zero.
*
* @param imotor The motor to control.
* @param ipair The gearset.
* @param imaxVelocity The maximum velocity after gearing.
* @param itimeUtil The TimeUtil.
* @param ilogger The logger this instance will log to.
*/
AsyncVelIntegratedController(const std::shared_ptr<AbstractMotor> &imotor,
const AbstractMotor::GearsetRatioPair &ipair,
std::int32_t imaxVelocity,
const TimeUtil &itimeUtil,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
/**
* Sets the target for the controller.
*/
void setTarget(double itarget) override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
double getTarget() override;
/**
* @return The most recent value of the process variable.
*/
double getProcessValue() const override;
/**
* Returns the last error of the controller. Does not update when disabled.
*/
double getError() const override;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return true.
*
* @return whether the controller is settled
*/
bool isSettled() override;
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information.
*/
void reset() override;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*/
void flipDisable() override;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(bool iisDisabled) override;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override;
/**
* Blocks the current task until the controller has settled. Determining what settling means is
* implementation-dependent.
*/
void waitUntilSettled() override;
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller. The range of input values is expected to be [-1, 1].
*
* @param ivalue the controller's output in the range [-1, 1]
*/
void controllerSet(double ivalue) override;
protected:
std::shared_ptr<Logger> logger;
TimeUtil timeUtil;
std::shared_ptr<AbstractMotor> motor;
AbstractMotor::GearsetRatioPair pair;
std::int32_t maxVelocity;
double lastTarget = 0;
bool controllerIsDisabled = false;
bool hasFirstTarget = false;
std::unique_ptr<SettledUtil> settledUtil;
virtual void resumeMovement();
};
} // namespace okapi

View File

@ -1,64 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncVelocityController.hpp"
#include "okapi/api/control/async/asyncWrapper.hpp"
#include "okapi/api/control/controllerInput.hpp"
#include "okapi/api/control/controllerOutput.hpp"
#include "okapi/api/control/iterative/iterativeVelPidController.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <memory>
namespace okapi {
class AsyncVelPIDController : public AsyncWrapper<double, double>,
public AsyncVelocityController<double, double> {
public:
/**
* An async velocity PID controller.
*
* @param iinput The controller input.
* @param ioutput The controller output.
* @param itimeUtil The TimeUtil.
* @param ikP The proportional gain.
* @param ikD The derivative gain.
* @param ikF The feed-forward gain.
* @param ikSF A feed-forward gain to counteract static friction.
* @param ivelMath The VelMath used for calculating velocity.
* @param iratio Any external gear ratio.
* @param iderivativeFilter The derivative filter.
*/
AsyncVelPIDController(
const std::shared_ptr<ControllerInput<double>> &iinput,
const std::shared_ptr<ControllerOutput<double>> &ioutput,
const TimeUtil &itimeUtil,
double ikP,
double ikD,
double ikF,
double ikSF,
std::unique_ptr<VelMath> ivelMath,
double iratio = 1,
std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(),
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
/**
* Set controller gains.
*
* @param igains The new gains.
*/
void setGains(const IterativeVelPIDController::Gains &igains);
/**
* Gets the current gains.
*
* @return The current gains.
*/
IterativeVelPIDController::Gains getGains() const;
protected:
std::shared_ptr<IterativeVelPIDController> internalController;
};
} // namespace okapi

View File

@ -1,14 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncController.hpp"
#include <memory>
namespace okapi {
template <typename Input, typename Output>
class AsyncVelocityController : virtual public AsyncController<Input, Output> {};
} // namespace okapi

View File

@ -1,287 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncController.hpp"
#include "okapi/api/control/controllerInput.hpp"
#include "okapi/api/control/iterative/iterativeController.hpp"
#include "okapi/api/control/util/settledUtil.hpp"
#include "okapi/api/coreProsAPI.hpp"
#include "okapi/api/util/abstractRate.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/mathUtil.hpp"
#include "okapi/api/util/supplier.hpp"
#include <atomic>
#include <memory>
namespace okapi {
template <typename Input, typename Output>
class AsyncWrapper : virtual public AsyncController<Input, Output> {
public:
/**
* A wrapper class that transforms an `IterativeController` into an `AsyncController` by running
* it in another task. The input controller will act like an `AsyncController`.
*
* @param iinput controller input, passed to the `IterativeController`
* @param ioutput controller output, written to from the `IterativeController`
* @param icontroller the controller to use
* @param irateSupplier used for rates used in the main loop and in `waitUntilSettled`
* @param iratio Any external gear ratio.
* @param ilogger The logger this instance will log to.
*/
AsyncWrapper(const std::shared_ptr<ControllerInput<Input>> &iinput,
const std::shared_ptr<ControllerOutput<Output>> &ioutput,
const std::shared_ptr<IterativeController<Input, Output>> &icontroller,
const Supplier<std::unique_ptr<AbstractRate>> &irateSupplier,
const double iratio = 1,
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger())
: logger(std::move(ilogger)),
rateSupplier(irateSupplier),
input(iinput),
output(ioutput),
controller(icontroller),
ratio(iratio) {
}
AsyncWrapper(AsyncWrapper<Input, Output> &&other) = delete;
AsyncWrapper<Input, Output> &operator=(AsyncWrapper<Input, Output> &&other) = delete;
~AsyncWrapper() override {
dtorCalled.store(true, std::memory_order_release);
delete task;
}
/**
* Sets the target for the controller.
*/
void setTarget(const Input itarget) override {
LOG_INFO("AsyncWrapper: Set target to " + std::to_string(itarget));
hasFirstTarget = true;
controller->setTarget(itarget * ratio);
lastTarget = itarget;
}
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller.
*
* @param ivalue the controller's output
*/
void controllerSet(const Input ivalue) override {
controller->controllerSet(ivalue);
}
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
Input getTarget() override {
return controller->getTarget();
}
/**
* @return The most recent value of the process variable.
*/
Input getProcessValue() const override {
return controller->getProcessValue();
}
/**
* Returns the last calculated output of the controller.
*/
Output getOutput() const {
return controller->getOutput();
}
/**
* Returns the last error of the controller. Does not update when disabled.
*/
Output getError() const override {
return controller->getError();
}
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return true.
*
* @return whether the controller is settled
*/
bool isSettled() override {
return isDisabled() || controller->isSettled();
}
/**
* Set time between loops.
*
* @param isampleTime time between loops
*/
void setSampleTime(const QTime &isampleTime) {
controller->setSampleTime(isampleTime);
}
/**
* Set controller output bounds.
*
* @param imax max output
* @param imin min output
*/
void setOutputLimits(const Output imax, const Output imin) {
controller->setOutputLimits(imax, imin);
}
/**
* Sets the (soft) limits for the target range that controllerSet() scales into. The target
* computed by controllerSet() is scaled into the range [-itargetMin, itargetMax].
*
* @param itargetMax The new max target for controllerSet().
* @param itargetMin The new min target for controllerSet().
*/
void setControllerSetTargetLimits(double itargetMax, double itargetMin) {
controller->setControllerSetTargetLimits(itargetMax, itargetMin);
}
/**
* Get the upper output bound.
*
* @return the upper output bound
*/
Output getMaxOutput() {
return controller->getMaxOutput();
}
/**
* Get the lower output bound.
*
* @return the lower output bound
*/
Output getMinOutput() {
return controller->getMinOutput();
}
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information.
*/
void reset() override {
LOG_INFO_S("AsyncWrapper: Reset");
controller->reset();
hasFirstTarget = false;
}
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*/
void flipDisable() override {
LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(!controller->isDisabled()));
controller->flipDisable();
resumeMovement();
}
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(const bool iisDisabled) override {
LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(iisDisabled));
controller->flipDisable(iisDisabled);
resumeMovement();
}
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override {
return controller->isDisabled();
}
/**
* Blocks the current task until the controller has settled. Determining what settling means is
* implementation-dependent.
*/
void waitUntilSettled() override {
LOG_INFO_S("AsyncWrapper: Waiting to settle");
auto rate = rateSupplier.get();
while (!isSettled()) {
rate->delayUntil(motorUpdateRate);
}
LOG_INFO_S("AsyncWrapper: Done waiting to settle");
}
/**
* Starts the internal thread. This should not be called by normal users. This method is called
* by the AsyncControllerFactory when making a new instance of this class.
*/
void startThread() {
if (!task) {
task = new CrossplatformThread(trampoline, this, "AsyncWrapper");
}
}
/**
* Returns the underlying thread handle.
*
* @return The underlying thread handle.
*/
CrossplatformThread *getThread() const {
return task;
}
protected:
std::shared_ptr<Logger> logger;
Supplier<std::unique_ptr<AbstractRate>> rateSupplier;
std::shared_ptr<ControllerInput<Input>> input;
std::shared_ptr<ControllerOutput<Output>> output;
std::shared_ptr<IterativeController<Input, Output>> controller;
bool hasFirstTarget{false};
Input lastTarget;
double ratio;
std::atomic_bool dtorCalled{false};
CrossplatformThread *task{nullptr};
static void trampoline(void *context) {
if (context) {
static_cast<AsyncWrapper *>(context)->loop();
}
}
void loop() {
auto rate = rateSupplier.get();
while (!dtorCalled.load(std::memory_order_acquire) && !task->notifyTake(0)) {
if (!isDisabled()) {
output->controllerSet(controller->step(input->controllerGet()));
}
rate->delayUntil(controller->getSampleTime());
}
}
/**
* Resumes moving after the controller is reset. Should not cause movement if the controller is
* turned off, reset, and turned back on.
*/
virtual void resumeMovement() {
if (isDisabled()) {
// This will grab the output *when disabled*
output->controllerSet(controller->getOutput());
} else {
if (hasFirstTarget) {
setTarget(lastTarget);
}
}
}
};
} // namespace okapi

View File

@ -1,86 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/controllerOutput.hpp"
#include "okapi/api/units/QTime.hpp"
namespace okapi {
/**
* An abstract closed-loop controller.
*
* @tparam Input The target/input type.
* @tparam Output The error/output type.
*/
template <typename Input, typename Output>
class ClosedLoopController : public ControllerOutput<Input> {
public:
virtual ~ClosedLoopController() = default;
/**
* Sets the target for the controller.
*
* @param itarget the new target
*/
virtual void setTarget(Input itarget) = 0;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
virtual Input getTarget() = 0;
/**
* @return The most recent value of the process variable.
*/
virtual Input getProcessValue() const = 0;
/**
* Returns the last error of the controller. Does not update when disabled.
*
* @return the last error
*/
virtual Output getError() const = 0;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return `true`.
*
* @return whether the controller is settled
*/
virtual bool isSettled() = 0;
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information.
*/
virtual void reset() = 0;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*/
virtual void flipDisable() = 0;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
virtual void flipDisable(bool iisDisabled) = 0;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
virtual bool isDisabled() const = 0;
};
} // namespace okapi

View File

@ -1,19 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace okapi {
template <typename T> class ControllerInput {
public:
/**
* Get the sensor value for use in a control loop. This method might be automatically called in
* another thread by the controller.
*
* @return the current sensor value, or ``PROS_ERR`` on a failure.
*/
virtual T controllerGet() = 0;
};
} // namespace okapi

View File

@ -1,19 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace okapi {
template <typename T> class ControllerOutput {
public:
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller. The range of input values is expected to be `[-1, 1]`.
*
* @param ivalue the controller's output in the range `[-1, 1]`
*/
virtual void controllerSet(T ivalue) = 0;
};
} // namespace okapi

View File

@ -1,79 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/closedLoopController.hpp"
#include "okapi/api/units/QTime.hpp"
namespace okapi {
/**
* Closed-loop controller that steps iteratively using the step method below.
*
* `ControllerOutput::controllerSet()` should set the controller's target to the input scaled by
* the output bounds.
*/
template <typename Input, typename Output>
class IterativeController : public ClosedLoopController<Input, Output> {
public:
/**
* Do one iteration of the controller.
*
* @param ireading A new measurement.
* @return The controller output.
*/
virtual Output step(Input ireading) = 0;
/**
* Returns the last calculated output of the controller.
*/
virtual Output getOutput() const = 0;
/**
* Set controller output bounds.
*
* @param imax max output
* @param imin min output
*/
virtual void setOutputLimits(Output imax, Output imin) = 0;
/**
* Sets the (soft) limits for the target range that controllerSet() scales into. The target
* computed by `controllerSet()` is scaled into the range `[-itargetMin, itargetMax]`.
*
* @param itargetMax The new max target for `controllerSet()`.
* @param itargetMin The new min target for `controllerSet()`.
*/
virtual void setControllerSetTargetLimits(Output itargetMax, Output itargetMin) = 0;
/**
* Get the upper output bound.
*
* @return the upper output bound
*/
virtual Output getMaxOutput() = 0;
/**
* Get the lower output bound.
*
* @return the lower output bound
*/
virtual Output getMinOutput() = 0;
/**
* Set time between loops.
*
* @param isampleTime time between loops
*/
virtual void setSampleTime(QTime isampleTime) = 0;
/**
* Get the last set sample time.
*
* @return sample time
*/
virtual QTime getSampleTime() const = 0;
};
} // namespace okapi

View File

@ -1,150 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/iterative/iterativeVelocityController.hpp"
#include "okapi/api/device/motor/abstractMotor.hpp"
#include <array>
#include <memory>
namespace okapi {
class IterativeMotorVelocityController : public IterativeVelocityController<double, double> {
public:
/**
* Velocity controller that automatically writes to the motor.
*/
IterativeMotorVelocityController(
const std::shared_ptr<AbstractMotor> &imotor,
const std::shared_ptr<IterativeVelocityController<double, double>> &icontroller);
/**
* Do one iteration of the controller.
*
* @param inewReading new measurement
* @return controller output
*/
double step(double ireading) override;
/**
* Sets the target for the controller.
*/
void setTarget(double itarget) override;
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller. The range of input values is expected to be `[-1, 1]`.
*
* @param ivalue the controller's output in the range `[-1, 1]`
*/
void controllerSet(double ivalue) override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
double getTarget() override;
/**
* @return The most recent value of the process variable.
*/
double getProcessValue() const override;
/**
* Returns the last calculated output of the controller.
*/
double getOutput() const override;
/**
* Get the upper output bound.
*
* @return the upper output bound
*/
double getMaxOutput() override;
/**
* Get the lower output bound.
*
* @return the lower output bound
*/
double getMinOutput() override;
/**
* Returns the last error of the controller. Does not update when disabled.
*/
double getError() const override;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* @return whether the controller is settled
*/
bool isSettled() override;
/**
* Set time between loops in ms.
*
* @param isampleTime time between loops in ms
*/
void setSampleTime(QTime isampleTime) override;
/**
* Set controller output bounds.
*
* @param imax max output
* @param imin min output
*/
void setOutputLimits(double imax, double imin) override;
/**
* Sets the (soft) limits for the target range that controllerSet() scales into. The target
* computed by controllerSet() is scaled into the range [-itargetMin, itargetMax].
*
* @param itargetMax The new max target for controllerSet().
* @param itargetMin The new min target for controllerSet().
*/
void setControllerSetTargetLimits(double itargetMax, double itargetMin) override;
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information.
*/
void reset() override;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*/
void flipDisable() override;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(bool iisDisabled) override;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override;
/**
* Get the last set sample time.
*
* @return sample time
*/
QTime getSampleTime() const override;
protected:
std::shared_ptr<AbstractMotor> motor;
std::shared_ptr<IterativeVelocityController<double, double>> controller;
};
} // namespace okapi

View File

@ -1,276 +0,0 @@
/*
* Based on the Arduino PID controller: https://github.com/br3ttb/Arduino-PID-Library
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/iterative/iterativePositionController.hpp"
#include "okapi/api/control/util/settledUtil.hpp"
#include "okapi/api/filter/filter.hpp"
#include "okapi/api/filter/passthroughFilter.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <limits>
#include <memory>
namespace okapi {
class IterativePosPIDController : public IterativePositionController<double, double> {
public:
struct Gains {
double kP{0};
double kI{0};
double kD{0};
double kBias{0};
bool operator==(const Gains &rhs) const;
bool operator!=(const Gains &rhs) const;
};
/**
* Position PID controller.
*
* @param ikP the proportional gain
* @param ikI the integration gain
* @param ikD the derivative gain
* @param ikBias the controller bias
* @param itimeUtil see TimeUtil docs
* @param iderivativeFilter a filter for filtering the derivative term
* @param ilogger The logger this instance will log to.
*/
IterativePosPIDController(
double ikP,
double ikI,
double ikD,
double ikBias,
const TimeUtil &itimeUtil,
std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(),
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
/**
* Position PID controller.
*
* @param igains the controller gains
* @param itimeUtil see TimeUtil docs
* @param iderivativeFilter a filter for filtering the derivative term
*/
IterativePosPIDController(
const Gains &igains,
const TimeUtil &itimeUtil,
std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(),
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
/**
* Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the
* bounds have been changed with setOutputLimits().
*
* @param inewReading new measurement
* @return controller output
*/
double step(double inewReading) override;
/**
* Sets the target for the controller.
*
* @param itarget new target position
*/
void setTarget(double itarget) override;
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller. The range of input values is expected to be [-1, 1].
*
* @param ivalue the controller's output in the range [-1, 1]
*/
void controllerSet(double ivalue) override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
double getTarget() override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
double getTarget() const;
/**
* @return The most recent value of the process variable.
*/
double getProcessValue() const override;
/**
* Returns the last calculated output of the controller. Output is in the range [-1, 1]
* unless the bounds have been changed with setOutputLimits().
*/
double getOutput() const override;
/**
* Get the upper output bound.
*
* @return the upper output bound
*/
double getMaxOutput() override;
/**
* Get the lower output bound.
*
* @return the lower output bound
*/
double getMinOutput() override;
/**
* Returns the last error of the controller. Does not update when disabled.
*/
double getError() const override;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return true.
*
* @return whether the controller is settled
*/
bool isSettled() override;
/**
* Set time between loops in ms.
*
* @param isampleTime time between loops
*/
void setSampleTime(QTime isampleTime) override;
/**
* Set controller output bounds. Default bounds are [-1, 1].
*
* @param imax max output
* @param imin min output
*/
void setOutputLimits(double imax, double imin) override;
/**
* Sets the (soft) limits for the target range that controllerSet() scales into. The target
* computed by controllerSet() is scaled into the range [-itargetMin, itargetMax].
*
* @param itargetMax The new max target for controllerSet().
* @param itargetMin The new min target for controllerSet().
*/
void setControllerSetTargetLimits(double itargetMax, double itargetMin) override;
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information.
*/
void reset() override;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*/
void flipDisable() override;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(bool iisDisabled) override;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override;
/**
* Get the last set sample time.
*
* @return sample time
*/
QTime getSampleTime() const override;
/**
* Set integrator bounds. Default bounds are [-1, 1].
*
* @param imax max integrator value
* @param imin min integrator value
*/
virtual void setIntegralLimits(double imax, double imin);
/**
* Set the error sum bounds. Default bounds are [0, std::numeric_limits<double>::max()]. Error
* will only be added to the integral term when its absolute value is between these bounds of
* either side of the target.
*
* @param imax max error value that will be summed
* @param imin min error value that will be summed
*/
virtual void setErrorSumLimits(double imax, double imin);
/**
* Set whether the integrator should be reset when error is 0 or changes sign.
*
* @param iresetOnZero true to reset
*/
virtual void setIntegratorReset(bool iresetOnZero);
/**
* Set controller gains.
*
* @param igains The new gains.
*/
virtual void setGains(const Gains &igains);
/**
* Gets the current gains.
*
* @return The current gains.
*/
Gains getGains() const;
protected:
std::shared_ptr<Logger> logger;
double kP, kI, kD, kBias;
QTime sampleTime{10_ms};
double target{0};
double lastReading{0};
double error{0};
double lastError{0};
std::unique_ptr<Filter> derivativeFilter;
// Integral bounds
double integral{0};
double integralMax{1};
double integralMin{-1};
// Error will only be added to the integral term within these bounds on either side of the target
double errorSumMin{0};
double errorSumMax{std::numeric_limits<double>::max()};
double derivative{0};
// Output bounds
double output{0};
double outputMax{1};
double outputMin{-1};
double controllerSetTargetMax{1};
double controllerSetTargetMin{-1};
// Reset the integrated when the controller crosses 0 or not
bool shouldResetOnCross{true};
bool controllerIsDisabled{false};
std::unique_ptr<AbstractTimer> loopDtTimer;
std::unique_ptr<SettledUtil> settledUtil;
};
} // namespace okapi

View File

@ -1,13 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/iterative/iterativeController.hpp"
namespace okapi {
template <typename Input, typename Output>
class IterativePositionController : public IterativeController<Input, Output> {};
} // namespace okapi

View File

@ -1,255 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/iterative/iterativeVelocityController.hpp"
#include "okapi/api/control/util/settledUtil.hpp"
#include "okapi/api/filter/passthroughFilter.hpp"
#include "okapi/api/filter/velMath.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
namespace okapi {
class IterativeVelPIDController : public IterativeVelocityController<double, double> {
public:
struct Gains {
double kP{0};
double kD{0};
double kF{0};
double kSF{0};
bool operator==(const Gains &rhs) const;
bool operator!=(const Gains &rhs) const;
};
/**
* Velocity PD controller.
*
* @param ikP the proportional gain
* @param ikD the derivative gain
* @param ikF the feed-forward gain
* @param ikSF a feed-forward gain to counteract static friction
* @param ivelMath The VelMath used for calculating velocity.
* @param itimeUtil see TimeUtil docs
* @param iderivativeFilter a filter for filtering the derivative term
* @param ilogger The logger this instance will log to.
*/
IterativeVelPIDController(
double ikP,
double ikD,
double ikF,
double ikSF,
std::unique_ptr<VelMath> ivelMath,
const TimeUtil &itimeUtil,
std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(),
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
/**
* Velocity PD controller.
*
* @param igains The controller gains.
* @param ivelMath The VelMath used for calculating velocity.
* @param itimeUtil see TimeUtil docs
* @param iderivativeFilter a filter for filtering the derivative term
* @param ilogger The logger this instance will log to.
*/
IterativeVelPIDController(
const Gains &igains,
std::unique_ptr<VelMath> ivelMath,
const TimeUtil &itimeUtil,
std::unique_ptr<Filter> iderivativeFilter = std::make_unique<PassthroughFilter>(),
std::shared_ptr<Logger> ilogger = Logger::getDefaultLogger());
/**
* Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the
* bounds have been changed with setOutputLimits().
*
* @param inewReading new measurement
* @return controller output
*/
double step(double inewReading) override;
/**
* Sets the target for the controller.
*
* @param itarget new target velocity
*/
void setTarget(double itarget) override;
/**
* Writes the value of the controller output. This method might be automatically called in another
* thread by the controller. The range of input values is expected to be [-1, 1].
*
* @param ivalue the controller's output in the range [-1, 1]
*/
void controllerSet(double ivalue) override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
double getTarget() override;
/**
* Gets the last set target, or the default target if none was set.
*
* @return the last target
*/
double getTarget() const;
/**
* @return The most recent value of the process variable.
*/
double getProcessValue() const override;
/**
* Returns the last calculated output of the controller.
*/
double getOutput() const override;
/**
* Get the upper output bound.
*
* @return the upper output bound
*/
double getMaxOutput() override;
/**
* Get the lower output bound.
*
* @return the lower output bound
*/
double getMinOutput() override;
/**
* Returns the last error of the controller. Does not update when disabled.
*/
double getError() const override;
/**
* Returns whether the controller has settled at the target. Determining what settling means is
* implementation-dependent.
*
* If the controller is disabled, this method must return true.
*
* @return whether the controller is settled
*/
bool isSettled() override;
/**
* Set time between loops in ms.
*
* @param isampleTime time between loops
*/
void setSampleTime(QTime isampleTime) override;
/**
* Set controller output bounds. Default bounds are [-1, 1].
*
* @param imax max output
* @param imin min output
*/
void setOutputLimits(double imax, double imin) override;
/**
* Sets the (soft) limits for the target range that controllerSet() scales into. The target
* computed by controllerSet() is scaled into the range [-itargetMin, itargetMax].
*
* @param itargetMax The new max target for controllerSet().
* @param itargetMin The new min target for controllerSet().
*/
void setControllerSetTargetLimits(double itargetMax, double itargetMin) override;
/**
* Resets the controller's internal state so it is similar to when it was first initialized, while
* keeping any user-configured information.
*/
void reset() override;
/**
* Changes whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*/
void flipDisable() override;
/**
* Sets whether the controller is off or on. Turning the controller on after it was off will
* cause the controller to move to its last set target, unless it was reset in that time.
*
* @param iisDisabled whether the controller is disabled
*/
void flipDisable(bool iisDisabled) override;
/**
* Returns whether the controller is currently disabled.
*
* @return whether the controller is currently disabled
*/
bool isDisabled() const override;
/**
* Get the last set sample time.
*
* @return sample time
*/
QTime getSampleTime() const override;
/**
* Do one iteration of velocity calculation.
*
* @param inewReading new measurement
* @return filtered velocity
*/
virtual QAngularSpeed stepVel(double inewReading);
/**
* Set controller gains.
*
* @param igains The new gains.
*/
virtual void setGains(const Gains &igains);
/**
* Gets the current gains.
*
* @return The current gains.
*/
Gains getGains() const;
/**
* Sets the number of encoder ticks per revolution. Default is 1800.
*
* @param tpr number of measured units per revolution
*/
virtual void setTicksPerRev(double tpr);
/**
* Returns the current velocity.
*/
virtual QAngularSpeed getVel() const;
protected:
std::shared_ptr<Logger> logger;
double kP, kD, kF, kSF;
QTime sampleTime{10_ms};
double error{0};
double derivative{0};
double target{0};
double outputSum{0};
double output{0};
double outputMax{1};
double outputMin{-1};
double controllerSetTargetMax{1};
double controllerSetTargetMin{-1};
bool controllerIsDisabled{false};
std::unique_ptr<VelMath> velMath;
std::unique_ptr<Filter> derivativeFilter;
std::unique_ptr<AbstractTimer> loopDtTimer;
std::unique_ptr<SettledUtil> settledUtil;
};
} // namespace okapi

View File

@ -1,13 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/iterative/iterativeController.hpp"
namespace okapi {
template <typename Input, typename Output>
class IterativeVelocityController : public IterativeController<Input, Output> {};
} // namespace okapi

View File

@ -1,41 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/controllerInput.hpp"
#include <memory>
namespace okapi {
class OffsetableControllerInput : public ControllerInput<double> {
public:
/**
* A ControllerInput which can be tared to change the zero position.
*
* @param iinput The ControllerInput to reference.
*/
explicit OffsetableControllerInput(const std::shared_ptr<ControllerInput<double>> &iinput);
virtual ~OffsetableControllerInput();
/**
* Get the sensor value for use in a control loop. This method might be automatically called in
* another thread by the controller.
*
* @return the current sensor value, or PROS_ERR on a failure.
*/
double controllerGet() override;
/**
* Sets the "absolute" zero position of this controller input to its current position. This does
* nothing if the underlying controller input returns PROS_ERR.
*/
virtual void tarePosition();
protected:
std::shared_ptr<ControllerInput<double>> input;
double offset{0};
};
} // namespace okapi

View File

@ -1,131 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/async/asyncController.hpp"
#include "okapi/api/control/controllerOutput.hpp"
#include "okapi/api/control/iterative/iterativeController.hpp"
#include "okapi/api/util/abstractRate.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <memory>
namespace okapi {
template <typename Input, typename Output> class ControllerRunner {
public:
/**
* A utility class that runs a closed-loop controller.
*
* @param itimeUtil The TimeUtil.
* @param ilogger The logger this instance will log to.
*/
explicit ControllerRunner(const TimeUtil &itimeUtil,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger())
: logger(ilogger), rate(itimeUtil.getRate()) {
}
/**
* Runs the controller until it has settled.
*
* @param itarget the new target
* @param icontroller the controller to run
* @return the error when settled
*/
virtual Output runUntilSettled(const Input itarget, AsyncController<Input, Output> &icontroller) {
LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Set target to " +
std::to_string(itarget));
icontroller.setTarget(itarget);
while (!icontroller.isSettled()) {
rate->delayUntil(10_ms);
}
LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Done waiting to settle");
return icontroller.getError();
}
/**
* Runs the controller until it has settled.
*
* @param itarget the new target
* @param icontroller the controller to run
* @param ioutput the output to write to
* @return the error when settled
*/
virtual Output runUntilSettled(const Input itarget,
IterativeController<Input, Output> &icontroller,
ControllerOutput<Output> &ioutput) {
LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Set target to " +
std::to_string(itarget));
icontroller.setTarget(itarget);
while (!icontroller.isSettled()) {
ioutput.controllerSet(icontroller.getOutput());
rate->delayUntil(10_ms);
}
LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Done waiting to settle");
return icontroller.getError();
}
/**
* Runs the controller until it has reached its target, but not necessarily settled.
*
* @param itarget the new target
* @param icontroller the controller to run
* @return the error when settled
*/
virtual Output runUntilAtTarget(const Input itarget,
AsyncController<Input, Output> &icontroller) {
LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Set target to " +
std::to_string(itarget));
icontroller.setTarget(itarget);
double error = icontroller.getError();
double lastError = error;
while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) {
lastError = error;
rate->delayUntil(10_ms);
error = icontroller.getError();
}
LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Done waiting to settle");
return icontroller.getError();
}
/**
* Runs the controller until it has reached its target, but not necessarily settled.
*
* @param itarget the new target
* @param icontroller the controller to run
* @param ioutput the output to write to
* @return the error when settled
*/
virtual Output runUntilAtTarget(const Input itarget,
IterativeController<Input, Output> &icontroller,
ControllerOutput<Output> &ioutput) {
LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Set target to " +
std::to_string(itarget));
icontroller.setTarget(itarget);
double error = icontroller.getError();
double lastError = error;
while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) {
ioutput.controllerSet(icontroller.getOutput());
lastError = error;
rate->delayUntil(10_ms);
error = icontroller.getError();
}
LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Done waiting to settle");
return icontroller.getError();
}
protected:
std::shared_ptr<Logger> logger;
std::unique_ptr<AbstractRate> rate;
};
} // namespace okapi

View File

@ -1,156 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <functional>
namespace okapi {
class FlywheelSimulator {
public:
/**
* A simulator for an inverted pendulum. The center of mass of the system changes as the link
* rotates (by default, you can set a new torque function with setExternalTorqueFunction()).
*/
explicit FlywheelSimulator(double imass = 0.01,
double ilinkLen = 1,
double imuStatic = 0.1,
double imuDynamic = 0.9,
double itimestep = 0.01);
virtual ~FlywheelSimulator();
/**
* Step the simulation by the timestep.
*
* @return the current angle
*/
double step();
/**
* Step the simulation by the timestep.
*
* @param itorque new input torque
* @return the current angle
*/
double step(double itorque);
/**
* Sets the torque function used to calculate the torque due to external forces. This torque gets
* summed with the input torque.
*
* For example, the default torque function has the torque due to gravity vary as the link swings:
* [](double angle, double mass, double linkLength) {
* return (linkLength * std::cos(angle)) * (mass * -1 * gravity);
* }
*
* @param itorqueFunc the torque function. The return value is the torque due to external forces
*/
void setExternalTorqueFunction(
std::function<double(double angle, double mass, double linkLength)> itorqueFunc);
/**
* Sets the input torque. The input will be bounded by the max torque.
*
* @param itorque new input torque
*/
void setTorque(double itorque);
/**
* Sets the max torque. The input torque cannot exceed this maximum torque.
*
* @param imaxTorque new maximum torque
*/
void setMaxTorque(double imaxTorque);
/**
* Sets the current angle.
*
* @param iangle new angle
**/
void setAngle(double iangle);
/**
* Sets the mass (kg).
*
* @param imass new mass
*/
void setMass(double imass);
/**
* Sets the link length (m).
*
* @param ilinkLen new link length
*/
void setLinkLength(double ilinkLen);
/**
* Sets the static friction (N*m).
*
* @param imuStatic new static friction
*/
void setStaticFriction(double imuStatic);
/**
* Sets the dynamic friction (N*m).
*
* @param imuDynamic new dynamic friction
*/
void setDynamicFriction(double imuDynamic);
/**
* Sets the timestep (sec).
*
* @param itimestep new timestep
*/
void setTimestep(double itimestep);
/**
* Returns the current angle (angle in rad).
*
* @return the current angle
*/
double getAngle() const;
/**
* Returns the current omgea (angular velocity in rad / sec).
*
* @return the current omega
*/
double getOmega() const;
/**
* Returns the current acceleration (angular acceleration in rad / sec^2).
*
* @return the current acceleration
*/
double getAcceleration() const;
/**
* Returns the maximum torque input.
*
* @return the max torque input
*/
double getMaxTorque() const;
protected:
double inputTorque = 0; // N*m
double maxTorque = 0.5649; // N*m
double angle = 0; // rad
double omega = 0; // rad / sec
double accel = 0; // rad / sec^2
double mass; // kg
double linkLen; // m
double muStatic; // N*m
double muDynamic; // N*m
double timestep; // sec
double I = 0; // moment of inertia
std::function<double(double, double, double)> torqueFunc;
const double minTimestep = 0.000001; // 1 us
virtual double stepImpl();
};
} // namespace okapi

View File

@ -1,23 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/units/QAngle.hpp"
#include "okapi/api/units/QLength.hpp"
namespace okapi {
struct PathfinderPoint {
QLength x; // X coordinate relative to the start of the movement
QLength y; // Y coordinate relative to the start of the movement
QAngle theta; // Exit angle relative to the start of the movement
};
struct PathfinderLimits {
double maxVel; // Maximum robot velocity in m/s
double maxAccel; // Maximum robot acceleration in m/s/s
double maxJerk; // Maximum robot jerk in m/s/s/s
};
} // namespace okapi

View File

@ -1,80 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/controllerInput.hpp"
#include "okapi/api/control/controllerOutput.hpp"
#include "okapi/api/control/iterative/iterativePosPidController.hpp"
#include "okapi/api/units/QTime.hpp"
#include "okapi/api/util/logging.hpp"
#include "okapi/api/util/timeUtil.hpp"
#include <memory>
#include <vector>
namespace okapi {
class PIDTuner {
public:
struct Output {
double kP, kI, kD;
};
PIDTuner(const std::shared_ptr<ControllerInput<double>> &iinput,
const std::shared_ptr<ControllerOutput<double>> &ioutput,
const TimeUtil &itimeUtil,
QTime itimeout,
std::int32_t igoal,
double ikPMin,
double ikPMax,
double ikIMin,
double ikIMax,
double ikDMin,
double ikDMax,
std::size_t inumIterations = 5,
std::size_t inumParticles = 16,
double ikSettle = 1,
double ikITAE = 2,
const std::shared_ptr<Logger> &ilogger = Logger::getDefaultLogger());
virtual ~PIDTuner();
virtual Output autotune();
protected:
static constexpr double inertia = 0.5; // Particle inertia
static constexpr double confSelf = 1.1; // Self confidence
static constexpr double confSwarm = 1.2; // Particle swarm confidence
static constexpr int increment = 5;
static constexpr int divisor = 5;
static constexpr QTime loopDelta = 10_ms; // NOLINT
struct Particle {
double pos, vel, best;
};
struct ParticleSet {
Particle kP, kI, kD;
double bestError;
};
std::shared_ptr<Logger> logger;
TimeUtil timeUtil;
std::shared_ptr<ControllerInput<double>> input;
std::shared_ptr<ControllerOutput<double>> output;
const QTime timeout;
const std::int32_t goal;
const double kPMin;
const double kPMax;
const double kIMin;
const double kIMax;
const double kDMin;
const double kDMax;
const std::size_t numIterations;
const std::size_t numParticles;
const double kSettle;
const double kITAE;
};
} // namespace okapi

View File

@ -1,51 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/units/QTime.hpp"
#include "okapi/api/util/abstractTimer.hpp"
#include <memory>
namespace okapi {
class SettledUtil {
public:
/**
* A utility class to determine if a control loop has settled based on error. A control loop is
* settled if the error is within `iatTargetError` and `iatTargetDerivative` for `iatTargetTime`.
*
* @param iatTargetTimer A timer used to track `iatTargetTime`.
* @param iatTargetError The minimum error to be considered settled.
* @param iatTargetDerivative The minimum error derivative to be considered settled.
* @param iatTargetTime The minimum time within atTargetError to be considered settled.
*/
explicit SettledUtil(std::unique_ptr<AbstractTimer> iatTargetTimer,
double iatTargetError = 50,
double iatTargetDerivative = 5,
QTime iatTargetTime = 250_ms);
virtual ~SettledUtil();
/**
* Returns whether the controller is settled.
*
* @param ierror The current error.
* @return Whether the controller is settled.
*/
virtual bool isSettled(double ierror);
/**
* Resets the "at target" timer and clears the previous error.
*/
virtual void reset();
protected:
double atTargetError = 50;
double atTargetDerivative = 5;
QTime atTargetTime = 250_ms;
std::unique_ptr<AbstractTimer> atTargetTimer;
double lastError = 0;
};
} // namespace okapi

View File

@ -1,131 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <cmath>
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <sstream>
#ifdef THREADS_STD
#include <thread>
#define CROSSPLATFORM_THREAD_T std::thread
#include <mutex>
#define CROSSPLATFORM_MUTEX_T std::mutex
#else
#include "api.h"
#include "pros/apix.h"
#define CROSSPLATFORM_THREAD_T pros::task_t
#define CROSSPLATFORM_MUTEX_T pros::Mutex
#endif
#define NOT_INITIALIZE_TASK \
(strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Initialization (PROS)") != 0)
#define NOT_COMP_INITIALIZE_TASK \
(strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Comp. Init. (PROS)") != 0)
class CrossplatformThread {
public:
#ifdef THREADS_STD
CrossplatformThread(void (*ptr)(void *),
void *params,
const char *const = "OkapiLibCrossplatformTask")
#else
CrossplatformThread(void (*ptr)(void *),
void *params,
const char *const name = "OkapiLibCrossplatformTask")
#endif
:
#ifdef THREADS_STD
thread(ptr, params)
#else
thread(
pros::c::task_create(ptr, params, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name))
#endif
{
}
~CrossplatformThread() {
#ifdef THREADS_STD
thread.join();
#else
if (pros::c::task_get_state(thread) != pros::E_TASK_STATE_DELETED) {
pros::c::task_delete(thread);
}
#endif
}
#ifdef THREADS_STD
void notifyWhenDeleting(CrossplatformThread *) {
}
#else
void notifyWhenDeleting(CrossplatformThread *parent) {
pros::c::task_notify_when_deleting(parent->thread, thread, 1, pros::E_NOTIFY_ACTION_INCR);
}
#endif
#ifdef THREADS_STD
void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T *) {
}
#else
void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T parent) {
pros::c::task_notify_when_deleting(parent, thread, 1, pros::E_NOTIFY_ACTION_INCR);
}
#endif
#ifdef THREADS_STD
std::uint32_t notifyTake(const std::uint32_t) {
return 0;
}
#else
std::uint32_t notifyTake(const std::uint32_t itimeout) {
return pros::c::task_notify_take(true, itimeout);
}
#endif
static std::string getName() {
#ifdef THREADS_STD
std::ostringstream ss;
ss << std::this_thread::get_id();
return ss.str();
#else
return std::string(pros::c::task_get_name(NULL));
#endif
}
CROSSPLATFORM_THREAD_T thread;
};
class CrossplatformMutex {
public:
CrossplatformMutex() = default;
void lock() {
#ifdef THREADS_STD
mutex.lock();
#else
while (!mutex.take(1)) {
}
#endif
}
void unlock() {
#ifdef THREADS_STD
mutex.unlock();
#else
mutex.give();
#endif
}
protected:
CROSSPLATFORM_MUTEX_T mutex;
};

View File

@ -1,46 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/controllerInput.hpp"
namespace okapi {
class AbstractButton : public ControllerInput<bool> {
public:
virtual ~AbstractButton();
/**
* Return whether the button is currently pressed.
**/
virtual bool isPressed() = 0;
/**
* Return whether the state of the button changed since the last time this method was
* called.
**/
virtual bool changed() = 0;
/**
* Return whether the state of the button changed to being pressed since the last time this method
* was called.
**/
virtual bool changedToPressed() = 0;
/**
* Return whether the state of the button to being not pressed changed since the last time this
* method was called.
**/
virtual bool changedToReleased() = 0;
/**
* Get the sensor value for use in a control loop. This method might be automatically called in
* another thread by the controller.
*
* @return the current sensor value. This is the same as the output of the pressed() method.
*/
virtual bool controllerGet() override;
};
} // namespace okapi

View File

@ -1,52 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/device/button/abstractButton.hpp"
namespace okapi {
class ButtonBase : public AbstractButton {
public:
/**
* @param iinverted Whether the button is inverted (`true` meaning default pressed and `false`
* meaning default not pressed).
*/
explicit ButtonBase(bool iinverted = false);
/**
* Return whether the button is currently pressed.
**/
bool isPressed() override;
/**
* Return whether the state of the button changed since the last time this method was called.
**/
bool changed() override;
/**
* Return whether the state of the button changed to pressed since the last time this method was
*called.
**/
bool changedToPressed() override;
/**
* Return whether the state of the button to not pressed since the last time this method was
*called.
**/
bool changedToReleased() override;
protected:
bool inverted{false};
bool wasPressedLast_c{false};
bool wasPressedLast_ctp{false};
bool wasPressedLast_ctr{false};
virtual bool currentlyPressed() = 0;
private:
bool changedImpl(bool &prevState);
};
} // namespace okapi

View File

@ -1,537 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/controllerOutput.hpp"
#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp"
#include <memory>
namespace okapi {
class AbstractMotor : public ControllerOutput<double> {
public:
/**
* Indicates the 'brake mode' of a motor.
*/
enum class brakeMode {
coast = 0, ///< Motor coasts when stopped, traditional behavior
brake = 1, ///< Motor brakes when stopped
hold = 2, ///< Motor actively holds position when stopped
invalid = INT32_MAX
};
/**
* Indicates the units used by the motor encoders.
*/
enum class encoderUnits {
degrees = 0, ///< degrees
rotations = 1, ///< rotations
counts = 2, ///< counts
invalid = INT32_MAX ///< invalid
};
/**
* Indicates the internal gear ratio of a motor.
*/
enum class gearset {
red = 100, ///< 36:1, 100 RPM, Red gear set
green = 200, ///< 18:1, 200 RPM, Green gear set
blue = 600, ///< 6:1, 600 RPM, Blue gear set
invalid = INT32_MAX
};
/**
* A simple structure representing the full ratio between motor and wheel.
*/
struct GearsetRatioPair {
/**
* A simple structure representing the full ratio between motor and wheel.
*
* The ratio is `motor rotation : wheel rotation`, e.x., if one motor rotation
* corresponds to two wheel rotations, the ratio is `1.0/2.0`.
*
* @param igearset The gearset in the motor.
* @param iratio The ratio of motor rotation to wheel rotation.
*/
GearsetRatioPair(const gearset igearset, const double iratio = 1)
: internalGearset(igearset), ratio(iratio) {
}
~GearsetRatioPair() = default;
gearset internalGearset;
double ratio = 1;
};
virtual ~AbstractMotor();
/******************************************************************************/
/** Motor movement functions **/
/** **/
/** These functions allow programmers to make motors move **/
/******************************************************************************/
/**
* Sets the target absolute position for the motor to move to.
*
* This movement is relative to the position of the motor when initialized or
* the position when it was most recently reset with setZeroPosition().
*
* @note This function simply sets the target for the motor, it does not block program execution
* until the movement finishes.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param iposition The absolute position to move to in the motor's encoder units
* @param ivelocity The maximum allowable velocity for the movement in RPM
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) = 0;
/**
* Sets the relative target position for the motor to move to.
*
* This movement is relative to the current position of the motor. Providing 10.0 as the position
* parameter would result in the motor moving clockwise 10 units, no matter what the current
* position is.
*
* @note This function simply sets the target for the motor, it does not block program execution
* until the movement finishes.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param iposition The relative position to move to in the motor's encoder units
* @param ivelocity The maximum allowable velocity for the movement in RPM
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t moveRelative(double iposition, std::int32_t ivelocity) = 0;
/**
* Sets the velocity for the motor.
*
* This velocity corresponds to different actual speeds depending on the gearset
* used for the motor. This results in a range of +-100 for pros::c::red,
* +-200 for green, and +-600 for blue. The velocity
* is held with PID to ensure consistent speed, as opposed to setting the motor's
* voltage.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's
* gearset
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t moveVelocity(std::int16_t ivelocity) = 0;
/**
* Sets the voltage for the motor from -12000 to 12000.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param ivoltage The new voltage value from -12000 to 12000
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t moveVoltage(std::int16_t ivoltage) = 0;
/**
* Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will
* have no effect if the motor is not following a profiled movement.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's
* gearset
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) = 0;
/******************************************************************************/
/** Motor telemetry functions **/
/** **/
/** These functions allow programmers to collect telemetry from motors **/
/******************************************************************************/
/**
* Gets the target position set for the motor by the user.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The target position in its encoder units or PROS_ERR_F if the operation failed,
* setting errno.
*/
virtual double getTargetPosition() = 0;
/**
* Gets the absolute position of the motor in its encoder units.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation
* failed, setting errno.
*/
virtual double getPosition() = 0;
/**
* Gets the positional error (target position minus actual position) of the motor in its encoder
* units.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's positional error in its encoder units or PROS_ERR_F if the operation
* failed, setting errno.
*/
double getPositionError();
/**
* Sets the "absolute" zero position of the motor to its current position.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t tarePosition() = 0;
/**
* Gets the velocity commanded to the motor by the user.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation
* failed, setting errno.
*/
virtual std::int32_t getTargetVelocity() = 0;
/**
* Gets the actual velocity of the motor.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting
* errno.
*/
virtual double getActualVelocity() = 0;
/**
* Gets the difference between the target velocity of the motor and the actual velocity of the
* motor.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's velocity error in RPM or PROS_ERR_F if the operation failed, setting
* errno.
*/
double getVelocityError();
/**
* Gets the current drawn by the motor in mA.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's current in mA or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t getCurrentDraw() = 0;
/**
* Gets the direction of movement for the motor.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return 1 for moving in the positive direction, -1 for moving in the negative direction, and
* PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t getDirection() = 0;
/**
* Gets the efficiency of the motor in percent.
*
* An efficiency of 100% means that the motor is moving electrically while
* drawing no electrical power, and an efficiency of 0% means that the motor
* is drawing power but not moving.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno.
*/
virtual double getEfficiency() = 0;
/**
* Checks if the motor is drawing over its current limit.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return 1 if the motor's current limit is being exceeded and 0 if the current limit is not
* exceeded, or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t isOverCurrent() = 0;
/**
* Checks if the motor's temperature is above its limit.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit,
* or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t isOverTemp() = 0;
/**
* Checks if the motor is stopped.
*
* Although this function forwards data from the motor, the motor presently does not provide any
* value. This function returns PROS_ERR with errno set to ENOSYS.
*
* @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation
* failed, setting errno
*/
virtual std::int32_t isStopped() = 0;
/**
* Checks if the motor is at its zero position.
*
* Although this function forwards data from the motor, the motor presently does not provide any
* value. This function returns PROS_ERR with errno set to ENOSYS.
*
* @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute
* zero, or PROS_ERR if the operation failed, setting errno
*/
virtual std::int32_t getZeroPositionFlag() = 0;
/**
* Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in
* pros::motor_fault_e_t.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit
* Hit
*/
virtual uint32_t getFaults() = 0;
/**
* Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in
* pros::motor_flag_e_t.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated
* to the individual get_specific_flag functions
*/
virtual uint32_t getFlags() = 0;
/**
* Gets the raw encoder count of the motor at a given timestamp.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param timestamp A pointer to a time in milliseconds for which the encoder count will be
* returned. If NULL, the timestamp at which the encoder count was read will not be supplied
*
* @return The raw encoder count at the given timestamp or PROS_ERR if the operation failed.
*/
virtual std::int32_t getRawPosition(std::uint32_t *timestamp) = 0;
/**
* Gets the power drawn by the motor in Watts.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno.
*/
virtual double getPower() = 0;
/**
* Gets the temperature of the motor in degrees Celsius.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed,
* setting errno.
*/
virtual double getTemperature() = 0;
/**
* Gets the torque generated by the motor in Newton Metres (Nm).
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno.
*/
virtual double getTorque() = 0;
/**
* Gets the voltage delivered to the motor in millivolts.
*
* This function uses the following values of errno when an error state is
* reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno.
*/
virtual std::int32_t getVoltage() = 0;
/******************************************************************************/
/** Motor configuration functions **/
/** **/
/** These functions allow programmers to configure the behavior of motors **/
/******************************************************************************/
/**
* Sets one of brakeMode to the motor.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param imode The new motor brake mode to set for the motor
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t setBrakeMode(brakeMode imode) = 0;
/**
* Gets the brake mode that was set for the motor.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the
* operation failed, setting errno.
*/
virtual brakeMode getBrakeMode() = 0;
/**
* Sets the current limit for the motor in mA.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param ilimit The new current limit in mA
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t setCurrentLimit(std::int32_t ilimit) = 0;
/**
* Gets the current limit for the motor in mA.
*
* The default value is 2500 mA.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t getCurrentLimit() = 0;
/**
* Sets one of encoderUnits for the motor encoder.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param iunits The new motor encoder units
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t setEncoderUnits(encoderUnits iunits) = 0;
/**
* Gets the encoder units that were set for the motor.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if
* the operation failed.
*/
virtual encoderUnits getEncoderUnits() = 0;
/**
* Sets one of gearset for the motor.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param igearset The new motor gearset
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t setGearing(gearset igearset) = 0;
/**
* Gets the gearset that was set for the motor.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @return One of gearset according to what is set for the motor, or gearset::invalid if the
* operation failed.
*/
virtual gearset getGearing() = 0;
/**
* Sets the reverse flag for the motor.
*
* This will invert its movements and the values returned for its position.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param ireverse True reverses the motor, false is default
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t setReversed(bool ireverse) = 0;
/**
* Sets the voltage limit for the motor in Volts.
*
* This function uses the following values of errno when an error state is reached:
* EACCES - Another resource is currently trying to access the port.
*
* @param ilimit The new voltage limit in Volts
* @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno.
*/
virtual std::int32_t setVoltageLimit(std::int32_t ilimit) = 0;
/**
* Returns the encoder associated with this motor.
*
* @return the encoder for this motor
*/
virtual std::shared_ptr<ContinuousRotarySensor> getEncoder() = 0;
};
AbstractMotor::GearsetRatioPair operator*(AbstractMotor::gearset gearset, double ratio);
} // namespace okapi

View File

@ -1,20 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/device/rotarysensor/rotarySensor.hpp"
namespace okapi {
class ContinuousRotarySensor : public RotarySensor {
public:
/**
* Reset the sensor to zero.
*
* @return `1` on success, `PROS_ERR` on fail
*/
virtual std::int32_t reset() = 0;
};
} // namespace okapi

View File

@ -1,23 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/control/controllerInput.hpp"
#include "okapi/api/coreProsAPI.hpp"
namespace okapi {
class RotarySensor : public ControllerInput<double> {
public:
virtual ~RotarySensor();
/**
* Get the current sensor value.
*
* @return the current sensor value, or `PROS_ERR` on a failure.
*/
virtual double get() const = 0;
};
} // namespace okapi

View File

@ -1,59 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/filter/filter.hpp"
#include <array>
#include <cstddef>
namespace okapi {
/**
* A filter which returns the average of a list of values.
*
* @tparam n number of taps in the filter
*/
template <std::size_t n> class AverageFilter : public Filter {
public:
/**
* Averaging filter.
*/
AverageFilter() = default;
/**
* Filters a value, like a sensor reading.
*
* @param ireading new measurement
* @return filtered result
*/
double filter(const double ireading) override {
data[index++] = ireading;
if (index >= n) {
index = 0;
}
output = 0.0;
for (size_t i = 0; i < n; i++)
output += data[i];
output /= (double)n;
return output;
}
/**
* Returns the previous output from filter.
*
* @return the previous output from filter
*/
double getOutput() const override {
return output;
}
protected:
std::array<double, n> data{0};
std::size_t index = 0;
double output = 0;
};
} // namespace okapi

View File

@ -1,50 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "okapi/api/filter/filter.hpp"
#include <functional>
#include <initializer_list>
#include <memory>
#include <vector>
namespace okapi {
class ComposableFilter : public Filter {
public:
/**
* A composable filter is a filter that consists of other filters. The input signal is passed
* through each filter in sequence. The final output of this filter is the output of the last
* filter.
*
* @param ilist The filters to use in sequence.
*/
ComposableFilter(const std::initializer_list<std::shared_ptr<Filter>> &ilist);
/**
* Filters a value.
*
* @param ireading A new measurement.
* @return The filtered result.
*/
double filter(double ireading) override;
/**
* @return The previous output from filter.
*/
double getOutput() const override;
/**
* Adds a filter to the end of the sequence.
*
* @param ifilter The filter to add.
*/
virtual void addFilter(std::shared_ptr<Filter> ifilter);
protected:
std::vector<std::shared_ptr<Filter>> filters;
double output = 0;
};
} // namespace okapi

Some files were not shown because too many files have changed in this diff Show More