spotpuppy

package module
v0.1.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2022 License: MIT Imports: 8 Imported by: 0

README

spotpuppy-go - The quadruped control module for go

View the documentation here

Caution - This module is still under heavy development and the api is changing a lot!

What does this module do?

  • Makes coding walking algorithms for quadrupedal robots more readable, yet still gives the programmer enough freedom to create complex programs
  • Makes it easy to use algorithms between mechanically different robots - when creating a robot you have to provide an IK controller. This can easily be changed to allow lots of different leg configurations.
    • This concept also extends to motor controller drivers and rotation sensors. Both of these are interface types and can be switched out for either pre-build ones, or custom implementations.
  • Allows you to work with vectors (such as up or forward), so you never have to think 'is positive y axis up or down?' or 'is the z axis forward or left?'
    • This is much more intuitive than xyz coordinates, and much more readable tha directly controlling motor rotations
  • Takes care of saving and loading robot configuration to disk - including custom implementations of motor controllers and leg IK drivers

What robots can run this code?

There are some limitations

  • You have to be able to build golang to the platform (I run all of my robots of raspberry pis)
  • The robot must have four legs, arranged such that there is one at front right, front left, back right, and back left (similar to boston dynamics spot mini, not a spider like quadruped)

Other than these limitations, you can write motor controllers, rotation sensors, and leg ik drivers for basically anything you can think of, and these components will plug into the module with ease.

Examples

There is a repo with some example code using this module to make a robot walk here.

Usage - INPORTANT - this code is outdated and will be updated soon, but for now just look at the example repo

The below code (15 lines!) is all you would need to write to create a robot, then keep its feet at the same points on the floor no matter what rotation the body is at. This particular robot has a 3 servo, one servo in each joint leg design, a pca9685 motor driver, and an arduino running arduinodmp code.

// Create a quadruped with direct motor IKs and a pca9685 motor controller
q := sp.NewQuadruped(spotpuppy.NewDirectMotorIKGenerator(), pca9685.NewPCAMotorController())
// Load its parameters from config file
q.LoadFromFile("config.json")

// Create a rotation sensor over a serrial connection to an arduino
mpu := arduinompu.NewArduinoRotationSensor("/dev/ttyUSB0")

// Create a new coordinate system which will be used to represent the floor
// This is used in code to rotate vectors from robot space to global space
cs := spotpuppy.NewRollPitchCoordinateSystem()

// Create a ups timer. This will allow us to make the robot update at 100 times per second
// This is particularly useful for PID control loops, as they work best at fixed update rates
ups := spotpuppy.NewUPSTimer(100)

// This is our update loop and gets run at 100 times per second
for true {
	// Copy the current rotation of the robot into the coordinate system
	cs.UpdateRollPitchFrom(mpu)
	// Find the vector that is 6cm down in robot space, then rotate it to world space
	// This means that it will always point at the floor, no matter what rotation the body is at
	straightDown := cs.TransformDirection(spotpuppy.DirDown.Mul(6))
	// For each leg (l is a string which can be used to identify legs)
	for _, l := range spotpuppy.AllLegs {
		// Vector from this legs shoulder to the center of the body, in robot space
		shoulderRobotSpace := q.ShoulderVec(l)
		// Vector from the robots center to the shoulder, if the body was flat in world space
		shoulderInvWorldSpace := cs.TransformDirection(q.ShoulderVec(l).Inv())
		// Add them all together to get the foot position, then set that foot
		q.SetLegPosition(l, shoulderRobotSpace.Add(straightDown).Add(shoulderInvWorldSpace))
	}
	// Calculate all motor positions and push them to the motor controller
	q.Update()
	// Wait until its time to do the next update
	ups.WaitForNext()
}

Included types

LegIk
  • DirectMotorIK - This is an IK driver for a leg with three motors, one at each joint, and joints laid out in the same location as Boston Dynamics Spot Mini (knee, hip_x (hip forwards and backwards), hip_z (hip left and right))
MotorController
  • DummyMotorController - This does nothing. It is there as a placeholder for performance testing
  • PCAMotorController - This is a motor controller designed to interface with the pca9685 servo controller. Tested only on rpi4
RotationSensor
  • DummyRotationSensor - This does nothing. It is there as a placeholder for performance testing
  • RawArduinoRotationSensor - This connects to an arduino (or any device for that matter) over a serial connection. It reads raw data from that connection and fuses it into a quaternion. For the arduino sketch, look here

