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