// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. package edu.wpi.first.math; import edu.wpi.first.util.RuntimeLoader; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; /** WPIMath JNI. */ public final class WPIMathJNI { static boolean libraryLoaded = false; static { if (Helper.getExtractOnStaticLoad()) { try { RuntimeLoader.loadLibrary("wpimathjni"); } catch (Exception ex) { ex.printStackTrace(); System.exit(1); } libraryLoaded = true; } } /** * Force load the library. * * @throws IOException If the library could not be loaded or found. */ public static synchronized void forceLoad() throws IOException { if (libraryLoaded) { return; } RuntimeLoader.loadLibrary("wpimathjni"); libraryLoaded = true; } // ArmFeedforward wrappers /** * Obtain a feedforward voltage from a single jointed arm feedforward object. * *

Constructs an ArmFeedforward object and runs its currentVelocity and nextVelocity overload * * @param ks The ArmFeedforward's static gain in volts. * @param kv The ArmFeedforward's velocity gain in volt seconds per radian. * @param ka The ArmFeedforward's acceleration gain in volt seconds² per radian. * @param kg The ArmFeedforward's gravity gain in volts. * @param currentAngle The current angle in the calculation in radians. * @param currentVelocity The current velocity in the calculation in radians per second. * @param nextVelocity The next velocity in the calculation in radians per second. * @param dt The time between velocity setpoints in seconds. * @return The calculated feedforward in volts. */ public static native double calculate( double ks, double kv, double ka, double kg, double currentAngle, double currentVelocity, double nextVelocity, double dt); // DARE wrappers /** * Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation. * *

AᵀXA − X − AᵀXB(BᵀXB + R)⁻¹BᵀXA + Q = 0 * *

This internal function skips expensive precondition checks for increased performance. The * solver may hang if any of the following occur: * *

* *

Only use this function if you're sure the preconditions are met. Solves the discrete * alegebraic Riccati equation. * * @param A Array containing elements of A in row-major order. * @param B Array containing elements of B in row-major order. * @param Q Array containing elements of Q in row-major order. * @param R Array containing elements of R in row-major order. * @param states Number of states in A matrix. * @param inputs Number of inputs in B matrix. * @param S Array storage for DARE solution. */ public static native void dareDetailABQR( double[] A, double[] B, double[] Q, double[] R, int states, int inputs, double[] S); /** * Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation. * *

AᵀXA − X − (AᵀXB + N)(BᵀXB + R)⁻¹(BᵀXA + Nᵀ) + Q = 0 * *

This overload of the DARE is useful for finding the control law uₖ that minimizes the * following cost function subject to xₖ₊₁ = Axₖ + Buₖ. * *

   *     ∞ [xₖ]ᵀ[Q  N][xₖ]
   * J = Σ [uₖ] [Nᵀ R][uₖ] ΔT
   *    k=0
   * 
* *

This is a more general form of the following. The linear-quadratic regulator is the feedback * control law uₖ that minimizes the following cost function subject to xₖ₊₁ = Axₖ + Buₖ: * *

   *     ∞
   * J = Σ (xₖᵀQxₖ + uₖᵀRuₖ) ΔT
   *    k=0
   * 
* *

This can be refactored as: * *

   *     ∞ [xₖ]ᵀ[Q 0][xₖ]
   * J = Σ [uₖ] [0 R][uₖ] ΔT
   *    k=0
   * 
* *

This internal function skips expensive precondition checks for increased performance. The * solver may hang if any of the following occur: * *

* *

Only use this function if you're sure the preconditions are met. * * @param A Array containing elements of A in row-major order. * @param B Array containing elements of B in row-major order. * @param Q Array containing elements of Q in row-major order. * @param R Array containing elements of R in row-major order. * @param N Array containing elements of N in row-major order. * @param states Number of states in A matrix. * @param inputs Number of inputs in B matrix. * @param S Array storage for DARE solution. */ public static native void dareDetailABQRN( double[] A, double[] B, double[] Q, double[] R, double[] N, int states, int inputs, double[] S); /** * Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation. * *

