Skip to content

Commit 0954ea7

Browse files
committed
feat: forked from 'github.com/ralvarezdev/klevor'
1 parent 0894b90 commit 0954ea7

File tree

6 files changed

+337
-0
lines changed

6 files changed

+337
-0
lines changed

constants.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build tinygo && (rp2040 || rp2350)
2+
3+
package tinygo_servo
4+
5+
const (
6+
// LeftLimitAngle is the angle that represents the left limit position of the servo motors.
7+
LeftLimitAngle uint16 = 0
8+
9+
// RightLimitAngle is the angle that represents the right limit position of the servo motors.
10+
RightLimitAngle uint16 = 180
11+
)

errors.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//go:build tinygo && (rp2040 || rp2350)
2+
3+
package tinygo_servo
4+
5+
import (
6+
tinygotypes "github.com/ralvarezdev/tinygo-types"
7+
)
8+
9+
const (
10+
// ErrorCodeServoStartNumber is the starting number for servo-related error codes.
11+
ErrorCodeServoStartNumber uint16 = 5230
12+
)
13+
14+
const (
15+
ErrorCodeServoFailedToConfigurePWM tinygotypes.ErrorCode = tinygotypes.ErrorCode(iota + ErrorCodeServoStartNumber)
16+
ErrorCodeServoFailedToInitializeServo
17+
ErrorCodeServoAngleOutOfRange
18+
ErrorCodeServoAngleBelowMinPulseWidth
19+
ErrorCodeServoAngleAboveMaxPulseWidth
20+
ErrorCodeServoFailedToSetServoAngle
21+
)

go.mod

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module github.com/ralvarezdev/tinygo-servo
2+
3+
go 1.25.0
4+
5+
require (
6+
github.com/ralvarezdev/tinygo-buffers v0.0.3 // indirect
7+
github.com/ralvarezdev/tinygo-logger v0.0.3 // indirect
8+
github.com/ralvarezdev/tinygo-types v0.0.3 // indirect
9+
)

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
github.com/ralvarezdev/tinygo-buffers v0.0.3 h1:KQJ9tg24PMr6RFjPkdf78WEzQ2cRG6NR7JQCqRns1N4=
2+
github.com/ralvarezdev/tinygo-buffers v0.0.3/go.mod h1:sP4ilzeozqemPX/4dqMmnAKq61ys0qs89XITGab03BA=
3+
github.com/ralvarezdev/tinygo-logger v0.0.3 h1:jd4a2JMf0orZPzz8upnVLKaNEWK+3SpYCwa0vnVl+Vo=
4+
github.com/ralvarezdev/tinygo-logger v0.0.3/go.mod h1:jS3shtdAG0nJzVMys4IWhD2YiSAZQ8/PU1oYoZwA5+w=
5+
github.com/ralvarezdev/tinygo-types v0.0.3 h1:h8ogOD2lOVxR+w5i6o+v/8qTROFA2KBjVXBM7NT3SMc=
6+
github.com/ralvarezdev/tinygo-types v0.0.3/go.mod h1:2u3ApwAtIqGZ6wDsmUYt44bIk1DEn06INNjtfWndCr4=

interfaces.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//go:build tinygo && (rp2040 || rp2350)
2+
3+
package tinygo_servo
4+
5+
import (
6+
tinygotypes "github.com/ralvarezdev/tinygo-types"
7+
)
8+
9+
type (
10+
// Handler is the interface to handle servo operations
11+
Handler interface {
12+
SetAngle(angle uint16) tinygotypes.ErrorCode
13+
GetAngle() uint16
14+
SetAngleRelativeToCenter(relativeAngle int16) tinygotypes.ErrorCode
15+
IsAngleCentered() bool
16+
SetAngleToCenter() tinygotypes.ErrorCode
17+
SetAngleToRight(angle uint16) tinygotypes.ErrorCode
18+
SetAngleToLeft(angle uint16) tinygotypes.ErrorCode
19+
SetDirectionToCenter() tinygotypes.ErrorCode
20+
SetDirectionToRight(angle uint16) tinygotypes.ErrorCode
21+
SetDirectionToLeft(angle uint16) tinygotypes.ErrorCode
22+
}
23+
)