Note: ArduinoRotationSensor is deprecated as I could not find a fatal bug, and the new RawArduinoRotationSensor works just as well.

Custom type implementations

LegIK

A LegIK controller describes a type that takes an input (x,y,z) in space relative to the leg, and returns a number of motor rotations. Some example coordinates:

  • (0,0,0) is the position at the shoulder
  • (0,1,0) is 1cm down from the shoulder
  • (1,0,0) is 1cm forward from the shoulder
  • (0,0,1) is 1cm left from the shoulder
type LegIK interface {
	// This function takes in some coordinates for the foot, and returns a list of motor rotations
	// There can be as many motors as you want, as long as they are all declared in GetMotorNames()
	CalculateMotorRotations(vector *Vector3) []float64
	// This just returns a list of all of the named motors in the leg
	// For example, the direct mortor ik returns ["hip_x","hip_z","knee"]
	// The order of these is the same order that the rotations are returned in CalculateMotorRotations()
	GetMotorNames() []string
	// This returns the position the foor should be at to have all motors centered
	GetRestingPosition() *Vector3
	// Load the json data into this object
	LoadJson(data []byte) error
}
MotorController

A motor controller describes a type that can set the positions of named motors to rotations (from -90 to 90)

Note on motor mappings: A motor mapping is usually a map[string]int, where the key represents a named motor, and the value represents an output channel (eg servo on pin 8)

type MotorController interface {
	// Set a named motor to an angle between -90 to 90
	SetMotor(string, float64)
	// Create the motor mapping using  a list of all possible motor names
	// This should set all of the motors to an invalid channel (eg -1)
	CreateMotorMapping([]string)
	// This function is called after both CreateServoMapping and loading the motor mapping from disk
	// This can be used, for example, to create Servo objects for each mmotor in the mapping
	Setup()
}
RotationSensor

A rotation sensor describes a type which can get the roll and pitch of the robot

type RotationSensor interface {
	// This returns the roll and pitch, in degrees, of the robot
	// 0,0 means the robot is flat. This should be blocking.
	// If concurrency is desired, you can wrap this type in ConcurrentRotationSensor
	GetRollPitch() (float64, float64)
	// This is called to calibrate the rotation sensor
	// It should block until calibration is complete
	Calibrate()
	// Setup should be called after the sensor is loaded
	Setup()
}

Differences to spotpuppy python

You may have noticed that this module shares its name with the spotpuppy python library (github.com/joshpattman/spotpuppy). This module is inspired by that package, but some less efficient or intuitive areas have been redesigned for maximum simplicity and performance. Some of the changes are:

  • Lack of a robot type to extend. You will have to write this type from scratch, however i have found that this actually shortens code and increases readability
  • LegIK interface. You can now write custom IK controllers for the legs which allow much easier integration with other leg designs
  • Simpler saving/loading. There is now one config file containing everything, with much more concise json
  • Faster performance. From some (not very in depth) tests, i think this package runs at least 50-100 times faster than the other code (this is not necessarily all pythons fault, and is partly due to the other package being bloated)
  • More intuitive leg indexing. In this module, all legs are referred to by their name (a string), not with an index. This makes confusion less likely

Documentation

Index

Constants

View Source
const LegBackLeft = "back_left"
View Source
const LegBackRight = "back_right"
View Source
const LegFrontLeft = "front_left"
View Source
const LegFrontRight = "front_right"

Variables

View Source
var (
	// Downwards unit vector. DEPRECATED: USE `Down`
	DirDown = Vec3{0, 1, 0}
	// Upwards unit vector. DEPRECATED: USE `Up`
	DirUp = DirDown.Inv()
	// Forwards unit vector. DEPRECATED: USE `Forward`
	DirForward = Vec3{1, 0, 0}
	// Backwards unit vector. DEPRECATED: USE `Backward`
	DirBackward = DirForward.Inv()
	// Left unit vector. DEPRECATED: USE `Left`
	DirLeft = Vec3{0, 0, 1}
	// Right unit vector. DEPRECATED: USE `Right`
	DirRight = DirLeft.Inv()
)

These are for compatibility. Dont use them

View Source
var (
	// Downwards unit vector
	Down = DirDown
	// Upwards unit vector
	Up = DirUp
	// Left unit vector
	Left = DirLeft
	// Right unit vector
	Right = DirRight
	// Forwards unit vector
	Forward = DirForward
	// Backwards unit vector
	Backward = DirBackward
	// Zero vector
	Zero = Vec3{0, 0, 0}
)