AᵀXA − X − AᵀXB(BᵀXB + R)⁻¹BᵀXA + Q = 0 * * @param A Array containing elements of A in row-major order. * @param B Array containing elements of B in row-major order. * @param Q Array containing elements of Q in row-major order. * @param R Array containing elements of R in row-major order. * @param states Number of states in A matrix. * @param inputs Number of inputs in B matrix. * @param S Array storage for DARE solution. * @throws IllegalArgumentException if Q isn't symmetric positive semidefinite. * @throws IllegalArgumentException if R isn't symmetric positive definite. * @throws IllegalArgumentException if the (A, B) pair isn't stabilizable. * @throws IllegalArgumentException if the (A, C) pair where Q = CᵀC isn't detectable. */ public static native void dareABQR( double[] A, double[] B, double[] Q, double[] R, int states, int inputs, double[] S); /** * Computes the unique stabilizing solution X to the discrete-time algebraic Riccati equation. * *

AᵀXA − X − (AᵀXB + N)(BᵀXB + R)⁻¹(BᵀXA + Nᵀ) + Q = 0 * *

This overload of the DARE is useful for finding the control law uₖ that minimizes the * following cost function subject to xₖ₊₁ = Axₖ + Buₖ. * *

   *     ∞ [xₖ]ᵀ[Q  N][xₖ]
   * J = Σ [uₖ] [Nᵀ R][uₖ] ΔT
   *    k=0
   * 
* *

This is a more general form of the following. The linear-quadratic regulator is the feedback * control law uₖ that minimizes the following cost function subject to xₖ₊₁ = Axₖ + Buₖ: * *

   *     ∞
   * J = Σ (xₖᵀQxₖ + uₖᵀRuₖ) ΔT
   *    k=0
   * 
* *

This can be refactored as: * *

   *     ∞ [xₖ]ᵀ[Q 0][xₖ]
   * J = Σ [uₖ] [0 R][uₖ] ΔT
   *    k=0
   * 
* * @param A Array containing elements of A in row-major order. * @param B Array containing elements of B in row-major order. * @param Q Array containing elements of Q in row-major order. * @param R Array containing elements of R in row-major order. * @param N Array containing elements of N in row-major order. * @param states Number of states in A matrix. * @param inputs Number of inputs in B matrix. * @param S Array storage for DARE solution. * @throws IllegalArgumentException if Q − NR⁻¹Nᵀ isn't symmetric positive semidefinite. * @throws IllegalArgumentException if R isn't symmetric positive definite. * @throws IllegalArgumentException if the (A − BR⁻¹Nᵀ, B) pair isn't stabilizable. * @throws IllegalArgumentException if the (A, C) pair where Q = CᵀC isn't detectable. */ public static native void dareABQRN( double[] A, double[] B, double[] Q, double[] R, double[] N, int states, int inputs, double[] S); // Eigen wrappers /** * Computes the matrix exp. * * @param src Array of elements of the matrix to be exponentiated. * @param rows How many rows there are. * @param dst Array where the result will be stored. */ public static native void exp(double[] src, int rows, double[] dst); /** * Computes the matrix pow. * * @param src Array of elements of the matrix to be raised to a power. * @param rows How many rows there are. * @param exponent The exponent. * @param dst Array where the result will be stored. */ public static native void pow(double[] src, int rows, double exponent, double[] dst); /** * Performs an inplace rank one update (or downdate) of an upper triangular Cholesky decomposition * matrix. * * @param mat Array of elements of the matrix to be updated. * @param lowerTriangular Whether mat is lower triangular. * @param rows How many rows there are. * @param vec Vector to use for the rank update. * @param sigma Sigma value to use for the rank update. */ public static native void rankUpdate( double[] mat, int rows, double[] vec, double sigma, boolean lowerTriangular); /** * Solves the least-squares problem Ax=B using a QR decomposition with full pivoting. * * @param A Array of elements of the A matrix. * @param Arows Number of rows of the A matrix. * @param Acols Number of rows of the A matrix. * @param B Array of elements of the B matrix. * @param Brows Number of rows of the B matrix. * @param Bcols Number of rows of the B matrix. * @param dst Array to store solution in. If A is m-n and B is m-p, dst is n-p. */ public static native void solveFullPivHouseholderQr( double[] A, int Arows, int Acols, double[] B, int Brows, int Bcols, double[] dst); // Ellipse2d wrappers /** * Returns the nearest point that is contained within the ellipse. * *

