Skip to content

Commit f5ffa59

Browse files
committed
refactor: removed tinygo servo driver dependency and added different frequency and angle limits support
1 parent a44bb5d commit f5ffa59

File tree

6 files changed

+121
-87
lines changed

6 files changed

+121
-87
lines changed

constants.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

errors.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ const (
1111

1212
const (
1313
ErrorCodeServoFailedToConfigurePWM tinygoerrors.ErrorCode = tinygoerrors.ErrorCode(iota + ErrorCodeServoStartNumber)
14-
ErrorCodeServoFailedToInitializeServo
14+
ErrorCodeServoZeroFrequency
1515
ErrorCodeServoAngleOutOfRange
16-
ErrorCodeServoAngleBelowMinPulseWidth
17-
ErrorCodeServoAngleAboveMaxPulseWidth
18-
ErrorCodeServoFailedToSetServoAngle
16+
ErrorCodeServoInvalidMinPulseWidth
17+
ErrorCodeServoInvalidMaxPulseWidth
1918
ErrorCodeServoNilHandler
2019
ErrorCodeServoUnknownDirection
20+
ErrorCodeServoFailedToGetPWMChannel
21+
ErrorCodeServoInvalidActuationRange
22+
ErrorCodeServoInvalidCenterAngle
2123
)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.25.0
55
require (
66
github.com/ralvarezdev/tinygo-errors v0.0.4
77
github.com/ralvarezdev/tinygo-logger v0.0.9
8-
tinygo.org/x/drivers v0.33.0
8+
github.com/ralvarezdev/tinygo-pwm v0.1.1
99
)
1010

1111
require github.com/ralvarezdev/tinygo-buffers v0.1.3 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ github.com/ralvarezdev/tinygo-errors v0.0.4 h1:nuqApi7tEzPSSf2/3Uqxxizwftvoxczae
44
github.com/ralvarezdev/tinygo-errors v0.0.4/go.mod h1:PlkyrG60saZetwFX1mPhve+9l2pneVH7c8q5w4sxe8M=
55
github.com/ralvarezdev/tinygo-logger v0.0.9 h1:S19f+yoWqvXJQLas6YJ5dUGRGhR+Qhk64mLGkcfW+dw=
66
github.com/ralvarezdev/tinygo-logger v0.0.9/go.mod h1:nkyqp2ph54sYYe6A6XMy9L8aEx7N7jVaVUL9uJCRVFo=
7-
tinygo.org/x/drivers v0.33.0 h1:5r8Ab0IxjWQi7LzYLNWpya6U4nedo9ZtxeMaAzrJTG8=
8-
tinygo.org/x/drivers v0.33.0/go.mod h1:ZdErNrApSABdVXjA1RejD67R8SNRI6RKVfYgQDZtKtk=
7+
github.com/ralvarezdev/tinygo-pwm v0.1.1 h1:bytmDqrnb8M0YFxzMeLlRrhXR8InJSzD+KvqdsPbq/E=
8+
github.com/ralvarezdev/tinygo-pwm v0.1.1/go.mod h1:7UIppP1HoK+Y89DlhTA3gUE/7ujiVJi+K1c0uO3SGOw=

interfaces.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ type (
1313
IsAngleCentered() bool
1414
SetAngleToCenter() tinygoerrors.ErrorCode
1515
SetAngleToRight(angle uint16) tinygoerrors.ErrorCode
16-
SafeSetAngleToRight(angle uint16) tinygoerrors.ErrorCode
1716
SetAngleToLeft(angle uint16) tinygoerrors.ErrorCode
18-
SafeSetAngleToLeft(angle uint16) tinygoerrors.ErrorCode
1917
}
2018
)

types.go

Lines changed: 112 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package tinygo_servo
22

33
import (
4-
"time"
5-
64
"machine"
75

86
tinygoerrors "github.com/ralvarezdev/tinygo-errors"
97
tinygologger "github.com/ralvarezdev/tinygo-logger"
10-
tinygodriversservo "tinygo.org/x/drivers/servo"
8+
tinygopwm "github.com/ralvarezdev/tinygo-pwm"
119
)
1210

