Open loop DC motor control with a PS3 controller

1-IMG_5063The next stage of my robot project is to make software talk to hardware. Previously I mentioned how I translate PS3 controller data into something useful for a robot. Before getting into complex real-world control, I wanted to check that my example 12V DC motor would respond to my Arduino firmware and controller with simple open loop messages.

What makes it open loop? A system is considered closed loop when the output is measured by a sensor input and fed back into the control system to reach a target setpoint. An example of that is a PID control scheme, which I’ll be building next. Compare that to how this system will work. The joystick position is mapped proportionally against the available motor output but there is no check about the motor’s actual speed. If the motor was powering something under load, the operator of the joystick would need to compensate for it to reach the desired speed. If a PID controller was used, the joystick position would map to a specific speed and the controller would make sure it actually turns at that speed, regardless of the load attached.

Here’s a list of the systems in use:

ROS node

My ROS system handles message communication and in this case it takes joy messages from the PS3 controller node, converts them into left-right motor magnitudes and sends them to the Arduino via serial. In the last node I wrote, the output from the PS3 controller was a Twist message: linear motion in the x direction and angular motion around the z axis. Those real-world values (m/s and rad/s) are great for actual robots but because I only have a single motor connected a breadboard, I changed the method so that the controller’s X/Y axes map from -255 to 255 (the Arduino’s PWM output range).

This is a pretty standard ROS C++ node object. First I define the class header, along with the different public and private methods and variables. Then is the object initializer. Here I set some variable values and create the joystick subscriber and motor publisher, then the parameter method is defined.

Next is the method that does the heavy lifting: the joystick callback. It’s much the same as the previous post, except this time I’ve added a zero-out function for the deadman button. This means that if the joystick is non-zero and the deadman button is released, nothing is sent until the joystick is zeroed out. This behaviour prevents the motor from taking off when the switch is pressed again.

At first I thought merging the two axes together would require complicated math but then the more I thought about it, I realized that since the axes are bound between -1 and 1, it’s a simple matter of adding the axes together so that pushing the stick left/right will add or subtract from the forward motion. Ultimately the left/right axis is about the relative speed between left and right motors. The end result is that moving the stick to the left or right extremes with 0 forward power will spin the robot in place.

The remaining methods offer some utility of constraining output and sending the zero speed message when no joystick data is received after a timeout.

Motor controller

Motor controller on breadboard
The motor controller I’m using is an L298D model from Sparkfun. It’s connected to an Arduino MEGA and 58RPM 12V DC motor. Like most H-bridge controllers, it uses 2 pins to control direction and another for speed using PWM output. In order to make that easier to use, I made a library that takes an integer between -255 and 255 and determines the direction pins automatically. Now the motor callback just needs to feed the message values directly to the library.

The ROS message passed in is custom and is essentially a better labelled 2D vector (left and right).

iPhone monitor

Motor monitor animationWhile not being required for a robot, I thought it would be cool to have an iPhone app to monitor the different robot systems. One of the functions I’ve made is an animated view of the motor inputs. The left and right motors have arrows that show forward and reverse direction and the length of the arrow indicates the Arduino output to the motor. With this view, you can clearly see that moving the joystick to the extreme left and right positions means one motor is full speed forward and the other is full reverse.

The app uses my custom RBManager library, which in turn requires rosbridge to run on the ROS host. The phone is connected via websocket, like a mobile game might be. I hope to make a more fully featured iPad version soon and potentially offer it to the ROS community.

This is only an intro for full motor control but it’s been good to actually see hardware and software play nice together. Next up: closed loop feedback control!

Posted in How to Tagged with: , , , , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

*