AllLegs is an ordered list of all the legs of a robot, useful for looping

View Source
var QuatIdentity = NewQuat(1, 0, 0, 0)

Functions

func Degrees added in v0.1.0

func Degrees(x float64) float64

Converts radians to degrees

func NewDirectMotorIKGenerator

func NewDirectMotorIKGenerator() func() LegIK

NewDirectMotorIKGenerator creates a function to create empty DirectMotorIK structs. This is used by robot to create a seperate controller for each leg

func Radians added in v0.1.0

func Radians(x float64) float64

Converts degrees to radians

Types

type AxesRemapper added in v0.1.10

type AxesRemapper struct {
	SrcForwardVector Vec3 `json:"src-forward"`
	SrcUpVector      Vec3 `json:"src-up"`
	SrcLeftVector    Vec3 `json:"src-left"`

	TargetForwardVector Vec3 `json:"target-forward"`
	TargetUpVector      Vec3 `json:"target-up"`
	TargetLeftVector    Vec3 `json:"target-left"`
}

AxesRemapper allows remapping of vectors from one axis space to another

func NewAxesRemapper added in v0.1.10

func NewAxesRemapper(SrcForwardVector, SrcUpVector, SrcLeftVector Vec3) *AxesRemapper

Returns an AxesRemapper with source vectors forward, up, and left. These are the vectors that represent the axes in the system we will convert from. By default, the target axes are spotpuppy Forward, Up, Left

func (*AxesRemapper) Remap added in v0.1.10

func (a *AxesRemapper) Remap(v Vec3) Vec3

Remap the vector from coordinate system with Src axes to coordinate system with Target axes, whilst keeping the meaning of the vector

func (*AxesRemapper) RemapInverse added in v0.1.10

func (a *AxesRemapper) RemapInverse(v Vec3) Vec3

Remap the vector from coordinate system with Target axes to coordinate system with Src axes, whilst keeping the meaning of the vector

type DirectMotorIK

type DirectMotorIK struct {
	ReverseKneeJoint bool    `json:"reverse_knee_joint"`
	ReverseHipXJoint bool    `json:"reverse_hip_x_joint"`
	ReverseHipZJoint bool    `json:"reverse_hip_z_joint"`
	FlipXAxis        bool    `json:"flip_x_axis"`
	KneeOffset       float64 `json:"knee_offset"`
	HipXOffset       float64 `json:"hip_x_offset"`
	HipZOffset       float64 `json:"hip_z_offset"`
	// BoneLength is the length from the foot to the knee
	BoneLength float64 `json:"bone_length"`
}

DirectMotorIK is an IK driver for 3 jointed legs (like Spot Mini), with one motor at each joint (no control rods or gears), and where the distance form foot to knee is the same as knee to hip

func (*DirectMotorIK) CalculateMotorRotations

func (dm *DirectMotorIK) CalculateMotorRotations(pos Vec3) []float64

CalculateMotorRotations calculates the rotations of the three motors, and returns them in the order (hip left right, hip forwards backwords, knee)

func (*DirectMotorIK) GetMotorNames

func (dm *DirectMotorIK) GetMotorNames() []string

func (*DirectMotorIK) GetRestingPosition

func (dm *DirectMotorIK) GetRestingPosition() Vec3

GetRestingPosition returns the position where all of the joints are at 0 degrees

func (*DirectMotorIK) LoadJson

func (dm *DirectMotorIK) LoadJson(data []byte) error

Loads json data into this object

type DummyMotorController

type DummyMotorController struct {
	Mapping map[string]int `json:"mapping"`
}

DummyMotorController is a basic MotorController. It does include a dummy servo mapping

func NewDummyMotorController

func NewDummyMotorController() *DummyMotorController

NewDummyMotorController creates a new dummy motor controller

func (*DummyMotorController) CalibrateAllJoints added in v0.0.6

func (d *DummyMotorController) CalibrateAllJoints()

func (*DummyMotorController) CreateMotorMapping

func (d *DummyMotorController) CreateMotorMapping(names []string)

CreateMotorMapping creates a map from string to int for this dummy. It then sets all servos to channel -1

func (*DummyMotorController) SetMotor

func (d *DummyMotorController) SetMotor(s string, f float64)

