Moderators: roger, 99jonathan, imaqine
kirkpthompson wrote:Hi Temp. No, I don't have an example of a line follower implementation using PIDController. Maybe you could provide some specifics on what you are trying to accomplish and we could go from there?
kirkpthompson wrote:Ok... Can you provide your PIDController implementation code?
-K
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import lejos.nxt.Button;
import lejos.nxt.ColorSensor;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.comm.Bluetooth;
import lejos.nxt.comm.NXTConnection;
import lejos.robotics.navigation.DifferentialPilot;
public class PIDLineFollow {
public PIDController pidController;
public float setpoint = 45;
public float deadband = 1;
public float kp = 3.5f;
public float ki = 0.0f;
public float kd = 0.0f;
public float limithigh = 200.0f;
public float limitlow = -200.0f;
public float integrallimithigh = 0.0f;
public float integrallimitlow = 0.0f;
public long dt = 25;
public boolean isThreadStopped = true;
public boolean stopped = false;
public ColorSensor sensor;
public DifferentialPilot pilot;
public PIDLineFollow() {
sensor = new ColorSensor(SensorPort.S1);
sensor.setFloodlight(true);
pilot = new DifferentialPilot(5.6f, 12.6f, Motor.A, Motor.B, false);
pilot.setTravelSpeed(30);
pilot.setRotateSpeed(400);
}
public void setPIDParameters() {
if (pidController != null) {
pidController.setPIDParam(PIDController.PID_SETPOINT, setpoint);
pidController.setPIDParam(PIDController.PID_DEADBAND, deadband);
pidController.setPIDParam(PIDController.PID_KP, kp);
pidController.setPIDParam(PIDController.PID_KI, ki);
pidController.setPIDParam(PIDController.PID_KD, kd);
pidController.setPIDParam(PIDController.PID_LIMITHIGH, limithigh);
pidController.setPIDParam(PIDController.PID_LIMITLOW, limitlow);
pidController.setPIDParam(PIDController.PID_I_LIMITHIGH, integrallimithigh);
pidController.setPIDParam(PIDController.PID_I_LIMITLOW, integrallimitlow);
}
}
public void start() {
new Thread() {
public void run() {
isThreadStopped = false;
pidController = new PIDController((int) setpoint);
setPIDParameters();
while (!stopped) {
int lightvalue = sensor.getLightValue();
int MV = pidController.doPID(lightvalue);
LCD.drawString(lightvalue + " " + MV + " ", 0, 1);
pilot.steer(MV);
try {
Thread.sleep(dt);
} catch (InterruptedException e) {
}
}
pilot.stop();
isThreadStopped = true;
}
}.start();
}
public static void main(String argv[]) {
// 0016530C218B
LCD.drawString("waiting ", 0, 0);
NXTConnection connection = Bluetooth.waitForConnection();
if (connection == null)
return;
PIDLineFollow p = new PIDLineFollow();
LCD.drawString("connected ", 0, 0);
final DataInputStream input = connection.openDataInputStream();
final DataOutputStream output = connection.openDataOutputStream();
try {
while (!Button.ESCAPE.isPressed()) {
int command = input.readInt();
LCD.drawString("command: " + command, 0, 1);
if (PIDConstants.SHUTDOWN_COMMAND == command) {
p.stopped = true;
break;
} else if (PIDConstants.STOP_COMMAND == command) {
p.stopped = true;
} else if (PIDConstants.START_COMMAND == command) {
p.stopped = false;
p.start();
} else if (PIDConstants.WRITE_COMMAND == command) {
int key = input.readInt();
float value = input.readFloat();
if (PIDController.PID_SETPOINT == key) {
p.setpoint = value;
} else if (PIDController.PID_DEADBAND == key) {
p.deadband = value;
} else if (PIDController.PID_KP == key) {
p.kp = value;
} else if (PIDController.PID_KI == key) {
p.ki = value;
} else if (PIDController.PID_KD == key) {
p.kd = value;
} else if (PIDController.PID_LIMITHIGH == key) {
p.limithigh = value;
} else if (PIDController.PID_LIMITLOW == key) {
p.limitlow = value;
} else if (PIDController.PID_I_LIMITHIGH == key) {
p.integrallimithigh = value;
} else if (PIDController.PID_I_LIMITLOW == key) {
p.integrallimitlow = value;
} else if (PIDConstants.TRAVEL_SPEED == key) {
p.pilot.setTravelSpeed((int)value);
} else if (PIDConstants.ROTATE_SPEED == key) {
p.pilot.setRotateSpeed((int)value);
} else if (PIDConstants.INTERVAL == key) {
p.dt = (long) value;
} else {
value = -1;
}
output.writeFloat(value);
} else if (PIDConstants.READ_COMMAND == command) {
int key = input.readInt();
LCD.drawString("key: " + key, 0, 2);
float value = 0;
if (PIDController.PID_SETPOINT == key) {
value = p.setpoint;
} else if (PIDController.PID_DEADBAND == key) {
value = p.deadband;
} else if (PIDController.PID_KP == key) {
value = p.kp;
} else if (PIDController.PID_KI == key) {
value = p.ki;
} else if (PIDController.PID_KD == key) {
value = p.kd;
} else if (PIDController.PID_LIMITHIGH == key) {
value = p.limithigh;
} else if (PIDController.PID_LIMITLOW == key) {
value = p.limitlow;
} else if (PIDController.PID_I_LIMITHIGH == key) {
value = p.integrallimithigh;
} else if (PIDController.PID_I_LIMITLOW == key) {
value = p.integrallimitlow;
} else if (PIDController.PID_I == key) {
value = -999999;
if (p.pidController != null) {
value = p.pidController.getPIDParam(PIDController.PID_I);
}
} else if (PIDConstants.RAW_OUTPUT_MV == key) {
value = -999999;
if (p.pidController != null) {
//value = p.pidController.rawOutputMV;
}
} else if (PIDConstants.LIGHTVALUE == key) {
value = p.sensor.getLightValue();
} else if (PIDConstants.TRAVEL_SPEED == key) {
value = p.pilot.getTravelSpeed();
} else if (PIDConstants.ROTATE_SPEED == key) {
value = p.pilot.getRotateSpeed();
} else if (PIDConstants.MAX_TRAVEL_SPEED == key) {
value = p.pilot.getMaxTravelSpeed();
} else if (PIDConstants.MAX_ROTATE_SPEED == key) {
value = p.pilot.getMaxRotateSpeed();
} else if (PIDConstants.INTERVAL == key) {
value = p.dt;
} else {
value = -1;
}
output.writeFloat(value);
} else {
// unknown command
output.writeInt(-1);
}
output.flush();
}
p.stopped = true;
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
p.stopped = true;
while (!p.isThreadStopped) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import lejos.pc.comm.NXTCommException;
import lejos.pc.comm.NXTCommLogListener;
import lejos.pc.comm.NXTConnector;
public class PIDTuner {
public static int getKey(String name) {
if (name != null) {
name = name.toLowerCase().trim();
}
if ("setpoint".equals(name)) {
return PIDController.PID_SETPOINT;
}
if ("deadband".equals(name)) {
return PIDController.PID_DEADBAND;
}
if ("kp".equals(name)) {
return PIDController.PID_KP;
}
if ("ki".equals(name)) {
return PIDController.PID_KI;
}
if ("kd".equals(name)) {
return PIDController.PID_KD;
}
if ("limithigh".equals(name)) {
return PIDController.PID_LIMITHIGH;
}
if ("limitlow".equals(name)) {
return PIDController.PID_LIMITLOW;
}
if ("integrallimithigh".equals(name)) {
return PIDController.PID_I_LIMITHIGH;
}
if ("integrallimitlow".equals(name)) {
return PIDController.PID_I_LIMITLOW;
}
if ("integral".equals(name)) {
return PIDController.PID_I;
}
if ("rawoutputmv".equals(name)) {
return PIDConstants.RAW_OUTPUT_MV;
}
if ("lightvalue".equals(name)) {
return PIDConstants.LIGHTVALUE;
}
if ("travelspeed".equals(name)) {
return PIDConstants.TRAVEL_SPEED;
}
if ("rotatespeed".equals(name)) {
return PIDConstants.ROTATE_SPEED;
}
if ("maxtravelspeed".equals(name)) {
return PIDConstants.MAX_TRAVEL_SPEED;
}
if ("maxrotatespeed".equals(name)) {
return PIDConstants.MAX_ROTATE_SPEED;
}
if ("interval".equals(name)) {
return PIDConstants.INTERVAL;
}
return -1;
}
public static void main(String argv[]) throws NXTCommException {
String bluetoothAddress = "0016530C218B";
if (argv.length > 0) {
bluetoothAddress = argv[0];
}
NXTConnector connector = new NXTConnector();
connector.addLogListener(new NXTCommLogListener() {
public void logEvent(String message) {
System.out.println("BTSend Log.listener: " + message);
}
public void logEvent(Throwable throwable) {
System.out.println("BTSend Log.listener - stack trace: ");
throwable.printStackTrace();
}
});
boolean connected = connector.connectTo("btspp://" + bluetoothAddress);
if (!connected) {
System.err.println("Failed to connect to any NXT");
System.exit(1);
}
System.out.println("Connected!");
DataOutputStream dos = connector.getDataOut();
DataInputStream dis = connector.getDataIn();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
while (true) {
String line = reader.readLine().toLowerCase();
if ("exit".equals(line)) {
dos.writeInt(PIDConstants.SHUTDOWN_COMMAND);
dos.flush();
break;
}
if ("start".equals(line)) {
dos.writeInt(PIDConstants.START_COMMAND);
dos.flush();
}
if ("stop".equals(line)) {
dos.writeInt(PIDConstants.STOP_COMMAND);
dos.flush();
}
if (line.startsWith("read")) {
int key = getKey(line.substring(4));
if (key != -1) {
dos.writeInt(PIDConstants.READ_COMMAND);
dos.flush();
dos.writeInt(key);
dos.flush();
System.out.println("received: " + dis.readFloat());
} else {
System.out.println("wrong key!");
}
}
if (line.startsWith("write")) {
StringTokenizer tokenizer = new StringTokenizer(line.substring(5));
if (tokenizer.countTokens() == 2) {
int key = getKey(tokenizer.nextToken());
if (key != -1) {
try {
float value = Float.parseFloat(tokenizer.nextToken());
dos.writeInt(PIDConstants.WRITE_COMMAND);
dos.flush();
dos.writeInt(key);
dos.flush();
dos.writeFloat(value);
dos.flush();
System.out.println("received: " + dis.readFloat());
} catch (NumberFormatException e) {
System.out.println("wrong number format!");
}
} else {
System.out.println("wrong key!");
}
} else {
System.out.println("wrong format!");
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
try {
dis.close();
dos.close();
connector.close();
} catch (IOException ioe) {
System.out.println("IOException closing connection");
}
}
}
public interface PIDConstants {
public static int SHUTDOWN_COMMAND = -1;
public static int STOP_COMMAND = 0;
public static int START_COMMAND = 1;
public static int READ_COMMAND = 2;
public static int WRITE_COMMAND = 3;
public static int LIGHTVALUE = 100;
public static int TRAVEL_SPEED = 110;
public static int ROTATE_SPEED = 111;
public static int MAX_TRAVEL_SPEED = 112;
public static int MAX_ROTATE_SPEED = 113;
public static int INTERVAL = 120;
public static int RAW_OUTPUT_MV = 121;
}
kirkpthompson wrote:...
I did notice you have a fairly large intial Kp (P) value. Have you tried to start out with a small value (0.1f) and observe behavior during loop execution? Increase the value until you observe oscillation/instability and back it off some. That is a starting point.
...
NXTDataLogger dlog = new NXTDataLogger();
NXTConnection conn = Bluetooth.waitForConnection(5000, NXTConnection.PACKET);
try {
dlog.startRealtimeLog(conn);
} catch (IOException e) {
// Do nothing
}
// Test passthrough message management and PID tuning framework
LogMessageManager lmm = LogMessageManager.getLogMessageManager(dlog);
PIDController pid = new PIDController(0, 50);
pid.setPIDParam(PIDController.PID_KP, 2);
PIDTuner pidTuner = new PIDTuner(pid, lmm);
... PID control code here ...
package my.lejos.linefollower;
import lejos.nxt.Button;
import lejos.nxt.ColorSensor;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.comm.Bluetooth;
import lejos.nxt.comm.NXTConnection;
import lejos.util.LogMessageManager;
import lejos.util.NXTDataLogger;
import lejos.util.PIDController;
import lejos.util.PIDTuner;
public class LineFollower {
static int SPEED = 200;
public static void main(String[] aArg) throws Exception {
NXTDataLogger dlog = new NXTDataLogger();
NXTConnection conn = Bluetooth.waitForConnection(15000, NXTConnection.PACKET);
try {
dlog.startRealtimeLog(conn);
} catch (Exception e) {
// Do nothing
}
// Test passthrough message management and PID tuning framework
LogMessageManager lmm = LogMessageManager.getLogMessageManager(dlog);
PIDController pid = new PIDController(340, 10);
pid.setPIDParam(PIDController.PID_KP, 2.0f);
// pid.setPIDParam(PIDController.PID_KI, 0.05f);
// pid.setPIDParam(PIDController.PID_KD, 10f);
PIDTuner pidTuner = new PIDTuner(pid, lmm);
Motor.B.setSpeed(SPEED);
Motor.C.setSpeed(SPEED);
Motor.B.forward();
Motor.C.forward();
final ColorSensor detector = new ColorSensor(SensorPort.S2);
while (!Button.ESCAPE.isDown()) {
// range is from 200 to 500
int sensor = detector.getRawLightValue();
//System.out.println(sensor);
int speedDelta = pid.doPID(sensor);
// System.out.println(speedDelta);
Motor.B.setSpeed(SPEED-speedDelta);
Motor.C.setSpeed(SPEED+speedDelta);
}
}
}
Users browsing this forum: No registered users and 0 guests