Hi everybody! My first post here, i hope it will yield some good results :)
Im planning to begin work on my DIY ROV, something pretty similar to work mr. Thomas J Coyle II is doing over here
I havent started any "actual work" except "designing" my thruster control software/hardware, im beginner wit Arduinos and C++, but i have a decent background in PHP/ORACLE so i'm not stranger to programming languages...
If everything works out as i imagined i will be using two arduinos, UNO topside and MEGA underwater... UNO will receive joystick data, process it and sent it over ether-net to MEGA which will control ESC-s and gather sensory data that will be sent back to UNO or PC.
I started my work on collecting and processing joystick information, and im stuck on processing part :) i don't know which approach to take for thruster control... i couldn't find any code/algorithm for vectored configuration online, any advice will be much appreciated!
What i got so far, im getting joystick readings and trying to process what is happening, moving forward, backwards etc...
//generic deadband limits - not all joystics will center at 512, so these limits remove 'drift' from joysticks that are off-center.
int DEADBANDLOW = 460; //Decrease this value if drift occurs, increase it to increase sensitivity around the center position
int DEADBANDHIGH = 564; //Increase this value if drift occurs, decrease it to increase sensitivity around the center position
int joyval_fb = evt->y; //forward and backward 0-1023
if (joyval_fb >= DEADBANDLOW && joyval_fb <= DEADBANDHIGH){
//idle
}
//FORWARD
if (joyval_fb < DEADBANDLOW) {
//code for moving forward
}
//BACKWARD
if (joyval_fb > DEADBANDHIGH) {
//code for moving backwards
}
Am i on a right track, or did i miss it by a mile?
Thanks!
Replies
Hi Vadran
Interesting project, I worked as a control engineer for one of the world's leading ROV manufacturers and developed the control code for their ROV's. The vectored configuration is standard layout for many work class ROVs, providing flexible thrust arrangement avoiding interference with equipment mounted in the ROV frame. I also developed auto positioning control routines which were incorporated in to the vehicle control loop. I am unable to give you the code directly for commercial reasons, but could prepare a pseudo-code explanation with algorithms showing how the routines worked to help you forward ...
Best regards
Martin
Hi Vedran,
The basic control code runs something like this ...
ROV Control (4 thrust vectored)
//Input:
//Joystick Controls, Fwd/Aft, Port/Stbd and Rotate L/R
// Convention +ve fwd and stbd
// Need to arrange (or adjust demands) to ensure thrust is in correct direction according to configuration of each // // motor i.e. when fwd demand, thrust pushes aft
float fDemand_fa;
float fDemand_ps;
float fDemand_ro;
// Output:
int pfh; // port front horizontal
int sfh; // stbd front horizontal
int prh; // port rear horizontal
int srh; // port rear horizontal
// Inputs should be corrected to square joystick if using circular type, i.e. when at quadrants you should be able to // attain 100% in both axis.
// Inputs scaled to +- 100%
// Set a deadband around the zeros (adjustable) to minimise continuous demand if just off zero
pfh = fDemand_fa + fDemand_ps + fDemand_ro;
sfh = fDemand_fa - fDemand_ps - fDemand_ro;
prh = fDemand_fa - fDemand_ps + fDemand_ro;
srh = fDemand_fa + fDemand_ps - fDemand_ro;
// Gate outputs to MAX_VALUE or MIN_VALUE according to hardware limits
// Auto routines could be implemented using motion sensors, (ROV usually use DVL and INS for position holding)
//
// The routine is simple and effective and can easily be adapted to include enhanced functionality.
Hope this is of use, give it a try look forward to seeing the finished product ...
Best regards
Martin
Hi Martin!
Of course, that would be much appreciated!
Hi Martin,
I think that the pseudo-code with the accompanying control algorithms would benefit all of the members on ArduBoat that are building their own hobby ROVs.
Regards,
Tom C AVD
Hi Tom
Yes, for sure, It will take me a day or two to dig out the details but will post it when I can. I am interested to see the progress you guys are making.
Best regards
Martin
Vedran,
It will be easier to understand if you can map your 0-1023 joystick value to something like +/- 400 (which will work well with forward/reverse ESCs and makes more logical sense for forward and reverse with the negative sign).
I'm also going to assume that the thrusters are oriented like Tom has on his ROV, except with the front thrusters flipped around (which will provide more even thrust forward and backward). I'll also use the standard aircraft coordinate frame with forward being positive and strafing to the right being positive. Moving in reverse and strafing left are negative. Yaw is positive when clockwise as viewed from above.
int forward_command = 0; // -400 to 400 from joystick
int strafe_command = 0; // -400 to 400 from joystick
int yaw_command = 0; // -400 to 400 from joystick
float fwd_factor = 1.41;
float strafe_factor = 1.41;
float yaw_factor = 0.2;
int base_command = 1500; // Value that will set motors to stopped
frontLeftThruster = base_command - fwd_factor*forward_command - strafe_factor*strafe_command - yaw_factor*yaw_command;
backLeftThruster = base_command + fwd_factor*forward_command - strafe_factor*strafe_command + yaw_factor*yaw_command;
backRightThruster = base_command + fwd_factor*forward_command + strafe_factor*strafe_command - yaw_factor*yaw_command;
frontRightThruster = base_command - fwd_factor*forward_command + strafe_factor*strafe_command + yaw_factor*yaw_command;
// Code to output those values to the thrusters
The forward, strafe, and yaw factors will be based on the angle of the thrusters and how strongly you want them to react to input. I set the forward and strafe at 1.41, which is 1/sin(45 deg) to scale them to the same force they would provide if they were oriented straight along the forward or strafe axis. The yaw factor is arbitrary right now.
If im gona be using your ESC with:
Max forward being 1900 microseconds
Max reverse being 1100 microsecond
How do i remap Thruster values to constrain them to those, what are MAX and MIN for those if using -400 to 400 scale..
In neutral joystick position it is reading all around 1500 with a bit of drift, but with full forward jostick position im reading:
frontLeftThruster: 933
frontRightThruster: 938
backLeftThruster: 2074
backRightThruster: 2053
p.s. Sorry if i am asking stupid questions but i'm new to all this and learning as i go :)
@Vedran,
Not to worry. The only stupid question is the one that is not asked:-)
You would use the Arduino "map" function to map the ESC PWM range to the +/-400 joystick scale.
Regards,
Tom C AVD
Thanks for fast answer Thom!
Im a bi lost now because Rusty said that a i have to map my joistick values (ranging from 0 to 1023) to -400 to 400 range, if im understanding it right i should map them to 1100 - 1900 range? Wouldn't that ruin the formula if it is intended to work with lower range?
This is how i done it now:
int joyval_fb = evt->y; //forward and backward
int joyval_lr = evt->x; //left and right
int joyval_vertical = evt->slider; //vertical
int joyval_yaw = evt->twist; //YAW
int forward_command = map(joyval_fb,0,1023,400,-400);
int strafe_command = map(joyval_lr,0,1023,-400,400);
int yaw_command = map(joyval_yaw,0,255,-400,400);
float fwd_factor = 1.41;
float strafe_factor = 1.41;
float yaw_factor = 0.2;
int base_command = 1500; // Value that will set motors to stopped
int frontLeftThruster = base_command - fwd_factor*forward_command - strafe_factor*strafe_command - yaw_factor*yaw_command;
int backLeftThruster = base_command + fwd_factor*forward_command - strafe_factor*strafe_command + yaw_factor*yaw_command;
int backRightThruster = base_command + fwd_factor*forward_command + strafe_factor*strafe_command - yaw_factor*yaw_command;
int frontRightThruster = base_command - fwd_factor*forward_command + strafe_factor*strafe_command + yaw_factor*yaw_command;
// Code to output those values to the thrusters
Serial.print("frontLeftThruster: ");
Serial.print(frontLeftThruster);
Serial.print(" frontRightThruster: ");
Serial.print(frontRightThruster);
Serial.print(" backLeftThruster: ");
Serial.print(backLeftThruster);
Serial.print(" backRightThruster: ");
Serial.print(backRightThruster);
Serial.println("");
delay(30);
Vedran,
The code I wrote as an example is pretty simple. You are correct that for large inputs in two axes simultaneously, the outputs will become saturated. This is equivalent to what happens on a quadcopter when you go to full throttle for maximum climb - you don't have any margin left for stability and control. Quadcopter code, of course, includes features to account for this, like a control margin or dynamic adjustment of throttle to maintain control margin.
The simplest way to resolve this is to reduce the mixing factors. For instance, you could make fwd_factor and strafe_factor both 0.4 and yaw_factor 0.1. That would leave enough margin to yaw even with a maximum forward and strafe input. Of course, that will also limit your maximum speed in each direction.
The better way to resolve it would be to change things dynamically. For instance, allow a full forward input, but if the user tries to then yaw simultaneously, the forward input is reduced to allow margin for the yawing.
Also, you are mapping the values to -400 to 400 since you are multiplying them by a factor. If you instead mapped from 1100 to 1900, then an input of 1400 would be multiplied by 1.41 and would become 1975, changing direction unintentionally!
The "base_command" value takes care of shifting the values back to the 1100-1900 range.
Hope that helps!
-Rusty