-
Notifications
You must be signed in to change notification settings - Fork 110
/
slam.go
146 lines (127 loc) · 3.97 KB
/
slam.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Package slam implements simultaneous localization and mapping
// This is an Experimental package
package slam
import (
"context"
"image"
"sync"
"github.com/edaniels/golog"
pb "go.viam.com/api/service/slam/v1"
goutils "go.viam.com/utils"
"go.viam.com/utils/rpc"
"go.viam.com/rdk/referenceframe"
"go.viam.com/rdk/registry"
"go.viam.com/rdk/resource"
"go.viam.com/rdk/subtype"
"go.viam.com/rdk/utils"
"go.viam.com/rdk/vision"
)
// TBD 05/04/2022: Needs more work once GRPC is included (future PR).
func init() {
registry.RegisterResourceSubtype(Subtype, registry.ResourceSubtype{
RegisterRPCService: func(ctx context.Context, rpcServer rpc.Server, subtypeSvc subtype.Service) error {
return rpcServer.RegisterServiceServer(
ctx,
&pb.SLAMService_ServiceDesc,
NewServer(subtypeSvc),
pb.RegisterSLAMServiceHandlerFromEndpoint,
)
},
RPCServiceDesc: &pb.SLAMService_ServiceDesc,
RPCClient: func(ctx context.Context, conn rpc.ClientConn, name string, logger golog.Logger) interface{} {
return NewClientFromConn(ctx, conn, name, logger)
},
Reconfigurable: WrapWithReconfigurable,
})
}
// NewUnimplementedInterfaceError is used when there is a failed interface check.
func NewUnimplementedInterfaceError(actual interface{}) error {
return utils.NewUnimplementedInterfaceError((Service)(nil), actual)
}
// SubtypeName is the name of the type of service.
const SubtypeName = resource.SubtypeName("slam")
// Subtype is a constant that identifies the slam resource subtype.
var Subtype = resource.NewSubtype(
resource.ResourceNamespaceRDK,
resource.ResourceTypeService,
SubtypeName,
)
// Named is a helper for getting the named service's typed resource name.
func Named(name string) resource.Name {
return resource.NameFromSubtype(Subtype, name)
}
var (
_ = Service(&reconfigurableSlam{})
_ = resource.Reconfigurable(&reconfigurableSlam{})
_ = goutils.ContextCloser(&reconfigurableSlam{})
)
// Service describes the functions that are available to the service.
type Service interface {
Position(context.Context, string, map[string]interface{}) (*referenceframe.PoseInFrame, error)
GetMap(
context.Context,
string,
string,
*referenceframe.PoseInFrame,
bool,
map[string]interface{},
) (string, image.Image, *vision.Object, error)
}
type reconfigurableSlam struct {
mu sync.RWMutex
name resource.Name
actual Service
}
func (svc *reconfigurableSlam) Name() resource.Name {
return svc.name
}
func (svc *reconfigurableSlam) Position(
ctx context.Context,
val string,
extra map[string]interface{},
) (*referenceframe.PoseInFrame, error) {
svc.mu.RLock()
defer svc.mu.RUnlock()
return svc.actual.Position(ctx, val, extra)
}
func (svc *reconfigurableSlam) GetMap(ctx context.Context,
name string,
mimeType string,
cp *referenceframe.PoseInFrame,
include bool,
extra map[string]interface{},
) (string, image.Image, *vision.Object, error) {
svc.mu.RLock()
defer svc.mu.RUnlock()
return svc.actual.GetMap(ctx, name, mimeType, cp, include, extra)
}
func (svc *reconfigurableSlam) Close(ctx context.Context) error {
svc.mu.RLock()
defer svc.mu.RUnlock()
return goutils.TryClose(ctx, svc.actual)
}
// Reconfigure replaces the old slam service with a new slam.
func (svc *reconfigurableSlam) Reconfigure(ctx context.Context, newSvc resource.Reconfigurable) error {
svc.mu.Lock()
defer svc.mu.Unlock()
rSvc, ok := newSvc.(*reconfigurableSlam)
if !ok {
return utils.NewUnexpectedTypeError(svc, newSvc)
}
if err := goutils.TryClose(ctx, svc.actual); err != nil {
golog.Global().Errorw("error closing old", "error", err)
}
svc.actual = rSvc.actual
return nil
}
// WrapWithReconfigurable wraps a slam service as a Reconfigurable.
func WrapWithReconfigurable(s interface{}, name resource.Name) (resource.Reconfigurable, error) {
svc, ok := s.(Service)
if !ok {
return nil, NewUnimplementedInterfaceError(s)
}
if reconfigurable, ok := s.(*reconfigurableSlam); ok {
return reconfigurable, nil
}
return &reconfigurableSlam{name: name, actual: svc}, nil
}