types.go

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
//go:build tinygo && (rp2040 || rp2350)
2+
3+
package tinygo_servo
4+
5+
import (
6+
"time"
7+
8+
"machine"
9+
10+
tinygotypes "github.com/ralvarezdev/tinygo-types"
11+
tinygodriversservo "tinygo.org/x/drivers/servo"
12+
tinygologger "github.com/ralvarezdev/tinygo-logger"
13+
)
14+
15+
type (
16+
// DefaultHandler is the default implementation of the Servo interface
17+
DefaultHandler struct {
18+
afterSetAngleFunc func(angle uint16)
19+
isMovementEnabled func() bool
20+
isDirectionInverted bool
21+
frequency uint16
22+
minPulseWidth uint16
23+
halfPulseWidth uint16
24+
maxPulseWidth uint16
25+
rangePulseWidth uint16
26+
centerAngle uint16
27+
maxAngle uint16
28+
servo tinygodriversservo.Servo
29+
angle uint16
30+
logger tinygologger.Logger
31+
}
32+
)
33+
34+
var (
35+
// setAnglePrefix is the prefix message for new angle setting
36+
setAnglePrefix = "Set servo angle degrees to:"
37+
)
38+
39+
// NewDefaultHandler creates a new instance of DefaultHandler
40+
//
41+
// Parameters:
42+
//
43+
// pwm: The PWM interface to control the servo
44+
// pin: The pin connected to the servo
45+
// afterSetAngleFunc: A callback function to be called after setting the angle
46+
// isMovementEnabled: A function to check if movement is enabled
47+
// frequency: The frequency of the PWM signal
48+
// minPulseWidth: The minimum pulse width for the servo motor
49+
// maxPulseWidth: The maximum pulse width for the servo motor
50+
// centerAngle: The center angle of the servo motor
51+
// maxAngle: The maximum angle the servo can move from the center
52+
// isDirectionInverted: Whether the direction of the servo motor is inverted
53+
// logger: The logger instance for logging messages
54+
//
55+
// Returns:
56+
//
57+
// An instance of DefaultHandler and an error if any occurred during initialization
58+
func NewDefaultHandler(
59+
pwm tinygodriversservo.PWM,
60+
pin machine.Pin,
61+
afterSetAngleFunc func(angle uint16),
62+
isMovementEnabled func() bool,
63+
frequency uint16,
64+
minPulseWidth uint16,
65+
maxPulseWidth uint16,
66+
centerAngle uint16,
67+
maxAngle uint16,
68+
isDirectionInverted bool,
69+
logger tinygologger.Logger,
70+
) (*DefaultHandler, tinygotypes.ErrorCode) {
71+
// Configure the PWM
72+
if err := pwm.Configure(
73+
machine.PWMConfig{
74+
Period: uint64(time.Second / time.Duration(frequency)),
75+
},
76+
); err != nil {
77+
return nil, ErrorCodeServoFailedToConfigurePWM
78+
}
79+
80+
// Create a new instance of the servo
81+
servo, err := tinygodriversservo.New(pwm, pin)
82+
if err != nil {
83+
return nil, ErrorCodeServoFailedToInitializeServo
84+
}
85+
86+
// Calculate the half pulse and range pulse
87+
halfPulseWidth := (maxPulseWidth + minPulseWidth) / 2
88+
rangePulseWidth := maxPulseWidth - minPulseWidth
89+
90+
// Initialize the servo with the provided parameters
91+
handler := &DefaultHandler{
92+
afterSetAngleFunc: afterSetAngleFunc,
93+
isMovementEnabled: isMovementEnabled,
94+
isDirectionInverted: isDirectionInverted,
95+
frequency: frequency,
96+
minPulseWidth: minPulseWidth,
97+
halfPulseWidth: halfPulseWidth,
98+
maxPulseWidth: maxPulseWidth,
99+
rangePulseWidth: rangePulseWidth,
100+
servo: servo,
101+
angle: centerAngle,
102+
centerAngle: centerAngle,
103+
logger: logger,
104+
}
105+
106+
// Center the servo on initialization
107+
_ = handler.SetAngleToCenter()
108+
return handler, tinygotypes.ErrorCodeNil
109+
}
110+
111+
// GetAngle returns the current angle of the servo motor
112+
//
113+
// Returns:
114+
//
115+
// The current angle of the servo motor
116+
func (h *DefaultHandler) GetAngle() uint16 {
117+
return h.angle
118+
}
119+
120+
// SetAngle sets the angle of the servo motor
121+
//
122+
// Parameters:
123+
//
124+
// angle: The angle to set the servo motor to, must be between 0 and the actuation range
125+
func (h *DefaultHandler) SetAngle(angle uint16) tinygotypes.ErrorCode {
126+
// Check if the angle is within the valid range
127+
if angle < h.centerAngle-h.maxAngle || angle > h.centerAngle+h.maxAngle {
128+
return ErrorCodeServoAngleOutOfRange
129+
}
130+
if angle < LeftLimitAngle || angle > RightLimitAngle {
131+
return ErrorCodeServoAngleOutOfRange
132+
}
133+
134+
// Check if the angle is the same as the current angle
135+
if angle == h.angle {
136+
return tinygotypes.ErrorCodeNil
137+
}
138+
139+
// Check if the direction is inverted
140+
if h.isDirectionInverted {
141+
angle = RightLimitAngle - (angle - LeftLimitAngle)
142+
}
143+
144+
// Update the current angle
145+
h.angle = angle
146+
147+
// Set the servo angle
148+
if h.isMovementEnabled == nil || h.isMovementEnabled() {
149+
if err := h.servo.SetAngleWithMicroseconds(
150+
int(angle),
151+
int(h.minPulseWidth),
152+
int(h.maxPulseWidth),
153+
); err != nil {
154+
return ErrorCodeServoFailedToSetServoAngle
155+
}
156+
}
157+
158+
// Log the new angle if logger is provided
159+
if h.logger != nil {
160+
h.logger.AddMessageWithUint16(setAnglePrefix, angle, true, true, false)
161+
h.logger.Debug()
162+
}
163+
164+
// Call the after set angle function if provided
165+
if h.afterSetAngleFunc != nil {
166+
h.afterSetAngleFunc(angle)
167+
}
168+
169+
return tinygotypes.ErrorCodeNil
170+
}
171+
172+
// IsAngleCentered checks if the servo motor angle is centered
173+
//
174+
// Returns:
175+
//
176+
// True if the servo motor is centered, false otherwise
177+
func (h *DefaultHandler) IsAngleCentered() bool {
178+
return h.angle == h.centerAngle
179+
}
180+
181+
// SetAngleToCenter centers the servo motor to the middle position
182+
//
183+
// Returns:
184+
//
185+
// An error if the servo motor could not be centered
186+
func (h *DefaultHandler) SetAngleToCenter() tinygotypes.ErrorCode {
187+
return h.SetAngle(h.centerAngle)
188+
}
189+
190+
// SetAngleRelativeToCenter sets the angle of the servo motor relative to the center position
191+
//
192+
// Parameters:
193+
//
194+
// relativeAngle: The relative angle value between -90 and 90 degrees
195+
//
196+
// Returns:
197+
//
198+
// An error if the relative angle is not within the left and right limits
199+
func (h *DefaultHandler) SetAngleRelativeToCenter(relativeAngle int16) tinygotypes.ErrorCode {
200+
// Calculate the absolute angle based on the center angle and relative angle
201+
absoluteAngle := int16(h.centerAngle) + relativeAngle
202+
203+
// Check if the absolute angle is within the left and right limits
204+
if absoluteAngle < int16(LeftLimitAngle) || absoluteAngle > int16(RightLimitAngle) {
205+
return ErrorCodeServoAngleOutOfRange
206+
}
207+
208+
// Set the servo angle
209+
return h.SetAngle(uint16(absoluteAngle))
210+
}
211+
212+
// SetAngleToRight sets the servo motor to the right by a specified angle
213+
//
214+
// Parameters:
215+
//
216+
// angle: The angle value to move the servo to the right, must be between 0 and the right limit
217+
//
218+
// Returns:
219+
//
220+
// An error if the angle is not within the right limit
221+
func (h *DefaultHandler) SetAngleToRight(angle uint16) tinygotypes.ErrorCode {
222+
return h.SetAngleRelativeToCenter(-int16(angle))
223+
}
224+
225+
// SetAngleToLeft sets the servo motor to the left by a specified angle
226+
//
227+
// Parameters:
228+
//
229+
// angle: The angle value to move the servo to the left, must be between 0 and the left limit
230+
//
231+
// Returns:
232+
//
233+
// An error if the angle is not within the left limit
234+
func (h *DefaultHandler) SetAngleToLeft(angle uint16) tinygotypes.ErrorCode {
235+
return h.SetAngleRelativeToCenter(int16(angle))
236+
}
237+
238+
// SetDirectionToCenter sets the direction to center
239+
func (h *DefaultHandler) SetDirectionToCenter() tinygotypes.ErrorCode {
240+
return h.SetAngleToCenter()
241+
}
242+
243+
// SetDirectionToRight sets the direction to right
244+
//
245+
// Parameters:
246+
//
247+
// angle: The angle value to move the servo to the left, must be between 0 and the left limit
248+
//
249+
// Returns:
250+
//
251+
// An error if the angle is not within the left limit
252+
func (h *DefaultHandler) SetDirectionToRight(angle uint16) tinygotypes.ErrorCode {
253+
return h.SetAngleToLeft(angle)
254+
}
255+
256+
// SetDirectionToLeft sets the direction to left
257+
//
258+
// Parameters:
259+
//
260+
// angle: The angle value to move the servo to the right, must be between 0 and the right limit
261+
//
262+
// Returns:
263+
//
264+
// An error if the angle is not within the right limit
265+
func (h *DefaultHandler) SetDirectionToLeft(angle uint16) tinygotypes.ErrorCode {
266+
return h.SetAngleToRight(angle)
267+
}

0 commit comments

Comments
 (0)