SetMotor does nothing for dummy motor controller

func (*DummyMotorController) Setup

func (d *DummyMotorController) Setup()

Setup does nothing for DummyMotorController

type DummyRotationSensor

type DummyRotationSensor struct{}

DummyRotationSensor is a rotation sensor that does nothing

func NewDummyRotationSensor

func NewDummyRotationSensor() *DummyRotationSensor

NewDummyRotationSensor creates a new DummyRotationSensor

func (*DummyRotationSensor) Calibrate

func (d *DummyRotationSensor) Calibrate()

Calibrate does nothing for DummyRotationSensor

func (*DummyRotationSensor) GetQuaternion added in v0.1.0

func (d *DummyRotationSensor) GetQuaternion() Quat

GetQuaternion returns identity for DummyRotationSensor

func (*DummyRotationSensor) Setup added in v0.1.7

func (d *DummyRotationSensor) Setup()

Setup does nothing for DummyRotationSensor

type LegIK

type LegIK interface {
	// CalculateMotorRotations gets a list of motor rotations from a foot position relative to this leg.
	// The returned servo positions should be in the same order as GetMotorNames
	// (ie the first value of the rotations should be for the first servo name returned by GetMotorNames)
	CalculateMotorRotations(vector Vec3) []float64
	// GetMotorNames returns a list of the motor names of this leg. See CalculateMotorRotations for more info
	GetMotorNames() []string
	// GetRestingPosition returns the position of the foot of this leg such that the motor rotations are all 0
	GetRestingPosition() Vec3
	// LoadJson loads the json data into this object
	LoadJson(data []byte) error
}

LegIK describes types that can calculate motor rotations from a foot endpoint

type MotorController

type MotorController interface {
	// SetMotor allows setting of a named motor to an angle between -90 to 90
	SetMotor(string, float64)
	// CreateMotorMapping is for initialising any motor mapping that is stored with all possible motor names
	CreateMotorMapping([]string)
	// Setup is called once the motor controller has a motor mapping set up and has been loaded from a file.
	// This could be used, for example, to create a servo object for each item in the mapping
	Setup()
	// CalibrateAllJoints is called to calibrate all joint positions. It can block until complete. It is only useful for brushless motors, not servos.
	CalibrateAllJoints()
}

MotorController is an interface type to allow setting of positions to named motors

type PCAMotorController added in v0.0.4

type PCAMotorController struct {
	ServoOptions *pca9685.ServOptions `json:"servo-options"`
	Mapping      map[string]int       `json:"mapping"`
	// contains filtered or unexported fields
}

func NewPCAMotorController added in v0.0.4

func NewPCAMotorController() *PCAMotorController

func (*PCAMotorController) CalibrateAllJoints added in v0.0.6

func (d *PCAMotorController) CalibrateAllJoints()

func (*PCAMotorController) CreateMotorMapping added in v0.0.4

func (d *PCAMotorController) CreateMotorMapping(names []string)

func (*PCAMotorController) SetMotor added in v0.0.4

func (d *PCAMotorController) SetMotor(s string, a float64)

func (*PCAMotorController) Setup added in v0.0.4

func (d *PCAMotorController) Setup()

type Quadruped

type Quadruped struct {
	Legs            legs            `json:"legs"`
	MotorController MotorController `json:"motor_controller"`
	BodyDimensionX  float64         `json:"body_dimension_x"`
	BodyDimensionZ  float64         `json:"body_dimension_z"`
	// contains filtered or unexported fields
}

Quadruped is a type to collect four LegIK objects, a motor controller, and some robot info together, to allow easy control

func NewQuadruped

func NewQuadruped(newIK func() LegIK, motorController MotorController) *Quadruped

NewQuadruped creates a new quadruped from a function to create empty LegIK objects, and a MotorController. No objects in the robot will be set up correctly, and it is recommended that a file load is performed before anything else

func NewQuadrupedWithExtraMotors

func NewQuadrupedWithExtraMotors(newIK func() LegIK, motorController MotorController, extraMotors []string) *Quadruped

NewQuadrupedWithExtraMotors creates a new quadruped from a function to create empty LegIK objects, and a MotorController. It also adds the specified servo names to the servo map. No objects in the robot will be set up correctly, and it is recommended that a file load is performed before anything else

func (*Quadruped) LoadFromFile

func (q *Quadruped) LoadFromFile(filename string) error

