A PX4 based camera pointer

servo.go 2.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright 2017 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. package pipoint
  16. import (
  17. "math"
  18. "juju.net.nz/x/pipoint/param"
  19. "juju.net.nz/x/pipoint/util"
  20. )
  21. // ServoParams holds the parameters for a servo including limits.
  22. type ServoParams struct {
  23. Pin int
  24. Span float64
  25. Min float64
  26. Max float64
  27. Low float64
  28. High float64
  29. Tau float64
  30. }
  31. // Servo is a servo on a pin with limits, demand, and actual
  32. // position.
  33. type Servo struct {
  34. params *param.Param
  35. sp *param.Param
  36. pv *param.Param
  37. pwm *ServoBlaster
  38. filter *Lowpass
  39. }
  40. // NewServo creates a new servo with params on the given tree.
  41. func NewServo(name string, params *param.Params) *Servo {
  42. s := &Servo{
  43. params: params.NewWith(name, &ServoParams{
  44. Pin: -1,
  45. Min: 1.0,
  46. Max: 2.0,
  47. Low: 1.1,
  48. High: 1.9,
  49. Span: math.Pi,
  50. Tau: 1.0,
  51. }),
  52. sp: params.NewNum(name + ".sp"),
  53. pv: params.NewNum(name + ".pv"),
  54. filter: &Lowpass{},
  55. }
  56. return s
  57. }
  58. // Set updates the target angle in radians. The servo is actually
  59. // updated on calling Tick().
  60. func (s *Servo) Set(angle float64) {
  61. s.sp.SetFloat64(angle)
  62. }
  63. // Tick updates the servo output based on demand. Call every ~20 ms.
  64. func (s *Servo) Tick() {
  65. params := s.params.Get().(*ServoParams)
  66. angle := s.sp.GetFloat64()
  67. angle = s.filter.StepEx(angle, params.Tau)
  68. // Convert to pulse width.
  69. angle += math.Pi / 2
  70. ms := util.Scale(angle, 0, params.Span, params.Low, params.High)
  71. ms = math.Min(params.Max, math.Max(params.Min, ms))
  72. s.pv.SetFloat64(ms)
  73. if params.Pin < 0 {
  74. return
  75. }
  76. if s.pwm == nil || params.Pin != s.pwm.Pin {
  77. // PWM pin has been set or changed. Update.
  78. s.pwm = &ServoBlaster{Pin: params.Pin}
  79. }
  80. if s.pwm != nil {
  81. s.pwm.SetDuty(int(ms * 1e6))
  82. }
  83. }