Using the servo driver

We will make an activity that allows us to select the target angle for a servo motor and apply it using components of the Rainbow HAT. To do so, we will use the buttons A and B to respectively decrease and increase the target angle, which we will display on the LCD. Finally, when we tap on button C, we will apply the target angle to the servo.

This sample project combines several components on the Rainbow HAT with a servo. It serves both as a reminder of how to use those components and as a showcase of how handy they can be when performing quick tests with other peripherals.

Since we are going to use a servo, buttons, and the alphanumeric display, we will need to add the following three dependencies to our build.gradle:

dependencies {
[...]
implementation 'com.google.android.things.contrib:driver-pwmservo:+'
implementation 'com.google.android.things.contrib:driver-button:+'
implementation 'com.google.android.things.contrib:driver-ht16k33:+'
}

The Rainbow HAT allows us to connect the servos really easily; it exposes the three pins (PWM, Vcc, and Ground) together and in the right order. Note that most servos come with a connector that just has these three pins. If you were to connect them to the developer kit directly, you would need extra wires.

When connecting the servo, use the colors for reference, especially the PWM, which is usually yellow.

When connecting the servo, you need to pay attention to the colors. Red and black should be used for Vcc and Ground respectively but not all manufacturers follow this standard (other similar colors, such as brown instead of black, may be used), but in all cases the PWM connection is yellowish and the Ground one is always darker:

To initialize a servo we just have to instantiate an object of type Servo passing the right name for the PWM pin and then set the angle:

val servo = Servo(BoardDefaults.servoPwm)
servo.setEnabled(true)
servo
.angle = targetAngle

In this case, we let the driver use the default values for the servo. Those values are 0 to 180 degrees for servo rotation and 1 to 2 milliseconds for pulse duration. Those defaults are fine for most servos, but always check the specs of your servo and modify them if required.

The default values for the servo driver are 0 to 180 degrees for servo rotation and 1 to 2 milliseconds for pulse duration.

Also note that we need to enable the PWM output. It is the same behavior as with the buzzer: Android Things will not generate any output on that pin unless it is enabled.

PWM only generates an output when it is enabled, so if you do not enable the pin, the servo won't move.

Let's explore the code of this example, starting with the member variables declaration:

class ServoActivity: Activity() {

private lateinit var buttonA: ButtonInputDriver
private lateinit var buttonB: ButtonInputDriver
private lateinit var buttonC: ButtonInputDriver
private lateinit var servo: Servo
private lateinit var display: AlphanumericDisplay

private var targetAngle = 0.0

[...]
}

We will be using three button input drivers, the servo, and the alphanumeric display, so we just declare them all as lateinit, as usual. We also use a class variable named targetAngle to store the current angle selected.

Initialization is also quite straightforward:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

servo = Servo(BoardDefaults.servoPwm)
servo.setEnabled(true)

display = AlphanumericDisplay(BoardDefaults.i2cBus)
display.setEnabled(true)
display.setBrightness(AlphanumericDisplay.HT16K33_BRIGHTNESS_MAX)

buttonA = ButtonInputDriver(BoardDefaults.buttonA,
PRESSED_WHEN_LOW, KEYCODE_A)
buttonB = ButtonInputDriver(BoardDefaults.buttonB,
PRESSED_WHEN_LOW, KEYCODE_B)
buttonC = ButtonInputDriver(BoardDefaults.buttonC,
PRESSED_WHEN_LOW, KEYCODE_C)

buttonA.register()
buttonB.register()
buttonC.register()
}

Inside onCreate we open the servo and enable it; the other components are initialized the same way as we did before. You may have noticed that the alphanumeric display uses the I2C bus. We will look into the details of that in the next chapter.

And we do the typical cleanup inside onDestroy:

override fun onDestroy() {
super.onDestroy()

servo.close()
display.close()

buttonA.unregister()
buttonB.unregister()
buttonC.unregister()
}

The reason why we are using ButtonInputDriver in this example is that it handles key repeats out of the box, and moving the value of the angle from 0 to 180 would be very tedious without that functionality.

We override both onKeyDown and onKeyMultiple using a common method to handle the key code and we pass the event up the chain if it wasn't handled:

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (handleKeyCode(keyCode)) {
return true
}
return super.onKeyDown(keyCode, event)
}

override fun onKeyMultiple(keyCode: Int, repeatCount: Int, event: KeyEvent?): Boolean {
if (handleKeyCode(keyCode)) {
return true
}
return super.onKeyMultiple(keyCode, repeatCount, event)
}

Let's look at the code for handleKeyCode:

private fun handleKeyCode(keyCode: Int): Boolean {
when (keyCode) {
KEYCODE_A -> {
decreaseAngle()
return true
}
KEYCODE_B -> {
increaseAngle()
return true
}
KEYCODE_C -> {
servo.angle = targetAngle
return true
}
else -> {
return false
}
}
}

As we mentioned before, to make the servo move to the specified position we just have to set its angle to the targetAngle and the driver will take care of it for us. Note that although Kotlin allows us to write the code as a variable assignment, it is calling a setter method behind the scenes, on which the PWM connection is configured.

Kotlin allows us to set the angle as a variable assignment, but it is calling a setter method behind the scenes.

Finally, let's look inside the functions that increase and decrease the angle:

private fun decreaseAngle() {
targetAngle--
if (targetAngle < servo.minimumAngle) {
targetAngle = servo.minimumAngle
}
display.display(targetAngle)
}

private fun increaseAngle() {
targetAngle++
if (targetAngle > servo.maximumAngle) {
targetAngle = servo.maximumAngle
}
display.display(targetAngle)
}

Both are quite simple: first we increase or decrease the value until we reach the values the servo has configured as maximum or minimum angles, and then we display the value on the display.

With this example, we have a very simple and visual way to interact with a servo and check how it works. Let's take a look at how to modify the configuration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.1.232