Motor Controller

You probably want to make your robot move around the arena. The most common way of doing this is using electric motors. The motor controller in your kit allows you to control the power delivered to two 12V motors.

Power, not Speed

From your robot software, you can tell the motor controller to deliver a certain amount of power to the motors. (For those who are interested, the motor controller uses pulse-width modulation to vary the amount of power delivered to the motors.) There is not a linear relationship between power and the speed of the motor. The motor will be subject to a varying load (e.g. your robot may be going up a ramp, or it might be pushing some blocks). There is also variation between different instances of the same motor, and most DC motors run slightly better in one direction.

As delivered power doesn't relate directly to a specific motor speed, it's not really possible to just use timing to get your robot into the position you want.

Feedback

Since a timing-based approach to motor control doesn't provide repeatable or reliable results, you need to find a different solution. The answer to this problem is "feedback". You will need to write your robot software so that it feeds information from relevant sensors back to your software that determines how to adjust the motor outputs next.

Imagine you had been blind-folded and had to walk across a large room to a chair. Every three steps you are allowed to take your blind-fold off and look around, then put the blind-fold back on before you take any more steps. When you are blind-folded, you have less of an idea about where you are in the room and you hope that your legs carry you in the right direction. Every time you lift up your blind-fold, you are reading your sensors, and when the blind-fold comes back down again you adjust the signals you send to your legs. This is a feedback loop. By periodically examining what needs to be done to reach a given target, and adjusting outputs as necessary, you will eventually reach your target (the chair).

Depending on how you use motors in your robot, there are several different sensors that you could use (and this is a non-exhaustive list):

The motor controller can interface with two AS5030 boards to allow you to read the rotary position of wheels. The motor controller also contains a PID controller (see below) that allows you to move a motor to an absolute position.

Connections

The connectors on the motor controller are shown in the following diagram:

Specification

Motor drivers:

Feedback lines:

These are digital I/O pins, and are used to communicate with the AS5030 sensor board.

Programming Interface

Each motor output can be configured and used independently of the other one. The SR library provides you with an array of motor channels. You control everything to do with the first motor channel using:

  motor[0]
Similarly, you control everything to with the second motor channel using:
  motor[1]
The following documentation talks about using motor[0]. All of these things are also applicable to motor[1].

Controlling motor power

To control the power delivered to motors directly, rather than use any sensors or control loop on the motor controller, configure the motor controller like this:

  motor[0].sensor = motor.NULL
  motor[0].controller = motor.UNITY
  motor[0].target = 0

After configuring the channel as above, enable it like so:

  motor[0].enable()

Your motor channel is now configured. You can set the output to a certain power using motor[0].target. This takes a number between -100 and 100:

So, to set your motor to go backwards at half power use the following:

  motor[0].target = -50

You can change the power delivered to a motor at any time.

Using the AS5030 sensor with PID control

The motor controller incorporates a PID controller that allows you to control the absolute angle of a wheel, or axle that a motor is connected to. The motor controller can sense the rotary position of a rotary shaft using the AS5030 sensor board.

To get the motor controller to use the AS5030 controller, you need to configure it as follows:

motor[0].sensor = motor.AS5030

You have an option of which pins are connected to which. The following code tells the motor controller that the clock pin of the AS5030 is connected to feedback pin 0, and the dio pin is connected to feedback pin 1. The diagram of the motor controller above shows the numbering of the feedback pins.

motor[0].as5030.set_pins( clk = 0, dio = 1 )

The AS5030 is an 8-bit sensor. It is likely that you do not want this many bits, as the least-significant bits are probably too noisy for you to use. You can choose how many bits to lose by calling set_shr. If you are not sure how many to lose, a good number to try first is 2.

motor[0].as5030.set_shr( 2 )

Configuring the PID controller

Tell the motor controller to use the PID controller like so:

motor[0].controller = motor.PID

You now need to configure the P, I, and D coefficients used within the PID controller. See "Tuning the PID loop" below to discover what values you should set these to. Set the coefficients like so:

motor[0].PID.set_coeff( kp = -4, ki = -5, kd = -10 )

To get the motor to move to a specific location when using the PID controller, set the target position:

motor[0].target = -3049 

The motor will then move until it reaches position -3049 (which is likely to be several rotations away).

Waiting for the motor to finish moving

You can suspend your code until the motor reaches the position you asked it to using the following code:

motor[0].target = 500
yield motor[0]

Tuning the PID loop

Using the PID loop requires slightly more set-up than the open-loop power control option. After connecting up the motor controller and AS5030, you will need to tune the PID controller. To tune the motor controller, you should write a program that commands the motor to switch back-and-forth between two positions, for example:

from sr import *

def main():
    motor[0].sensor = motor.AS5030
    motor[0].as5030.set_pins( clk = 0, dio = 1 )
    motor[0].as5030.set_shr( 2 )

    motor[0].controller = motor.PID
    motor[0].PID.set_coeff( kp = -5, ki = 0, kd = 0 )

    while True:
        motor[0].target = 100
        yield 1.5
        motor[0].target = 0
        yield 1.5

Now, you will need to play with the values that the PID coefficients are set to. The following approach is recommended:

  1. Set all coefficients (kp, ki and kd) to 0.
  2. Increase kp until the wheel overshoots the target position and oscillates slightly after reaching the target.
  3. Increase kd until the oscillation is suppressed.
  4. Increase ki until the wheel always reaches the required position.
If there is sufficient demand, Student Robotics may produce a tutorial video on tuning the PID controller.

Reconfiguring motor controller channels

To reconfigure a motor controller channel, you should disable it first:

  motor[0].disable()