Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions docs/docs/common-issues/kotlin-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
sidebar_position: 5
---

# Kotlin Support

Although advantagekit supports kotlin out of the box, there are a couple of features that do not work within kotlin files.

## @AutoLogOutput

Kotlin singletons(or objects) must be registered through a ```AutoLogOutput.addObject(this)``` call within the constructor. For instance:
```
object SomeSingleton {
init {
AutoLogOutput.addObject(this)
}

@AutoLogOutput
fun getValue() = 2.0
}
```

## @AutoLog

If your team plans to use @AutoLog, it is recommended to paste the code below into a kotlin file named "AdvantageKitExtensions.kt"
(preferrably located within a "lib" or "util" folder of your robot code):

```kt
package your.lib.folder

import edu.wpi.first.units.Measure
import edu.wpi.first.units.MutableMeasure
import edu.wpi.first.util.struct.Struct
import edu.wpi.first.util.struct.StructSerializable
import org.littletonrobotics.junction.AutoLogOutputManager
import org.littletonrobotics.junction.LogTable
import org.littletonrobotics.junction.inputs.LoggableInputs
import kotlin.reflect.KProperty
import edu.wpi.first.units.Unit as WPIUnit

abstract class AutoLogInputs: LoggableInputs {
fun log(value: Double, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: Int, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: String, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: Boolean, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: Long, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun <T: StructSerializable> log(value: T, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun <T> log(value: T, struct: Struct<T>, key: String? = null) =
LoggedInput(value, key, {k,v -> put(k, struct, v)}, {k,v -> get(k, struct, v)})
fun <U: WPIUnit> log(value: Measure<U>, key: String? = null) =
LoggedInput(value, key, LogTable::put, LogTable::get)
fun <U: WPIUnit, Base: Measure<U>, M: MutableMeasure<U, Base, M>> log(value: M, key: String? = null) =
LoggedInput(value, key, LogTable::put, LogTable::get)

fun log(value: DoubleArray, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: IntArray, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: Array<String>, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: BooleanArray, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun log(value: LongArray, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)
fun <T: StructSerializable> log(value: Array<T>, key: String? = null) = LoggedInput(value, key, LogTable::put, LogTable::get)

private val toLogRunners = mutableListOf<(LogTable) -> Unit>()
private val fromLogRunners = mutableListOf<(LogTable) -> Unit>()

inner class LoggedInput<T>(
private var value: T,
private val name: String? = null,
private val toLog: LogTable.(String, T) -> Unit,
private val fromLog: LogTable.(String, T) -> T,
) {
operator fun getValue(thisRef: Any, property: KProperty<*>) = value
operator fun setValue(thisRef: Any, property: KProperty<*>, value: T) { this.value = value }

operator fun provideDelegate(thisRef: Any, property: KProperty<*>): LoggedInput<T> {
val namespace = this.name ?: property.name
toLogRunners.add { logTable -> this.toLog(logTable, namespace, value) }
fromLogRunners.add { logTable -> value = this.fromLog(logTable, namespace, value) }
return this
}
}

override fun fromLog(table: LogTable) {
fromLogRunners.forEach { it(table) }
}

override fun toLog(table: LogTable) {
toLogRunners.forEach { it(table) }
}
}
```

This base class gives a replacement for the @AutoLog annotation for kotlin.

Here is an example of using auto-logged inputs in kotlin:
```kt
class ArmInputs: AutoLogInputs() {
var angle by log(Rotation2d())
var voltage by log(Volts.mutable(0.0), "ArmVoltage")
var statorCurrent by log(Amps.mutable(2.0))
}

interface ArmIO {
fun updateInputs(inputs: ArmInputs) {}
fun setVoltage(volts: Voltage) {}
}

class Arm: SubsystemBase() {
private val inputs = ArmInputs()
private val io: ArmIO = ArmIOImpl()

override fun periodic() {
io.updateInputs(inputs)
Logger.processInputs("Arm", inputs)
}
}
```


4 changes: 3 additions & 1 deletion docs/docs/legal/privacy-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar_position: 2

AdvantageKit is a volunteer-run project that is owned and published by the Littleton STEM Educational Foundation ("Littleton Robotics"), a non-profit organization based in the United States.

_This policy was last modified on October 9th, 2024._
_This policy was last modified on November 1st, 2024._

## Information We Collect

Expand All @@ -16,6 +16,8 @@ Littleton Robotics does not collect data from users of the AdvantageKit library

The AdvantageKit code repository, Maven repository, and documentation site are hosted by GitHub, which publishes a [privacy policy](https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement) that applies when interacting with these services.

The search feature of the AdvantageKit documentation uses Algolia, which publishes a [privacy policy](https://www.algolia.com/policies/privacy/) that applies when interacting with this service.

## Contact

Questions about this policy can be directed to software@team6328.org.
12 changes: 6 additions & 6 deletions docs/docs/recording-inputs/io-interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ All of the IO methods include a default implementation which is used during simu
public RobotContainer() {
if (isReal()) {
// Instantiate IO implementations to talk to real hardware
driveTrain = new DriveTrain(DriveTrainIOReal());
elevator = new Elevator(ElevatorIOReal());
intake = new Intake(IntakeIOReal());
driveTrain = new DriveTrain(new DriveTrainIOReal());
elevator = new Elevator(new ElevatorIOReal());
intake = new Intake(new IntakeIOReal());
} else {
// Use anonymous classes to create "dummy" IO implementations
driveTrain = new DriveTrain(DriveTrainIO() {});
elevator = new Elevator(ElevatorIO() {});
intake = new Intake(IntakeIO() {});
driveTrain = new DriveTrain(new DriveTrainIO() {});
elevator = new Elevator(new ElevatorIO() {});
intake = new Intake(new IntakeIO() {});
}
}
```
Expand Down
5 changes: 5 additions & 0 deletions docs/docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ const config: Config = {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
additionalLanguages: ["java"]
},
algolia: {
appId: "7JW2R5AY94",
apiKey: "34dce56eab484e7f5d69f9a71f44f3eb",
indexName: "advantagekit"
}
} satisfies Preset.ThemeConfig
};
Expand Down