1311
type (
@@ -17,19 +15,24 @@ type (
1715
isMovementEnabled func() bool
1816
isDirectionInverted bool
1917
frequency uint16
20-
minPulseWidth uint16
21-
halfPulseWidth uint16
22-
maxPulseWidth uint16
23-
rangePulseWidth uint16
18+
minPulseWidth uint32
19+
maxPulseWidth uint32
2420
centerAngle uint16
25-
maxAngle uint16
26-
servo tinygodriversservo.Servo
21+
actuationRange uint16
22+
leftLimitAngle uint16
23+
rightLimitAngle uint16
2724
angle uint16
2825
logger tinygologger.Logger
26+
pwm tinygopwm.PWM
27+
channel uint8
28+
period uint32
2929
}
3030
)
3131

3232
var (
33+
// setPeriodPrefix is the prefix for the log message when setting the PWM period
34+
setPeriodPrefix = []byte("Set Servo PWM period to:")
35+
3336
// setAnglePrefix is the prefix message for new angle setting
3437
setAnglePrefix = []byte("Set servo angle degrees to:")
3538
)
@@ -46,44 +49,95 @@ var (
4649
// minPulseWidth: The minimum pulse width for the servo motor
4750
// maxPulseWidth: The maximum pulse width for the servo motor
4851
// centerAngle: The center angle of the servo motor
49-
// maxAngle: The maximum angle the servo can move from the center
52+
// maxLeftAngle: The maximum left angle from the center
53+
// maxRightAngle: The maximum right angle from the center
5054
// isDirectionInverted: Whether the direction of the servo motor is inverted
5155
// logger: The logger instance for logging messages
5256
//
5357
// Returns:
5458
//
5559
// An instance of DefaultHandler and an error if any occurred during initialization
5660
func NewDefaultHandler(
57-
pwm tinygodriversservo.PWM,
61+
pwm tinygopwm.PWM,
5862
pin machine.Pin,
5963
afterSetAngleFunc func(angle uint16),
6064
isMovementEnabled func() bool,
6165
frequency uint16,
62-
minPulseWidth uint16,
63-
maxPulseWidth uint16,
66+
minPulseWidth uint32,
67+
maxPulseWidth uint32,
68+
actuationRange uint16,
6469
centerAngle uint16,
65-
maxAngle uint16,
70+
maxLeftAngle uint16,
71+
maxRightAngle uint16,
6672
isDirectionInverted bool,
6773
logger tinygologger.Logger,
6874
) (*DefaultHandler, tinygoerrors.ErrorCode) {
75+
// Check if the frequency is zero
76+
if frequency == 0 {
77+
return nil, ErrorCodeServoZeroFrequency
78+
}
79+
6980
// Configure the PWM
81+
period := 1e9 / float64(frequency)
7082
if err := pwm.Configure(
7183
machine.PWMConfig{
72-
Period: uint64(time.Second / time.Duration(frequency)),
84+
Period: uint64(period),
7385
},
7486
); err != nil {
7587
return nil, ErrorCodeServoFailedToConfigurePWM
7688
}
7789

78-
// Create a new instance of the servo
79-
servo, err := tinygodriversservo.New(pwm, pin)
90+
// Log the configured period
91+
if logger != nil {
92+
logger.AddMessageWithUint32(
93+
setPeriodPrefix,
94+
uint32(period),
95+
true,
96+
true,
97+
false,
98+
)
99+
logger.Debug()
100+
}
101+
102+
// Get the channel from the pin
103+
channel, err := pwm.Channel(pin)
80104
if err != nil {
81-
return nil, ErrorCodeServoFailedToInitializeServo
105+
return nil, ErrorCodeServoFailedToGetPWMChannel
106+
}
107+
108+
// Check if the min pulse width is valid
109+
if minPulseWidth == 0 || minPulseWidth >= uint32(period) {
110+
return nil, ErrorCodeServoInvalidMinPulseWidth
111+
}
112+
113+
// Check if the max pulse width is valid
114+
if maxPulseWidth == 0 || maxPulseWidth >= uint32(period) {
115+
return nil, ErrorCodeServoInvalidMaxPulseWidth
116+
}
117+
118+
// Check if the actuation range is valid
119+
if actuationRange == 0 || actuationRange > 360 {
120+
return nil, ErrorCodeServoInvalidActuationRange
82121
}
83122

84-
// Calculate the half pulse and range pulse
85-
halfPulseWidth := (maxPulseWidth + minPulseWidth) / 2
86-
rangePulseWidth := maxPulseWidth - minPulseWidth
123+
// Check if the center angle is valid
124+
if centerAngle < 0 || centerAngle > actuationRange {
125+
return nil, ErrorCodeServoInvalidCenterAngle
126+
}
127+
128+
// Calculate the left and right limit angles
129+
leftLimitAngle := centerAngle - maxLeftAngle
130+
rightLimitAngle := centerAngle + maxRightAngle
131+
132+
// Check if the left limit angle is valid
133+
if leftLimitAngle < 0 {
134+
leftLimitAngle = 0
135+
}
136+
137+
// Check if the right limit angle is valid
138+
if rightLimitAngle > actuationRange {
139+
rightLimitAngle = actuationRange
140+
}
87141

88142
// Initialize the servo with the provided parameters
89143
handler := &DefaultHandler{
@@ -92,14 +146,17 @@ func NewDefaultHandler(
92146
isDirectionInverted: isDirectionInverted,
93147
frequency: frequency,
94148
minPulseWidth: minPulseWidth,
95-
halfPulseWidth: halfPulseWidth,
96149
maxPulseWidth: maxPulseWidth,
97-
rangePulseWidth: rangePulseWidth,
98-
servo: servo,
99150
angle: centerAngle,
100151
centerAngle: centerAngle,
152+
actuationRange: actuationRange,
101153
logger: logger,
102-
maxAngle: maxAngle,
154+
pwm: pwm,
155+
channel: channel,
156+
leftLimitAngle: leftLimitAngle,
157+
rightLimitAngle: rightLimitAngle,
158+
period: uint32(period),
159+
103160
}
104161

105162
// Center the servo on initialization
@@ -123,10 +180,7 @@ func (h *DefaultHandler) GetAngle() uint16 {
123180
// angle: The angle to set the servo motor to, must be between 0 and the actuation range
124181
func (h *DefaultHandler) SetAngle(angle uint16) tinygoerrors.ErrorCode {
125182
// Check if the angle is within the valid range
126-
if angle < h.centerAngle-h.maxAngle || angle > h.centerAngle+h.maxAngle {
127-
return ErrorCodeServoAngleOutOfRange
128-
}
129-
if angle < LeftLimitAngle || angle > RightLimitAngle {
183+
if angle < h.centerAngle-h.leftLimitAngle || angle > h.centerAngle+h.rightLimitAngle {
130184
return ErrorCodeServoAngleOutOfRange
131185
}
132186

@@ -137,21 +191,24 @@ func (h *DefaultHandler) SetAngle(angle uint16) tinygoerrors.ErrorCode {
137191

138192
// Check if the direction is inverted
139193
if h.isDirectionInverted {
140-
angle = RightLimitAngle - (angle - LeftLimitAngle)
194+
angle = h.rightLimitAngle - (angle - h.leftLimitAngle)
141195
}
142196

143197
// Update the current angle
144198
h.angle = angle
145199

200+
// Calculate the pulse
201+
pulse := uint32(h.minPulseWidth) + uint32(float64(h.maxPulseWidth-h.minPulseWidth) * float64(angle) / float64(h.actuationRange))
202+
203+
146204
// Set the servo angle
147205
if h.isMovementEnabled == nil || h.isMovementEnabled() {
148-
if err := h.servo.SetAngleWithMicroseconds(
149-
int(angle),
150-
int(h.minPulseWidth),
151-
int(h.maxPulseWidth),
152-
); err != nil {
153-
return ErrorCodeServoFailedToSetServoAngle
154-
}
206+
tinygopwm.SetDuty(
207+
h.pwm,
208+
h.channel,
209+
pulse,
210+
h.period,
211+
)
155212
}
156213

157214
// Log the new angle if logger is provided
@@ -200,7 +257,7 @@ func (h *DefaultHandler) SetAngleRelativeToCenter(relativeAngle int16) tinygoerr
200257
absoluteAngle := int16(h.centerAngle) + relativeAngle
201258

202259
// Check if the absolute angle is within the left and right limits
203-
if absoluteAngle < int16(LeftLimitAngle) || absoluteAngle > int16(RightLimitAngle) {
260+
if absoluteAngle < int16(h.leftLimitAngle) || absoluteAngle > int16(h.rightLimitAngle) {
204261
return ErrorCodeServoAngleOutOfRange
205262
}
206263

@@ -218,23 +275,16 @@ func (h *DefaultHandler) SetAngleRelativeToCenter(relativeAngle int16) tinygoerr
218275
//
219276
// An error if the angle is not within the right limit
220277
func (h *DefaultHandler) SetAngleToRight(angle uint16) tinygoerrors.ErrorCode {
221-
return h.SetAngleRelativeToCenter(int16(angle))
222-
}
278+
// Check if the angle is negative
279+
if angle < 0 {
280+
angle = 0
281+
}
223282

224-
// SafeSetAngleToRight sets the servo motor to the right by a specified angle without exceeding limits
225-
//
226-
// Parameters:
227-
//
228-
// angle: The angle value to move the servo to the right, must be between 0 and the right limit
229-
//
230-
// Returns:
231-
//
232-
// An error if the angle is not within the right limit
233-
func (h *DefaultHandler) SafeSetAngleToRight(angle uint16) tinygoerrors.ErrorCode {
234-
if angle > h.maxAngle {
235-
angle = h.maxAngle
283+
// Check if the angle is within the right limit
284+
if angle > h.rightLimitAngle-h.centerAngle {
285+
angle = h.rightLimitAngle - h.centerAngle
236286
}
237-
return h.SetAngleToRight(angle)
287+
return h.SetAngleRelativeToCenter(int16(angle))
238288
}
239289

240290
// SetAngleToLeft sets the servo motor to the left by a specified angle
@@ -247,21 +297,14 @@ func (h *DefaultHandler) SafeSetAngleToRight(angle uint16) tinygoerrors.ErrorCod
247297
//
248298
// An error if the angle is not within the left limit
249299
func (h *DefaultHandler) SetAngleToLeft(angle uint16) tinygoerrors.ErrorCode {
250-
return h.SetAngleRelativeToCenter(-int16(angle))
251-
}
300+
// Check if the angle is negative
301+
if angle < 0 {
302+
angle = 0
303+
}
252304

253-
// SafeSetAngleToLeft sets the servo motor to the left by a specified angle without exceeding limits
254-
//
255-
// Parameters:
256-
//
257-
// angle: The angle value to move the servo to the left, must be between 0 and the left limit
258-
//
259-
// Returns:
260-
//
261-
// An error if the angle is not within the left limit
262-
func (h *DefaultHandler) SafeSetAngleToLeft(angle uint16) tinygoerrors.ErrorCode {
263-
if angle > h.maxAngle {
264-
angle = h.maxAngle
305+
// Check if the angle is within the left limit
306+
if angle > h.centerAngle-h.leftLimitAngle {
307+
angle = h.centerAngle - h.leftLimitAngle
265308
}
266-
return h.SetAngleToLeft(angle)
267-
}
309+
return h.SetAngleRelativeToCenter(-int16(angle))
310+
}

0 commit comments

Comments
 (0)