Constructs an Ellipse2d object and runs its FindNearestPoint() method. * * @param centerX The x coordinate of the center of the ellipse in meters. * @param centerY The y coordinate of the center of the ellipse in meters. * @param centerHeading The ellipse's rotation in radians. * @param xSemiAxis The x semi-axis in meters. * @param ySemiAxis The y semi-axis in meters. * @param pointX The x coordinate of the point that this will find the nearest point to. * @param pointY The y coordinate of the point that this will find the nearest point to. * @param nearestPoint Array to store nearest point into. */ public static native void ellipse2dFindNearestPoint( double centerX, double centerY, double centerHeading, double xSemiAxis, double ySemiAxis, double pointX, double pointY, double[] nearestPoint); // Pose3d wrappers /** * Obtain a Pose3d from a (constant curvature) velocity. * *

The double array returned is of the form [dx, dy, dz, qx, qy, qz]. * * @param poseX The pose's translational X component. * @param poseY The pose's translational Y component. * @param poseZ The pose's translational Z component. * @param poseQw The pose quaternion's W component. * @param poseQx The pose quaternion's X component. * @param poseQy The pose quaternion's Y component. * @param poseQz The pose quaternion's Z component. * @param twistDx The twist's dx value. * @param twistDy The twist's dy value. * @param twistDz The twist's dz value. * @param twistRx The twist's rx value. * @param twistRy The twist's ry value. * @param twistRz The twist's rz value. * @return The new pose as a double array. */ public static native double[] expPose3d( double poseX, double poseY, double poseZ, double poseQw, double poseQx, double poseQy, double poseQz, double twistDx, double twistDy, double twistDz, double twistRx, double twistRy, double twistRz); /** * Returns a Twist3d that maps the starting pose to the end pose. * *

The double array returned is of the form [dx, dy, dz, rx, ry, rz]. * * @param startX The starting pose's translational X component. * @param startY The starting pose's translational Y component. * @param startZ The starting pose's translational Z component. * @param startQw The starting pose quaternion's W component. * @param startQx The starting pose quaternion's X component. * @param startQy The starting pose quaternion's Y component. * @param startQz The starting pose quaternion's Z component. * @param endX The ending pose's translational X component. * @param endY The ending pose's translational Y component. * @param endZ The ending pose's translational Z component. * @param endQw The ending pose quaternion's W component. * @param endQx The ending pose quaternion's X component. * @param endQy The ending pose quaternion's Y component. * @param endQz The ending pose quaternion's Z component. * @return The twist that maps start to end as a double array. */ public static native double[] logPose3d( double startX, double startY, double startZ, double startQw, double startQx, double startQy, double startQz, double endX, double endY, double endZ, double endQw, double endQx, double endQy, double endQz); // StateSpaceUtil wrappers /** * Returns true if (A, B) is a stabilizable pair. * *

(A, B) is stabilizable if and only if the uncontrollable eigenvalues of A, if any, have * absolute values less than one, where an eigenvalue is uncontrollable if rank(lambda * I - A, B) * < n where n is the number of states. * * @param states the number of states of the system. * @param inputs the number of inputs to the system. * @param A System matrix. * @param B Input matrix. * @return If the system is stabilizable. */ public static native boolean isStabilizable(int states, int inputs, double[] A, double[] B); // Trajectory wrappers /** * Loads a Pathweaver JSON. * * @param path The path to the JSON. * @return A double array with the trajectory states from the JSON. * @throws IOException if the JSON could not be read. */ public static native double[] fromPathweaverJson(String path) throws IOException; /** * Converts a trajectory into a Pathweaver JSON and saves it. * * @param elements The elements of the trajectory. * @param path The location to save the JSON to. * @throws IOException if the JSON could not be written. */ public static native void toPathweaverJson(double[] elements, String path) throws IOException; /** * Deserializes a trajectory JSON into a double[] of trajectory elements. * * @param json The JSON containing the serialized trajectory. * @return A double array with the trajectory states. */ public static native double[] deserializeTrajectory(String json); /** * Serializes the trajectory into a JSON string. * * @param elements The elements of the trajectory. * @return A JSON containing the serialized trajectory. */ public static native String serializeTrajectory(double[] elements); /** Sets whether JNI should be loaded in the static block. */ public static class Helper { private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); /** * Returns true if the JNI should be loaded in the static block. * * @return True if the JNI should be loaded in the static block. */ public static boolean getExtractOnStaticLoad() { return extractOnStaticLoad.get(); } /** * Sets whether the JNI should be loaded in the static block. * * @param load Whether the JNI should be loaded in the static block. */ public static void setExtractOnStaticLoad(boolean load) { extractOnStaticLoad.set(load); } /** Utility class. */ private Helper() {} } /** Utility class. */ private WPIMathJNI() {} }