-- 接楼上
直流电机控制
直流电机是通过L298N控制板进行控制的。一块L298N控制板可以同时控制2路直流电机,其中,每路直流电机需要3根脚进行控制,一根使用PWM信号控制电机的转速,2路数字信号控制电机的转动状态,请参见下表
了解L298N的控制方式后,控制代码比较简单。 - package org.dreamwork.smart.car.server.component;
- public class Motor {
- private GpioPinDigitalOutput pin0, pin1;
- private PWM pwm;
- private int speed = 3;
- public static final int MAX_SPEED = 5, MIN_SPEED = 0;
- public Motor (GpioPinDigitalOutput pin0, GpioPinDigitalOutput pin1, PWM pwm) {
- this.pin0 = pin0;
- this.pin1 = pin1;
- this.pwm = pwm;
- }
- public int getSpeed () {
- return speed;
- }
- public void setSpeed (int speed) {
- if (speed < MIN_SPEED) speed = MIN_SPEED;
- if (speed > MAX_SPEED) speed = MAX_SPEED;
- this.speed = speed;
- // 将速度映射为PWM占空比
- pwm.setValue (.2f * speed);
- }
- public void forward () {
- pin0.high ();
- pin1.low ();
- }
- public void backward () {
- pin0.low ();
- pin1.high ();
- }
- public void stop () {
- pin0.low ();
- pin1.low ();
- }
- public void dispose () {
- pin0.low ();
- pin1.low ();
- pwm.setValue (0);
- }
- }
复制代码
增加转向灯
这部分对于小车运动控制来说,不是必须的,但可以增加趣味性,同时更加接近现实情况:当车辆转弯时转向灯同时闪烁,指示车辆转弯的方向。 这部分的代码相当简单,就是控制一个LED灯的闪烁,唯一不同的事,采用线程,使得LED的闪烁不影响主线程(小车控制命令接收线程) - package org.dreamwork.smart.car.server.component;
- import com.pi4j.io.gpio.GpioPinDigitalOutput;
- import org.apache.log4j.Logger;
- import org.dreamwork.smart.car.server.util.GpioHelper;
- import org.dreamwork.smart.car.server.util.PausableThread;
- /**
- * Created by seth.yang on 2015/6/8.
- */
- public class BlinkLED extends PausableThread {
- private GpioPinDigitalOutput pin;
- public BlinkLED (int pinIndex) {
- super (true);
- pin = GpioHelper.getDigitalOutputPin (pinIndex);
- }
- public boolean isBlinking () {
- return !paused;
- }
- public void blink () {
- proceed ();
- }
- @Override
- protected void doWork () {
- try {
- pin.high ();
- sleep (300);
- pin.low ();
- sleep (300);
- } catch (Exception ex) {
- // process exception
- }
- }
- }
复制代码
摄像头
这个和java关系不大,和GPIO也没关系。通过java调用mjpg-streamer就行了。
拼装小车控制程序
小车动作控制部分介绍完了,可以将这些代码拼装成一台完整的小车了。 我们的小车需要: l 两路舵机,用于控制摄像头的转动 l 四路直流电机(实际上我只用了两路,记得吗,我将左右两侧的2个电机并联了) l 四路转向灯(实际上是也是两路,同上) l 一路照明LED灯(好吧,上面的介绍中没有,但这不影响整体代码)
代码较长,截取了其中public的方法,抱歉注释不多,不过看名字应该能看懂方法的含义。
值得一提的是控制转向。我们的小车是四驱的,并没有转向轮,那么如何转向呢?答案是差速转向:当左右两侧轮子的转速不同时,小车就不再沿直线运动了。 设小车左轮的速度为VL,右轮的转速为VR,那么理论上: n 当VL = VR时,转弯半径为无穷大(直线) n 当VL > VR>0时,小车右转,转弯半径 > 轴距 n 当VL > VR=0时,小车右转,转弯半径 = 轴距 n 当 VR = -VL时,小车右转,转弯半径 = 0 反之左转 我们的转弯代码取其中一种(我取的是一侧速率为0的方式,这取决于电机的减速比和轮胎的抓地力,如果电机减速比较小或轮胎抓地力较小,建议取VR = -VL,进行原地转弯) - ...
- // 一侧速率为0的转弯方式
- private void turnLeft () throws InterruptedException {
- left_front.setSpeed (5);
- right_front.setSpeed (5);
- if (dir == DIR_BACKWARD) {
- left_forward ();
- right_pause ();
-
- } else {
- left_pause ();
- right_forward ();
- }
- leftLed.blink ();
- }
- // 原地转弯的方式
- private void turnLeft () throws InterruptedException {
- left_forward ();
- right_backward ();
- leftLed.blink ();
- }
- ...
复制代码
指令
我们需要指令,来和小车的动作一一对应,枚举它就行了 - package org.dreamwork.smart.car.server.io;
- public enum Command {
- DISPOSE (-2, false),
- QUIT (-1, false),
- STOP ( 0, false),
- FORWARD (1, false),
- BACKWARD (2, false),
- TURN_LEFT (3, false),
- TURN_RIGHT (4, false),
- TOGGLE_LED (5, false),
- TOGGLE_CAMERA (6, false),
- TOGGLE_LEFT_BLINK (7, false),
- TOGGLE_RIGHT_BLINK (8, false),
- STOP_VERTICAL_SERVO (9, false),
- STOP_HORIZONTAL_SERVO (10, false),
- SPEED (11, false),
- SERVO_UP (12, false),
- SERVO_RIGHT (13, false),
- SERVO_DOWN (14, false),
- SERVO_LEFT (15, false),
- LEFT_FORWARD (101, false),
- LEFT_BACKWARD (102, false),
- LEFT_PAUSE (103, false),
- RIGHT_FORWARD (104, false),
- RIGHT_BACKWARD (105, false),
- RIGHT_PAUSE (106, false),
- RESET (501, false)
- ;
- public final int code;
- public final boolean hasReturn;
- private Command (int code, boolean hasReturn) {
- this.code = code;
- this.hasReturn = hasReturn;
- }
- }
复制代码
-- 看来2楼还是无法完全放下全部内容,代码贴的有点多,呵呵,下面还有一楼,介绍本篇剩余的内容,不要走开哦
|