LoadFromFile loads some quadruped data from a file. It is important to make sure the quadruped that created that file had the same LegIK and MotorController types

func (*Quadruped) SaveToFile

func (q *Quadruped) SaveToFile(filename string) error

SaveToFile saves this quadruped to a file

func (*Quadruped) SetExtraMotorNow

func (q *Quadruped) SetExtraMotorNow(motorName string, angle float64)

SetExtraMotorNow sets the named motor to a position, without waiting for the next update loop

func (*Quadruped) SetLegPosition

func (q *Quadruped) SetLegPosition(leg string, pos Vec3)

SetLegPosition sets a legs position for the next update call. It does not perform any calculations or movement immediately.

func (*Quadruped) ShoulderVec

func (q *Quadruped) ShoulderVec(leg string) Vec3

ShoulderVec gets the Vec3 between the robots center and the shoulder joint of the leg specified

func (*Quadruped) Update

func (q *Quadruped) Update()

Update takes the most recent leg positions (set with SetLegPosition), calculates the motor angles with LegIK, and sets the motors with the MotorController

type Quat added in v0.1.0

type Quat struct {
	W float64 // Scalar component
	X float64 // i component
	Y float64 // j component
	Z float64 // k component
}

Quat represents a quaternion W+X*i+Y*j+Z*k

func NewQuat added in v0.1.0

func NewQuat(w, x, y, z float64) Quat

NewQuat returns a new quaternion

func NewQuatAngleAxis added in v0.1.0

func NewQuatAngleAxis(v Vec3, a float64) Quat

NewQuatAngleAxis returns a quaternion with rotation a in degrees around axis v

func NewQuatFromTo added in v0.1.10

func NewQuatFromTo(v1, v2 Vec3) Quat

func (Quat) Apply added in v0.1.0

func (qin Quat) Apply(vec Vec3) Vec3

Apply returns the vector rotated by the quaternion.

func (Quat) Conj added in v0.1.0

func (qin Quat) Conj() Quat

Conj returns the conjugate of a Quat (W,X,Y,Z) -> (W,-X,-Y,-Z)

func (Quat) HeadingAngle added in v0.1.9

func (q Quat) HeadingAngle() float64

Returns the heading angle of this quaternion in degrees. This suffers from gimbal lock

func (Quat) Inv added in v0.1.0

func (qin Quat) Inv() Quat

Inv returns the Quat conjugate rescaled so that Q Q* = 1

func (Quat) Neg added in v0.1.0

func (qin Quat) Neg() Quat

Neg returns the negative

func (Quat) NoYaw added in v0.1.0

func (q Quat) NoYaw() Quat

NoYaw removes the global yaw component of this quaternion. Use this to take a quaternion in global space and make it useful for robot calculations. This suffers from gimbal lock

func (Quat) Norm added in v0.1.0

func (qin Quat) Norm() float64

Norm returns the L1-Norm of a Quat (W,X,Y,Z) -> Sqrt(W*W+X*X+Y*Y+Z*Z)

func (Quat) Norm2 added in v0.1.0

func (qin Quat) Norm2() float64

Norm2 returns the L2-Norm of a Quat (W,X,Y,Z) -> W*W+X*X+Y*Y+Z*Z

func (Quat) Prod added in v0.1.0

func (q Quat) Prod(q2 Quat) Quat

Prod returns the product of q and q2 (q*q2)

func (Quat) RotateByGlobal added in v0.1.0

func (a Quat) RotateByGlobal(b Quat) Quat

RotateByGlobal rotates quaternion a by b along the global axis

func (Quat) RotateByLocal added in v0.1.0

func (a Quat) RotateByLocal(b Quat) Quat

RotateByGlobal rotates quaternion a by b along the local axis relative to a

func (Quat) String added in v0.1.0

func (q Quat) String() string

String converts this quaternion to a string

func (Quat) Unit added in v0.1.0

func (qin Quat) Unit() Quat

Unit returns the Quat rescaled to unit-L1-norm

type RawArduinoRotationSensor added in v0.1.8

type RawArduinoRotationSensor struct {
	Port               *serial.Port  `json:"-"`
	IsReady            bool          `json:"-"`
	PortName           string        `json:"port_name"`
	Axes               *AxesRemapper `json:"axes_remap"`
	ReverseGyroUp      bool          `json:"rev_gyro_up"`
	ReverseGyroLeft    bool          `json:"rev_gyro_left"`
	ReverseGyroForward bool          `json:"rev_gyro_forward"`
	// Maximum number of deg/s the accelerometer can move the rotation
	AccSpeed float64 `json:"acc_speed"`
	// contains filtered or unexported fields
}

