Need clarification on proper format of multi-tasking with threads?
Your code is confused. Topics to go read up on:
Assignment to a variable. Specifically, that it happens once and is not continuous (as you appear to be trying to do with your joystick global variables).
Function declaration. You donât know the syntax for starters, but youâve also written 9 functions that could be accomplished by 3. I.e., you donât need a function for every joystick axis, you need a single function that is passed the value of a joystick axis and returns a modified value:
int add_one (int x) { return x + 1; }
Next, you declare threads in a loop. The best use of threads is to accomplish some specific task that would be onerous to accomplish without them. The functions you are trying to seed these threads with have no blocking elements in them (in the code you have provided, anyway), and could be done synchronously just as easily. Even if there were blocking elements, creating additional threads to do the same task before the first ones have finished would result in them stepping on each othersâ toes and malfunctioning.
Lastly for now, as a matter of convention, definitions donât go in .h files, only declarations. You would put the definitions you have in âdrive.hâ into a âdrive.cppâ instead, and replace the definitions in âdrive.hâ with forward declarations.
My recommendation for you is forget that threads exist for now and focus on walking before you run.
Tyler
Thank you for the advice. I will take your suggestions to improve my code.
As the programmer for our team, I have considered your reply and updated some code accordingly. I believe it matches your suggestions.
However there is still a problem of a âparameter inputâ issue. The problem is probably due, we are assuming, to a data type mis-match. It is a challenge, you might help.
This is one of the questions we were asking in the original post. The other question, was a inquiry for conformation that our team was using threading correctly.
Thank you.
Iâll be sure to take a look for you tomorrow.
v5code-project-650N.zip (15.1 KB)
Thank you for your offer to help.
I was able to fix the errors by adding input type in your functions.
This input doesnât state the type:
double ceil_drive_lval( drive_lval ){
but this one does:
double ceil_drive_lval( int drive_lval ){
Additionally, when you call the functions you just write their names like this:
LFmotor.spin( directionType::fwd, cube_drive_lval, velocityUnits::pct );
but when you call a function it needs parentheses for inputs like so:
LFmotor.spin( directionType::fwd, cube_drive_lval(5), velocityUnits::pct );
Looking at your functions it appears you are just returning controller values. I donât see a use for inputs. Therefore, another solution would be to remove the input:
double cube_drive_lval(){
return pow(ceil_input_lval/100.0, 3.0)*100.0;
}
LFmotor.spin( directionType::fwd, cube_drive_lval(), velocityUnits::pct );
EDIT:
Also note if you intend to have an input it must be reflected in your header
v5code-project-650N.zip (15.5 KB)
@John_TYler @deicer Thank you for the suggestions.
Updated project, possible solution.
Any feedback will be appreciated.
Your variables are not being updated through the loop. Instead, theyâll spin however fast the initial read told it to. One way would be to add this in your main loop:
while(true){ //this is the loop you already have, don't copy the loop into your loop.
ceildrive_lval = ceil_drive_lval(drive_lval);
ceildrive_rval = ceil_drive_rval(drive_rval);
cubedrive_lval = cube_drive_lval(ceildrive_lval);
cubedrive_rval = cube_drive_rval(ceildrive_rval);
//rest of code
}
Thisâll update the value continually so the motors can change their velocity.
However, I think you have more variables then you need. You could just call a single function in the motor spin command. Hereâs what I got when I combined your functions and called them in the motor spin command (with a slightly reworked while loop):
//couldn't find function 'ceil'. It can probably be added here as well.
double unifiedTheoryOfPotatoes(double drive_val){
double var = ceil(drive_val);
return(pow(var/100.0, 3.0)*100.0);
}
//not returning anything, I'll make this function a void.
void tankDrive_F(){
double leftPow;
double rightPow;
while(1){
//note these next 2 lines specifically. It's in the while loop so it'll update the motor power.
leftPow = unifiedTheoryOfPotatoes(drive_lval);
rightPow = unifiedTheoryOfPotatoes(drive_rval);
LFmotor.spin( directionType::fwd, leftPow, velocityUnits::pct );
LBmotor.spin( directionType::fwd, leftPow, velocityUnits::pct );
RFmotor.spin( directionType::fwd, rightPow, velocityUnits::pct );
RBmotor.spin( directionType::fwd, rightPow, velocityUnits::pct );
}
}
As you can see itâs a lot simpler and cuts out your middleman variables/functions. Obviously you wouldnât call your function âtheFundementalTheoryOfPotatoesâ, but you get the idea.
I would add vex::task::sleep(10)
to any while(1) loop to make sure you are not hogging CPU.
But I still donât understand how you set values to drive_lval and drive_rval and why would you need to run this in the separate thread?
Why is it not good enough to have a single user control while(1) loop inside usercontrol() function that reads Controller.Axis values and commands motors?
Now that I learned the âsecret knowledgeâ, I totally would!
seems like you had some good feedback today. I think your issues come from not understanding the difference between local and global variables and how/when they get updated. Hereâs a revised version of your tank drive code, many of the variables you had as global need to be local and updated within the while loop, assignment to a variable only happens when the line of code is executed, assignment outside of all functions and threads would only happen once when the program is executed, and functions are not even called at that time.
tankDrive.cpp
/*----------------------------------------------------------------------------------------*/
/* */
/* Module: tankDrive.cpp */
/* Author: NMS_RP: 650N */
/* Created: 16 Dec 2019 */
/* Description: tank drive with deadband and cubic power input for VEX V5 */
/* */
/*----------------------------------------------------------------------------------------*/
// VEX V5 C++ Project
#include "vex.h"
using namespace vex;
// deadband threshold
const int deadband = 15;
/**
* --- Cubic Scale Factor Functions for Power Adjustment ---
* Description: Functions used to achieve more sensitivity at low motor power
* used for precise movements while still being able to use 100% power
*
*/
// ceiling function, function definition, function call
double ceil_drive_lval( double drive_lval ){
return ceil(drive_lval);
}
double ceil_drive_rval( double drive_rval ){
return ceil(drive_rval);
}
// cube function, function definition, function call
double cube_drive_lval( double ceildrive_lval ){ // tank drive cube scale factor left joy
return pow(ceildrive_lval/100.0, 3.0)*100.0;
}
double cube_drive_rval( double ceildrive_rval ){ // tank drive cube scale factor right joy
return pow(ceildrive_rval/100.0, 3.0)*100.0;
}
/**
* --- tankDrive_f is a callback function ---
* func to be registered to a thread
* func registered to thread tankdrive_t
*
*/
int tankDrive_f(){
int count = 0;
while(true){
Brain.Screen.setCursor(1,1);
Brain.Screen.print("TankDrive has iterated %d times", count);
count++;
// tank drive func --- variable intializations
double drive_lval = Controller1.Axis3.position(); // tank drive control
double drive_rval = Controller1.Axis2.position(); // tank drive control
// deadband, set to 0 if below the deadband value
if( fabs( drive_lval ) < deadband ) drive_lval = 0;
if( fabs( drive_rval ) < deadband ) drive_rval = 0;
double ceildrive_lval = ceil_drive_lval( drive_lval );
double ceildrive_rval = ceil_drive_rval( drive_rval );
double cubedrive_lval = cube_drive_lval( ceildrive_lval );
double cubedrive_rval = cube_drive_rval( ceildrive_rval );
// just for fun, display the values
Brain.Screen.setCursor(3,1);
Brain.Screen.print("Raw %6.2f cube %6.2f", drive_lval, cubedrive_lval );
Brain.Screen.setCursor(4,1);
Brain.Screen.print("Raw %6.2f cube %6.2f", drive_rval, cubedrive_rval );
/* --- send to motors --- */
// left tank motors
LFmotor.spin( directionType::fwd, cubedrive_lval, velocityUnits::pct );
LBmotor.spin( directionType::fwd, cubedrive_lval, velocityUnits::pct );
// right tank motors
RFmotor.spin( directionType::fwd, cubedrive_rval, velocityUnits::pct );
RBmotor.spin( directionType::fwd, cubedrive_rval, velocityUnits::pct );
/* You must sleep threads by using the 'this_thread::sleep_for(unit in
msec)' command to prevent this thread from using all of the CPU's
resources. */
this_thread::sleep_for( 25 );
}
/* A threads's callback must return an int, even though the code will never
get here. You must return an int here. Threads can exit, but this one does not. */
return 0;
}
@jpearman Awesome, Thank you for the clarifications.
@deicer Thank you for the help. Suggestions were greatly appreciated.