Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSDK-2478: Update encoder driver methods #2161

Merged
merged 11 commits into from
Apr 11, 2023
12 changes: 6 additions & 6 deletions components/board/arduino/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/edaniels/golog"
"github.com/pkg/errors"
pb "go.viam.com/api/component/encoder/v1"
rdkutils "go.viam.com/utils"

"go.viam.com/rdk/components/board"
Expand Down Expand Up @@ -77,7 +76,7 @@ type Encoder struct {
A, B string
name string

positionType pb.PositionType
positionType encoder.PositionType
generic.Unimplemented
}

Expand All @@ -104,13 +103,14 @@ func (cfg *EncoderConfig) Validate(path string) ([]string, error) {
return deps, nil
}

// GetPosition returns number of ticks since last zeroing.
// GetPosition returns the current position in terms of ticks or
// degrees, and whether it is a relative or absolute position.
func (e *Encoder) GetPosition(
ctx context.Context,
positionType *pb.PositionType,
positionType *encoder.PositionType,
extra map[string]interface{},
) (float64, pb.PositionType, error) {
if positionType != nil && *positionType == pb.PositionType_POSITION_TYPE_ANGLE_DEGREES {
) (float64, encoder.PositionType, error) {
if positionType != nil && *positionType == encoder.PositionType_POSITION_TYPE_ANGLE_DEGREES {
err := errors.New("Encoder does not support PositionType Angle Degrees, use a different PositionType")
return 0, *positionType, err
}
Expand Down
12 changes: 7 additions & 5 deletions components/encoder/AMS/ams_as5048.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/edaniels/golog"
"github.com/pkg/errors"
"go.uber.org/zap"
pb "go.viam.com/api/component/encoder/v1"
"go.viam.com/utils"

"go.viam.com/rdk/components/board"
Expand Down Expand Up @@ -132,7 +131,7 @@ type Encoder struct {
positionOffset float64
rotations int
connectionType string
positionType pb.PositionType
positionType encoder.PositionType
i2cBus board.I2C
i2cAddr byte
cancelCtx context.Context
Expand All @@ -155,6 +154,7 @@ func newAS5048Encoder(
cancelCtx: cancelCtx,
cancel: cancel,
logger: logger,
positionType: encoder.PositionType_POSITION_TYPE_TICKS_COUNT,
}
brd, err := board.FromDependencies(deps, attr.BoardName)
if err != nil {
Expand Down Expand Up @@ -254,14 +254,16 @@ func (enc *Encoder) updatePosition(ctx context.Context) error {
// motor to 1. Any other value will result in completely incorrect
// position measurements by the motor.
func (enc *Encoder) GetPosition(
ctx context.Context, positionType *pb.PositionType, extra map[string]interface{},
) (float64, pb.PositionType, error) {
ctx context.Context, positionType *encoder.PositionType, extra map[string]interface{},
) (float64, encoder.PositionType, error) {
enc.mu.RLock()
defer enc.mu.RUnlock()
if positionType != nil && *positionType == pb.PositionType_POSITION_TYPE_ANGLE_DEGREES {
if positionType != nil && *positionType == encoder.PositionType_POSITION_TYPE_ANGLE_DEGREES {
enc.positionType = encoder.PositionType_POSITION_TYPE_ANGLE_DEGREES
return enc.position, enc.positionType, nil
}
ticks := float64(enc.rotations) + enc.position/360.0
enc.positionType = encoder.PositionType_POSITION_TYPE_TICKS_COUNT
return ticks, enc.positionType, nil
}

Expand Down
17 changes: 10 additions & 7 deletions components/encoder/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,25 @@ func NewClientFromConn(ctx context.Context, conn rpc.ClientConn, name string, lo
}
}

// GetPosition returns number of ticks since last zeroing.
// GetPosition returns the current position in terms of ticks or
// degrees, and whether it is a relative or absolute position.
func (c *client) GetPosition(
ctx context.Context,
positionType *pb.PositionType,
positionType *PositionType,
extra map[string]interface{},
) (float64, pb.PositionType, error) {
) (float64, PositionType, error) {
ext, err := structpb.NewStruct(extra)
if err != nil {
return 0, pb.PositionType_POSITION_TYPE_UNSPECIFIED, err
return 0, PositionType_POSITION_TYPE_UNSPECIFIED, err
}
req := &pb.GetPositionRequest{Name: c.name, PositionType: positionType, Extra: ext}
posType, err := EncoderToProtoPositionType(positionType)
req := &pb.GetPositionRequest{Name: c.name, PositionType: &posType, Extra: ext}
resp, err := c.client.GetPosition(ctx, req)
if err != nil {
return 0, pb.PositionType_POSITION_TYPE_UNSPECIFIED, err
return 0, PositionType_POSITION_TYPE_UNSPECIFIED, err
}
return float64(resp.Value), resp.PositionType, nil
posType1, err := ProtoToEncoderPositionType(&resp.PositionType)
return float64(resp.Value), posType1, nil
}

// ResetPosition sets the current position of
Expand Down
16 changes: 8 additions & 8 deletions components/encoder/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ func TestClient(t *testing.T) {
}
workingEncoder.GetPositionFunc = func(
ctx context.Context,
positionType *pb.PositionType,
positionType *encoder.PositionType,
extra map[string]interface{},
) (float64, pb.PositionType, error) {
) (float64, encoder.PositionType, error) {
actualExtra = extra
return 42.0, pb.PositionType_POSITION_TYPE_UNSPECIFIED, nil
return 42.0, encoder.PositionType_POSITION_TYPE_UNSPECIFIED, nil
}
workingEncoder.GetPropertiesFunc = func(ctx context.Context, extra map[string]interface{}) (map[encoder.Feature]bool, error) {
actualExtra = extra
Expand All @@ -60,10 +60,10 @@ func TestClient(t *testing.T) {
}
failingEncoder.GetPositionFunc = func(
ctx context.Context,
positionType *pb.PositionType,
positionType *encoder.PositionType,
extra map[string]interface{},
) (float64, pb.PositionType, error) {
return 0, pb.PositionType_POSITION_TYPE_UNSPECIFIED, errors.New("position unavailable")
) (float64, encoder.PositionType, error) {
return 0, encoder.PositionType_POSITION_TYPE_UNSPECIFIED, errors.New("position unavailable")
}
failingEncoder.GetPropertiesFunc = func(ctx context.Context, extra map[string]interface{}) (map[encoder.Feature]bool, error) {
return nil, errors.New("get properties failed")
Expand Down Expand Up @@ -129,7 +129,7 @@ func TestClient(t *testing.T) {
err = failingEncoderClient.ResetPosition(context.Background(), nil)
test.That(t, err, test.ShouldNotBeNil)

pos, _, err := failingEncoderClient.GetPosition(context.Background(), pb.PositionType_POSITION_TYPE_UNSPECIFIED.Enum(), nil)
pos, _, err := failingEncoderClient.GetPosition(context.Background(), encoder.PositionType_POSITION_TYPE_UNSPECIFIED.Enum(), nil)
test.That(t, err, test.ShouldNotBeNil)
test.That(t, pos, test.ShouldEqual, 0.0)

Expand All @@ -141,7 +141,7 @@ func TestClient(t *testing.T) {
test.That(t, err, test.ShouldBeNil)
workingEncoderDialedClient := encoder.NewClientFromConn(context.Background(), conn, testEncoderName, logger)

pos, _, err := workingEncoderDialedClient.GetPosition(context.Background(), pb.PositionType_POSITION_TYPE_UNSPECIFIED.Enum(), nil)
pos, _, err := workingEncoderDialedClient.GetPosition(context.Background(), encoder.PositionType_POSITION_TYPE_UNSPECIFIED.Enum(), nil)
test.That(t, err, test.ShouldBeNil)
test.That(t, pos, test.ShouldEqual, 42.0)

Expand Down
59 changes: 55 additions & 4 deletions components/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,31 @@ var Subtype = resource.NewSubtype(
SubtypeName,
)

// PositionType is an enum representing the encoders position type.
type PositionType int32

// PositionReporting represesnts the feature of a motor being
// able to report its own position.
const (
PositionType_POSITION_TYPE_UNSPECIFIED PositionType = 0
// Return type for relative encoders that report
// how far they've gone from a start position
PositionType_POSITION_TYPE_TICKS_COUNT PositionType = 1
// Return type for absolute encoders that report
// their position in degrees along the radial axis
PositionType_POSITION_TYPE_ANGLE_DEGREES PositionType = 2
)

func (x PositionType) Enum() *PositionType {
p := new(PositionType)
*p = x
return p
}

// A Encoder turns a position into a signal.
type Encoder interface {
// GetPosition returns number of ticks since last zeroing
GetPosition(ctx context.Context, positionType *pb.PositionType, extra map[string]interface{}) (float64, pb.PositionType, error)
// GetPosition returns the current position in terms of ticks or degrees, and whether it is a relative or absolute position.
GetPosition(ctx context.Context, positionType *PositionType, extra map[string]interface{}) (float64, PositionType, error)

// ResetPosition sets the current position of the motor to be its new zero position.
ResetPosition(ctx context.Context, extra map[string]interface{}) error
Expand Down Expand Up @@ -121,9 +142,9 @@ func (r *reconfigurableEncoder) DoCommand(ctx context.Context, cmd map[string]in

func (r *reconfigurableEncoder) GetPosition(
ctx context.Context,
positionType *pb.PositionType,
positionType *PositionType,
extra map[string]interface{},
) (float64, pb.PositionType, error) {
) (float64, PositionType, error) {
r.mu.RLock()
defer r.mu.RUnlock()
return r.actual.GetPosition(ctx, positionType, extra)
Expand Down Expand Up @@ -177,3 +198,33 @@ func WrapWithReconfigurable(r interface{}, name resource.Name) (resource.Reconfi
}
return &reconfigurableEncoder{name: name, actual: m}, nil
}

// ProtoToEncoderPositionType takes a GetPositionResponse and returns
// an equivalent PositionType-to-int map.
func ProtoToEncoderPositionType(positionType *pb.PositionType) (PositionType, error) {
if positionType == nil {
return PositionType_POSITION_TYPE_UNSPECIFIED, nil
}
if *positionType == pb.PositionType_POSITION_TYPE_ANGLE_DEGREES {
return PositionType_POSITION_TYPE_ANGLE_DEGREES, nil
}
if *positionType == pb.PositionType_POSITION_TYPE_TICKS_COUNT {
return PositionType_POSITION_TYPE_TICKS_COUNT, nil
}
return PositionType_POSITION_TYPE_UNSPECIFIED, nil
}

// EncoderToProtoPositionType takes a map of PositionType-to-int (indicating
// the PositionType) and converts it to a GetPositionResponse.
func EncoderToProtoPositionType(positionType *PositionType) (pb.PositionType, error) {
if positionType == nil {
return pb.PositionType_POSITION_TYPE_UNSPECIFIED, nil
}
if *positionType == PositionType_POSITION_TYPE_ANGLE_DEGREES {
return pb.PositionType_POSITION_TYPE_ANGLE_DEGREES, nil
}
if *positionType == PositionType_POSITION_TYPE_TICKS_COUNT {
return pb.PositionType_POSITION_TYPE_TICKS_COUNT, nil
}
return pb.PositionType_POSITION_TYPE_UNSPECIFIED, nil
}
11 changes: 5 additions & 6 deletions components/encoder/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"testing"

pb "go.viam.com/api/component/encoder/v1"
"go.viam.com/test"
"go.viam.com/utils"

Expand Down Expand Up @@ -189,7 +188,7 @@ func TestReconfigurableEncoder(t *testing.T) {

test.That(t, actualEncoder1.posCount, test.ShouldEqual, 0)
test.That(t, actualEncoder2.posCount, test.ShouldEqual, 0)
result, _, err := reconfEncoder1.(encoder.Encoder).GetPosition(context.Background(), pb.PositionType_POSITION_TYPE_UNSPECIFIED.Enum(), nil)
result, _, err := reconfEncoder1.(encoder.Encoder).GetPosition(context.Background(), encoder.PositionType_POSITION_TYPE_UNSPECIFIED.Enum(), nil)
test.That(t, err, test.ShouldBeNil)
test.That(t, result, test.ShouldResemble, position)
test.That(t, actualEncoder1.posCount, test.ShouldEqual, 0)
Expand Down Expand Up @@ -226,7 +225,7 @@ func TestGetPosition(t *testing.T) {
test.That(t, err, test.ShouldBeNil)
test.That(t, pos1, test.ShouldResemble, position)
test.That(t, actualEncoder1.posCount, test.ShouldEqual, 1)
test.That(t, positionType, test.ShouldEqual, pb.PositionType_POSITION_TYPE_UNSPECIFIED)
test.That(t, positionType, test.ShouldEqual, encoder.PositionType_POSITION_TYPE_UNSPECIFIED)

props, err := reconfEncoder1.(encoder.Encoder).GetProperties(context.Background(), nil)
test.That(t, err, test.ShouldBeNil)
Expand Down Expand Up @@ -269,12 +268,12 @@ func (m *mock) ResetPosition(ctx context.Context, extra map[string]interface{})

func (m *mock) GetPosition(
ctx context.Context,
positionType *pb.PositionType,
positionType *encoder.PositionType,
extra map[string]interface{},
) (float64, pb.PositionType, error) {
) (float64, encoder.PositionType, error) {
m.posCount++
m.extra = extra
return position, pb.PositionType_POSITION_TYPE_UNSPECIFIED, nil
return position, encoder.PositionType_POSITION_TYPE_UNSPECIFIED, nil
}

func (m *mock) GetProperties(ctx context.Context, extra map[string]interface{}) (map[encoder.Feature]bool, error) {
Expand Down
35 changes: 23 additions & 12 deletions components/encoder/fake/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"time"

"github.com/edaniels/golog"
pb "go.viam.com/api/component/encoder/v1"
"go.viam.com/utils"

"go.viam.com/rdk/components/encoder"
Expand All @@ -28,11 +27,7 @@ func init() {
cfg config.Component,
logger golog.Logger,
) (interface{}, error) {
e := &Encoder{}
e.updateRate = cfg.ConvertedAttributes.(*AttrConfig).UpdateRate

e.Start(ctx)
return e, nil
return NewFakeEncoder(ctx, cfg)
},
}
registry.RegisterComponent(encoder.Subtype, fakeModel, _encoder)
Expand All @@ -46,6 +41,21 @@ func init() {
}, &AttrConfig{})
}

// NewFakeEncoder creates a new Encoder.
func NewFakeEncoder(
ctx context.Context,
cfg config.Component,
) (encoder.Encoder, error) {
e := &Encoder{
position: 0,
positionType: encoder.PositionType_POSITION_TYPE_TICKS_COUNT,
}
e.updateRate = cfg.ConvertedAttributes.(*AttrConfig).UpdateRate

e.Start(ctx)
return e, nil
}

// AttrConfig describes the configuration of a fake encoder.
type AttrConfig struct {
UpdateRate int64 `json:"update_rate_msec,omitempty"`
Expand All @@ -60,21 +70,22 @@ func (cfg *AttrConfig) Validate(path string) error {
type Encoder struct {
mu sync.Mutex
position int64
positionType pb.PositionType
positionType encoder.PositionType
speed float64 // ticks per minute
updateRate int64 // update position in start every updateRate ms
activeBackgroundWorkers sync.WaitGroup

generic.Unimplemented
}

// GetPosition returns the current position in terms of ticks.
// GetPosition returns the current position in terms of ticks or
// degrees, and whether it is a relative or absolute position.
func (e *Encoder) GetPosition(
ctx context.Context,
positionType *pb.PositionType,
positionType *encoder.PositionType,
extra map[string]interface{},
) (float64, pb.PositionType, error) {
if positionType != nil && *positionType == pb.PositionType_POSITION_TYPE_ANGLE_DEGREES {
) (float64, encoder.PositionType, error) {
if positionType != nil && *positionType == encoder.PositionType_POSITION_TYPE_ANGLE_DEGREES {
err := errors.New("Encoder does not support PositionType Angle Degrees, use a different PositionType")
return 0, *positionType, err
}
Expand Down Expand Up @@ -123,7 +134,7 @@ func (e *Encoder) ResetPosition(ctx context.Context, extra map[string]interface{
// GetProperties returns a list of all the position types that are supported by a given encoder.
func (e *Encoder) GetProperties(ctx context.Context, extra map[string]interface{}) (map[encoder.Feature]bool, error) {
return map[encoder.Feature]bool{
encoder.TicksCountSupported: false,
encoder.TicksCountSupported: true,
encoder.AngleDegreesSupported: false,
}, nil
}
Expand Down
Loading