kirkpthompson wrote:Ok... Can you provide your PIDController implementation code?
-K
I wanted to tune the variables over the bluetooth connection. Here is my code:
For NXT:
- Code: Select all
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) {
}
}
}
}
For the PC (you must configure also the bluetooth address of the used NXT):
- Code: Select all
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");
}
}
}
Some constants used both on PC and NXT:
- Code: Select all
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;
}
How to use it:
* Deploy PIDLineFollow on the NXT
* Start PIDTuner on PC
** Now we can read and write variables on the NXT ie.: "read setpoint" or "write kp 11.0" etc.
*** Following variables are available: setpoint, deadband, kp, ki, kd, limithigh, limitlow, integrallimitlow, integrallimithigh, integral, lightvalue, travelspeed, rotatespeed, interval
** After variable configuration, we can start and stop the lego with "start" or "stop"
** After "stop" we can configure variables again
** If "exit" called, the NXT is shutdown.
My problem is: I cant tune the variables properly.
best regards
temp