树莓派WIFI小车java版(三)小车java控制程序(续1)
由于帖子字数实在太多,只能拆出来发贴,接连-- 接上一节内容 (http://www.shumeipai.net/thread-26817-1-1.html)
直流电机控制
直流电机是通过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灯(好吧,上面的介绍中没有,但这不影响整体代码)package org.dreamwork.smart.car.server.component;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import org.apache.log4j.Logger;
import org.dreamwork.smart.car.server.util.Config;
import org.dreamwork.smart.car.server.util.GpioHelper;
import org.dreamwork.smart.car.server.util.Rotate;
import java.io.*;
public class Car implements ServoListener {
private static final int
DIR_FORWARD = 1, DIR_BACKWARD = -1, DIR_STOP = 0,
DIR_TURN_LEFT = -2, DIR_TURN_RIGHT = 2;
/**
* 小车当前运动状态(前进,后退或停止)
*/
private int dir = DIR_STOP;
/**
* 小车上一次的运动状态
*/
private Integer backup_dir = null;
/**
* 小车转动状态(左转,右转,停止)
*/
private Rotate rotate;
/**
* 两路转向灯
*/
private BlinkLED leftLed, rightLed;
/**
* 两路舵机
*/
private Servo servo0, servo1;
/**
* 两路直流电机
*/
private Motor left_front, right_front;
/**
* 摄像头
*/
private Camera camera;
/**
* 配置文件
*/
private Config config;
/**
* 前灯
*/
private GpioPinDigitalOutput led;
private GpioController gpio;
private boolean shutdown = false;
public Car (Config config) throws IOException, InterruptedException {
this.config = config;
setup ();
}
/**
* 初始化
*/
private void setup () throws IOException, InterruptedException {
... // 读取配置文件,初始化各个部件
}
/**
* 使指定的LED灯闪烁
*/
private void toggleBlinkLed (BlinkLED led) {
...
}
/**
* 重置小车的各个状态
*/
public void reset () throws InterruptedException {
stop ();
servo0.reset ();
servo1.reset ();
camera.close ();
}
/**
* 销毁小车的各个部件,释放资源
*/
public void dispose () throws InterruptedException {
...
}
public void toggleLeftBlink () {
...
}
public void toggleRightBlink () {
...
}
public void forward () throws InterruptedException {
...
}
public void backward () throws InterruptedException {
...
}
public void stop () throws InterruptedException {
...
}
public void toggleServoLeft () {
...
}
public void toggleServoRight () {
...
}
public void toggleServoUp () {
...
}
public void toggleServoDown () {
...
}
public void toggleTurnLeft () throws InterruptedException {
...
}
public void toggleTurnRight () throws InterruptedException {
...
}
public void toggleLED () {
led.toggle ();
}
public void toggleCamera () throws IOException {
if (!camera.isOpened ())
camera.open ();
else
camera.close ();
}
public void servoLeft () {
servo0.increase ();
}
public void servoRight () {
servo0.decrease ();
}
public void stopHorizontalRotate () {
servo0.stopRotate ();
}
public void servoUp () {
servo1.decrease ();
}
public void servoDown () {
servo1.increase ();
}
public void stopVerticalRotate () {
servo1.stopRotate ();
}
public boolean isRotateUp () {
return rotate.isRotateUp ();
}
public boolean isRotateLeft () {
return rotate.isRotateLeft ();
}
public boolean isRotateDown () {
return rotate.isRotateDown ();
}
public boolean isRotateRight () {
return rotate.isRotateRight ();
}
}代码较长,抱歉没有更多的注释,不过我想看方法名应该差不多就能理解方法是干什么的了值得一提的是控制转向。我们的小车是四驱的,并没有转向轮,那么如何转向呢?答案是差速转向:当左右两侧轮子的转速不同时,小车就不再沿直线运动了。设小车左轮的速度为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;
}
}
-- 还是写不下所有内容,只能再次拆楼。预告剩余内容包含:
[*]网络监听部分
[*]基于swing的测试前端
[*]成品效果图和视频
不要走开哦
页:
[1]