Position sensing + motor drive ⇒ a servo

1. Review

These are tasks you have done before using your Maker Pi board. This task combines past experience.

1.1. Measuring a voltage with the ADC

In Lab 17 Analog Inputs to the Microcontroller you learned about the analog-to-digital converter (ADC).

You used several ADC channels again in Lab 18 Interfacing to a Joystick.

That hardware on the MCU converts a voltage at a (specifically capable) pin into an integer of a certain bit width — 16 bits in this case.

1
2
3
4
5
6
import analogio

pot = analogio.AnalogIn(board.GP26)

# read the voltage and convert to 0.0 to 1.0 range for convenience.
position = pot.value / 65535

1.2. Controlling a DC motor’s speed

Way back in MCU motors and PWM you used the Maker Pi board to drive a DC motor with the help of an H-bridge chip on the board. You changed the speed by turning the motor voltage high and low very quickly with a certain duty cycle percentage called pulse-width modulation (PWM).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import board
import digitalio as dio

import pwmio
from adafruit_motor import motor


# DC motor setup
M1A = pwmio.PWMOut(board.GP8, frequency=1_000)
M1B = pwmio.PWMOut(board.GP9, frequency=1_000)
dcmotor = motor.DCMotor(M1A, M1B)

# set .throttle to the range -1.0 to +1.0
#   .throttle = 0 means *brake mode*
#   .throttle = None means *coast mode*
dcmotor.throttle = 0.75

2. Software-defined servo

How does a servo work?
  • Accepts a commanded shaft angle.

  • Senses its current position by measuring the potentiometer’s wiper voltage.

  • Drives the motor in the appropriate direction to reduce the difference between the commanded and actual shaft angle.

  • repeats (always)



Create a program that takes in a number in degrees (0 to 180) and causes your servo’s output shaft to move to that angle and stay there if pushed away from that position.

2.1. Tips

It is best (way best, by a huge margin) to approach this task one step at a time.

  • Use the MCU to read the position of the shaft by wiring the ends of the potentiometer to +3.3 V and GND. The middle pin’s voltage is: Vx = (% rotation) * (3.3-0)  V

Figure out where the mechanical mid-rotation point is and mark its position as 90°. Then turn the shaft to 0° and 180° and write down the values as measured by the MCU’s analog-to-digital converter attached to the potentiometer’s middle pin. (these numbers will not be 0 and 65535 since the potentiometer’s range is more than 180°)

Pay attention to the direction the shaft moves compared to the ADC numbers!

  • Drive the motor inside the servo unit.

Figure out how to drive the motor at various speeds and directions. Pay attention to the sign you give to dcmotor.throttle = NUMBER and the physical direction. This is how you get the shaft to go to the position you desire. Remember that driving the motor sets its speed and not the position directly! You will need to stop the motor when the output shaft reaches the commanded angle.

Create a servo(deg) function:
  • one input: deg - the shaft angle to move to, a floating point number between 0. and 180.0

  • one output: the current shaft angle in degrees.

  • each time you call the function, take some action to make the actual position match the commanded position.

Call this function in a while True: loop.

On each iteration of the loop:

It will be very helpful to include in this while True: loop some way to change the commanded position. Perhaps by using the two buttons on the board to increment or decrement the postion’s value. You have seen examples of reading user input while doing other things.

 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
# ...
# ... setup code for pin inputs, outputs, motor drivers, etc.
# ...

while True:
    #
    # Handle user input on the buttons
    #
    if button0.value == 0:
        command = command - 1
    if button1.value == 0:
        command = command + 1

    # some code to ensure 'command' stays between 0 and 180
    # if command > ....:   and so on

    #
    # Get the position of the shaft via the potentiometer's voltage.
    #
    ...your code here...


    #
    # Compute which direction to move
    # and how much to move
    #
    ...this is your job...


    #
    # Command the DC motor to go in that direction
    # (the speed is also up to you)
    #
    ...remember, one step at a time...
    ... which means: test one small thing at once!