func NewRawArduinoRotationSensor added in v0.1.8

func NewRawArduinoRotationSensor() *RawArduinoRotationSensor

Creates a new sensor instance. Does not connect to the arduino yet, that is done from Setup()

func (*RawArduinoRotationSensor) Calibrate added in v0.1.8

func (a *RawArduinoRotationSensor) Calibrate()

Calibrates the sensors accelerometer and gyro. Ensure the sensor is very flat for this

func (*RawArduinoRotationSensor) GetQuaternion added in v0.1.8

func (a *RawArduinoRotationSensor) GetQuaternion() Quat

Returns the last measured rotation of the sensor. Non blocking

func (*RawArduinoRotationSensor) Restart added in v0.1.8

func (a *RawArduinoRotationSensor) Restart()

Restarts the updating in background thread

func (*RawArduinoRotationSensor) Setup added in v0.1.8

func (a *RawArduinoRotationSensor) Setup()

Sets up and connects to the arduino

type RotationSensor

type RotationSensor interface {
	// GetQuaternion returns the quaternion rotation in global space of this sensor.
	// It can also have y axis rotation, which can be cancelled out easily later to get roll and pitch.
	GetQuaternion() Quat
	// Calibrate tells the rotation sensor to calibrate, then waits for the action to complete
	Calibrate()
	// Setup should be called after the sensor is loaded
	Setup()
}

RotationSensor is an interface for getting the roll and pitch from a gyroscope/accelerometer

type UPSTimer

type UPSTimer struct {
	UPS float64
	// contains filtered or unexported fields
}

func NewUPSTimer

func NewUPSTimer(ups float64) *UPSTimer

func (*UPSTimer) WaitForNext

func (u *UPSTimer) WaitForNext()

type Vec3 added in v0.1.0

type Vec3 struct {
	X float64
	Y float64
	Z float64
}

A Vector with 3 dimensions X Y Z

func NewVector3

func NewVector3(x, y, z float64) Vec3

Create a new Vec3 with x y z components

func V3 added in v0.1.10

func V3(x, y, z float64) Vec3

Create a new Vec3 with x y z components. Sugar for NewVector3

func (Vec3) Add added in v0.1.0

func (v Vec3) Add(v2 Vec3) Vec3

Returns the elementwise addition of this vector and the parameter vector

func (Vec3) AngleTo added in v0.1.0

func (v Vec3) AngleTo(v2 Vec3) float64

Returns (in degrees) the angle from this vector and the parameter vector

func (Vec3) Cross added in v0.1.0

func (v Vec3) Cross(v2 Vec3) Vec3

Returns the cross product of this vector and the parameter vector

func (Vec3) Dot added in v0.1.0

func (v Vec3) Dot(v2 Vec3) float64

Returns the dot product of this vector and the parameter vector

func (Vec3) Inv added in v0.1.0

func (v Vec3) Inv() Vec3

Returns the inverse of this vector: v.Mul(-1)

func (Vec3) Len added in v0.1.0

func (v Vec3) Len() float64

Returns the length of this vector

func (Vec3) Mul added in v0.1.0

func (v Vec3) Mul(f float64) Vec3

Returns the vector scaled by a scalar number

func (Vec3) MulVec added in v0.1.0

func (v Vec3) MulVec(v2 Vec3) Vec3

Returns the elementwise multiplication of this vector and the parameter vector

func (Vec3) ProjectToPlane added in v0.1.0

func (v Vec3) ProjectToPlane(normal Vec3) Vec3

Returns this vector projected onto the plane, where the normal of the plane is the parameter vector

func (Vec3) Rotated added in v0.1.0

func (v Vec3) Rotated(q Quat) Vec3

Returns the vector rotated by parameter quaternion

func (Vec3) String added in v0.1.0

func (v Vec3) String() string

Returns this vector as a readable string

func (Vec3) Sub added in v0.1.0

func (v Vec3) Sub(v2 Vec3) Vec3

Returns the elementwise subtraction of this vector and the parameter vector

func (Vec3) Unit added in v0.1.0

func (v Vec3) Unit() Vec3

Return the normalized form of this vector. If the length is 0, it will return Zero

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL