@bryanpearson
There are some problems with the control showing the error value and I haven't found it yet..
You can do amazing things with Processing but when you should make a good GUI you half to make all controls from the ground and that takes more time than making it to what you really want. A balancing bot GUI...
I have moved on and start porting it to .net c# to be able to put more focus on the application than the individual controls.
@kas
I have also expremented with the communication between the bot and the computer and made a test program that seams to work. I will try it in my bot when the new one is finished. The last parts should com in the next week..
#define GYR_Y 0 // Gyro Y (IMU pin #4)
#define ACC_Z 1 // Acc Z (IMU pin #7)
#define ACC_X 2 // Acc X (IMU pin #9)
#define LINE_END 10 // \n
#define SPLIT 58 // :
int STD_LOOP_TIME = 9;
int sensorValue[3] = { 10, 11, 12};
int sensorZero[3] = { 0, 0, 0 };
int lastLoopTime = STD_LOOP_TIME;
int lastLoopUsefulTime = STD_LOOP_TIME;
unsigned long loopStartTime = 0;
int actAngle; // angles in QUIDS (360° = 2PI = 1204 QUIDS <<<
int ACC_angle;
int GYRO_rate;
int setPoint = 0;
int drive = 0;
int error = 0;
int updateRate = 0; //Nr of loop to skip sending and receving info from PC
long count = 0;
long last_count = 0;
float K = 1.4;
int Kp = 3;
int Ki = 1;
int Kd = 6;
int Kp_Wheel = 1;
int Kd_Wheel = 1;
int last_error = 0;
int integrated_error = 0;
int pTerm = 0, iTerm = 0, dTerm = 0;
int pTerm_Wheel = 0, dTerm_Wheel = 0;
int error_message = 0;
float motorOffsetL = 1; //The offset for left motor
float motorOffsetR = 1; //The offset for right motor
byte buffer[55];
void setup() {
Serial.begin(115200);
//Serial.begin(19200);
buffer[0] = char('#');
sendErrorToBuffer(1);
}
void loop() {
// ********************* print Debug info *************************************
//serialOut_raw();
//serialOut_timing();
serialIn_GUI(); //Processing information from a pc
serialOut_GUI(); //Sending information to pc for debug
// *********************** loop timing control **************************
lastLoopUsefulTime = millis()-loopStartTime;
if(lastLoopUsefulTime<STD_LOOP_TIME) delay(STD_LOOP_TIME-lastLoopUsefulTime);
if(lastLoopUsefulTime>STD_LOOP_TIME) sendErrorToBuffer(1); //Sends error to GUI
lastLoopTime = millis() - loopStartTime;
loopStartTime = millis();
}
int serial_type=0;
uint8_t loop_count=0;
void serialOut_GUI() {
if(error_message == 0)
{
//send PID values
addIntToBuffer(1, pTerm);
addIntToBuffer(3, iTerm);
addIntToBuffer(5, dTerm);
addIntToBuffer(7, error);
addIntToBuffer(9, pTerm_Wheel);
addIntToBuffer(11, dTerm_Wheel);
//send PID parameter values
addFloatToBuffer(13, K);
addIntToBuffer(17, Kp);
addIntToBuffer(19, Ki);
addIntToBuffer(21, Kd);
addIntToBuffer(23, Kp_Wheel);
addIntToBuffer(25, Kd_Wheel);
//send Sensor values
//send Angel values
addIntToBuffer(27, ACC_angle);
addIntToBuffer(29, actAngle);
addIntToBuffer(31, sensorValue[ACC_X]);
addIntToBuffer(33, sensorValue[ACC_Z]);
addIntToBuffer(35, sensorValue[GYR_Y]);
//send Torque values
addIntToBuffer(37, drive);
addFloatToBuffer(39, motorOffsetL);
addFloatToBuffer(43, motorOffsetR);
//send Settings values
addIntToBuffer(47, setPoint);
addIntToBuffer(49, STD_LOOP_TIME);
addIntToBuffer(51, lastLoopUsefulTime);
addIntToBuffer(53, lastLoopTime);
Serial.write(buffer,55);
}else{
sendErrorToBuffer(error_message);
}
}
void serialIn_GUI(){
byte id;
if(Serial.available() > 0){
byte param = Serial.read();
delay(10);
byte inByte[Serial.available()];
if(Serial.read() == SPLIT){
switch (param) {
case 1:
if(Serial.available() >= 2){
Kp = readIntFromBuffer();
}
break;
case 2:
if(Serial.available() >= 2){
Ki = readIntFromBuffer();
}
break;
case 3:
if(Serial.available() >= 2){
Kd = readIntFromBuffer();
}
break;
case 4:
if(Serial.available() >= 4){
K = readFloatFromBuffer();
}
break;
case 5:
if(Serial.available() >= 2){
setPoint = readIntFromBuffer();
}
break;
case 6:
if(Serial.available() >= 4){
motorOffsetL = readFloatFromBuffer();
}
break;
case 7:
if(Serial.available() >= 4){
motorOffsetR = readFloatFromBuffer();
}
break;
case 8:
if(Serial.available() >= 2){
Kp_Wheel = readIntFromBuffer();
}
break;
case 9:
if(Serial.available() >= 2){
serial_type = readIntFromBuffer();
}
break;
case 10:
if(Serial.available() >= 2){
Kd_Wheel = readIntFromBuffer();
}
break;
case 11:
if(Serial.available() >= 2){
error_message = readIntFromBuffer();
}
break;
} //End switch
} //if(Serial.read() == SPLIT)
} //if(Serial.available() > 0)
}
union u_tag {
byte b[4];
float fval;
} u;
void addIntToBuffer(int index, int value)
{
buffer[index] = lowByte(value);
buffer[index + 1] = highByte(value);
}
void addFloatToBuffer(int index, float value)
{
u.fval = value;
buffer[index] = u.b[0];
buffer[index + 1] = u.b[1];
buffer[index + 2] = u.b[2];
buffer[index + 3] = u.b[3];
}
void sendErrorToBuffer(int error){
byte buffer_error[3];
error_message = error;
buffer_error[0] = char('!');
buffer_error[1] = lowByte(error);
buffer_error[2] = highByte(error);
Serial.write(buffer_error, 3);
}
int readIntFromBuffer(){
uint8_t lsb = Serial.read();
uint8_t msb = Serial.read();
Serial.flush();
return (lsb + (msb <<8));
}
float readFloatFromBuffer(){
u.b[0] = Serial.read();
u.b[1] = Serial.read();
u.b[2] = Serial.read();
u.b[3] = Serial.read();
Serial.flush();
return u.fval;
}
I have added a error handler so we can send errors to the GUI that you half to acknowledged by sending a 0 value to the error_message to get it to stop sending the error to the GUI..
What do you think about it so far? The code is real dirty but I think you understand it.. The loop time is around 4-6ms when running it...