239 views

# Coding variables in vcs

1. last week

### mvas8037

Jan 8

I was wondering if there is a way to sleep a task for an exact amount of time which is based on the task above. For instance, I want a motor to spin 720 degrees at 50 pct velocity, without doing a guess and check which can get tedious with a large list of operations, how would you code a variable that sleeps the task until say 20 milliseconds after the above task has been completed. Keep in mind this will be for various motor operations, not just the for a 720 degree rotation at 50 pct velocity.

### Answered by callen

See post in context

How about this?

```void driveTrainForward (int numTiles, int pctSpeed) {
int degreesToRotate = (360 * oneTile) / circumference * numTiles;
LeftDriveFront.startRotateFor(degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
RightDriveFront.startRotateFor(-degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
LeftDriveBack.startRotateFor(-degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
RighDriveBack.RotateFor(degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
}```

You then call this function

`driveTrainForward (how many tiles, how fast);`

I think you had "constant" for the number of tiles, which I wrote as "numTiles" to be clearer. I also don't like "pct" when there are other "pct's" so I called it "pctSpeed." When you call this function it will turn on all four motors, rotate them to where you want to go, and pause the code in the task that calls it until it has gotten there.

Then after calling this function you do whatever you wanted when you get there. So if you want a 20 ms delay, maybe to stop some shaking, and then something else, you would have

```driveTrainForward (how many tiles, how fast);
task.sleep(20);
something else;```
2. ### jpearman

Jan 8 Moderator, ROBOTC Tech Support, V5 Beta Moderator Los Angeles 8888
Edited last week by jpearman

could you provide some more details. Most of the motor "goto" functions such as rotateTo will block until they are finished, you can then just add a delay after they return if you need to wait 20mS before doing another operation. If you need to synchronize with another task/thread, you could use vex::semaphore.

3. ### callen

Jan 8 Braintree, MA, USA
Edited last week by callen

How about a mutex or semaphore? Lock it in the earlier task. In that task, as its last lines once it's done you delay it from ending before unlocking:

```...
vex::task.sleep(20)
vex::mutex.unlock()```

Then in the task to be delayed you delay until there it is unlocked:

```while(vex::mutex.try_lock==false){
vex::task.sleep(5)
}```

Or just don't do this in two separate tasks. Do they really need to be?

4. ### mvas8037

Jan 9

@jpearman could you provide some more details. Most of the motor "goto" functions such as rotateTo will block until they are finished, you can then just add a delay after they return if you need to wait 20mS before doing another operation. If you need to synchronize with another task/thread, you could use vex::semaphore.

The problem is that I need 4 motors to synchronize and stop at the same time. I use non-blocking code for this but I this is gonna be variable since it's for autonomous and I coded it in one of the methods I made. I'll post an example of what I'm trying to do. In the driveTrainForward, I want the task to sleep for the amount of time it takes for a motor to spin to the target position I have coded but it should be able to change because when I call the method the target position changes to what I have set. So instead once the motor spins to the desired location which changes depending on the distance I want it to go, the task will sleep for that exact time and maybe a 20 millisecond added delay. I don't know if that made sense. I also used an "if" statement for the sleep command which won't work but it's easier to understand what I'm trying to accomplish.

5. ### mvas8037

Jan 9

@callen How about a mutex or semaphore? Lock it in the earlier task. In that task, as its last lines once it's done you delay it from ending before unlocking:

```...
vex::task.sleep(20)
vex::mutex.unlock()```

Then in the task to be delayed you delay until there it is unlocked:

```while(vex::mutex.try_lock==false){
vex::task.sleep(5)
}```

Or just don't do this in two separate tasks. Do they really need to be?

I'm not sure what a semaphore or mutex is. Could you explain what it does simply? I've been teaching myself how to code by the way and I'm relatively new.

6. ### Gary Patel

Jan 9

As far as I can tell from your code you can just change the startRotateTo to rotateFor and just stop the motors after that. That way it will rotate the correct distance and you don’t need a wait time.

7. ### callen

Jan 9 Braintree, MA, USA
Edited last week by callen

@mvas8037 I'm not sure what a semaphore or mutex is. Could you explain what it does simply? I've been teaching myself how to code by the way and I'm relatively new.

The basic idea is that you have a variable that you can lock so that only one task/thread can change it at a time. So in your drive thread you lock it. When you reach your target, you put in a small delay and then unlock it. The other thread isn't really idle, it just keeps waiting until the variable becomes unlocked. Only once that variable becomes unlocked does it do anything. But it seems like you're really overcomplicating things. Why not just use a function that calls the function to move as a regular function and then follows it with the next function?

@mvas8037 I also used an "if" statement for the sleep command which won't work but it's easier to understand what I'm trying to accomplish.

Well, for starters, you have far more "(" than ")." Also, what are you trying to return from the if statement? It looks like you're setting a value to rightF, but never really comparing anything; note the difference between "=" and "==" in that line. And then you're not doing anything with the "if." Finally, it seems like you want "while," not "if." Something maybe more like this:

```while (rightDriveBack.rotation(rotationUnits::deg) < rightF){
task.sleep(10);
}```

If you do want to use in-line if statements, try looking up ternary operators in C++.

8. ### callen

Jan 9 Braintree, MA, USA

@Gary Patel As far as I can tell from your code you can just change the startRotateTo to rotateFor and just stop the motors after that. That way it will rotate the correct distance and you don’t need a wait time.

rotateFor is blocking unless you include "false" at the end of it, in which case it's the same thing as startRotateFor. So just change the very last one to rotateFor. Yup. This is why I'm curious about what is really being done. Why make it so complex when it's not doing anything. I would just run a function this way and then do whatever is next without any task/thread for this.

9. ### mvas8037

Jan 9

@callen The basic idea is that you have a variable that you can lock so that only one task/thread can change it at a time. So in your drive thread you lock it. When you reach your target, you put in a small delay and then unlock it. The other thread isn't really idle, it just keeps waiting until the variable becomes unlocked. Only once that variable becomes unlocked does it do anything. But it seems like you're really overcomplicating things. Why not just use a function that calls the function to move as a regular function and then follows it with the next function?

Well, for starters, you have far more "(" than ")." Also, what are you trying to return from the if statement? It looks like you're setting a value to rightF, but never really comparing anything; note the difference between "=" and "==" in that line. And then you're not doing anything with the "if." Finally, it seems like you want "while," not "if." Something maybe more like this:

```while (rightDriveBack.rotation(rotationUnits::deg) < rightF){
task.sleep(10);
}```

If you do want to use in-line if statements, try looking up ternary operators in C++.

That makes more sense, I'll try it with the while statement instead but like I said I've been coding for less than a month so I don't have much under my belt.

10. ### callen

Jan 9 Braintree, MA, USA
Edited last week by callen

@mvas8037 That makes more sense, I'll try it with the while statement instead but like I said I've been coding for less than a month so I don't have much under my belt.

Then can I suggest doing a much simpler approach overall? I'm pretty sure you're way-overcomplicating something that can be pretty straightforward. Could you write in pseudocode the functions for the two tasks you want done, the one that does the driving and the one that waits until the driving is done? I just want to make sure there is nothing extra that I'm not aware of that you're trying to do.

I should ask, are you familiar with pseudocode? If not, here is an example:

```void driveForward( speed, distance ) {
set all four motors to go this distance at this speed
brake to stop
}```
11. ### mvas8037

Jan 9

@callen Then can I suggest doing a much simpler approach overall? I'm pretty sure you're way-overcomplicating something that can be pretty straightforward. Could you write in pseudocode the functions for the two tasks you want done, the one that does the driving and the one that waits until the driving is done? I just want to make sure there is nothing extra that I'm not aware of that you're trying to do.

I should ask, are you familiar with pseudocode? If not, here is an example:

```void driveForward( speed, distance ) { set all four motors to go this distance at this speed brake to stop }```

It's not over complicating it because the way I have it set up allows me to control the exact distance the robot travels and turns down to the inch and possibly more. I have it set up so that I can easily find a factor to multiply the distance by using a formula in my calculator so that I can control exact distances. I want the time to be exact as well. If it was a simple drive train method than yes it would be over complicated but this allows me to create autons without even having the robot in front of me and also take advantage of the integrated motor encoders with the new v5 system. The reason I want the time to be exact and not just a ballpark range is because time during autonomous is limited and I want to maximize the scoring possibility of the robot all while keeping a relatively condensed code that's easy to edit. I guess there is redundant code with the left and right variables since they would be the same rotations but that also allows me to have minor tweaks with the bot of the robot veers slightly because of uneven weight distribution.

12. ### callen

Jan 9 Braintree, MA, USA

I'm not denying any of that. But you can accomplish every bit of what you just said more simply without tasks/threads.

13. ### mvas8037

Jan 9

@callen I'm not denying any of that. But you can accomplish every bit of what you just said more simply without tasks/threads.

I only understand the way I have it written out and it's taken me a while just to code something thats probably simple. I implemented your way for the time variable but now I get a compliation error. Not sure how to resolve it, probaby a simple solution. Would you know how to solve it? Also, I'll try to sk

14. ### mvas8037

Jan 9

I wrote this out when I had the robot in front of me and through some trial and error I came up with that, there is likely an easier way to code it but it works and I understand it. I would consider redoing it in a simpler way but keep in mind I've taught myself everything on there. Basically the method takes the length of a tile and converts it into rotations that the motor can turn to, then those rotations are set = to left and right and you would simply multiply it by a factor which would be found through some basic algebra to the find what you would need to multiply the rotations by to get the motors to spin to the desired distance. I don't know if that made much sense but I fully get it in my head. What would you propose I do to simplify this in a step by step sort of process as I have just explained.

15. ### jpearman

Jan 9 Moderator, ROBOTC Tech Support, V5 Beta Moderator Los Angeles 8888
Edited last week by jpearman

you cannot pass an expression like "leftF*constant" as a parameter (meaning leftF multiplied by constant)
I'm not sure why you think you need to check for the motor traveling the requested distance, that's what rotateTo does. There is also an "isSpinning" method you could use if you wanted to do it yourself. If you are worried that the motor will not achieve the requested distance and want to bail after a certain time, rotateTo can also do that for you, set the timeout period using the "setTimeout" method (remember to change it back if you made it something small)

http://help.vexcodingstudio.com/#pro/namespacevex/classvex_1_1motor/isSpinning
(and by spinning we mean moving to the target requested by rotateTo etc.)
http://help.vexcodingstudio.com/#pro/namespacevex/classvex_1_1motor/setTimeout

16. ### callen

Jan 9 Answer Braintree, MA, USA

How about this?

```void driveTrainForward (int numTiles, int pctSpeed) {
int degreesToRotate = (360 * oneTile) / circumference * numTiles;
LeftDriveFront.startRotateFor(degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
RightDriveFront.startRotateFor(-degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
LeftDriveBack.startRotateFor(-degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
RighDriveBack.RotateFor(degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
}```

You then call this function

`driveTrainForward (how many tiles, how fast);`

I think you had "constant" for the number of tiles, which I wrote as "numTiles" to be clearer. I also don't like "pct" when there are other "pct's" so I called it "pctSpeed." When you call this function it will turn on all four motors, rotate them to where you want to go, and pause the code in the task that calls it until it has gotten there.

Then after calling this function you do whatever you wanted when you get there. So if you want a 20 ms delay, maybe to stop some shaking, and then something else, you would have

```driveTrainForward (how many tiles, how fast);
task.sleep(20);
something else;```
17. ### mvas8037

Jan 9

@callen How about this?

```void driveTrainForward (int numTiles, int pctSpeed) {
int degreesToRotate = (360 * oneTile) / circumference * numTiles;
LeftDriveFront.startRotateFor(degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
RightDriveFront.startRotateFor(-degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
LeftDriveBack.startRotateFor(-degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
RighDriveBack.RotateFor(degreesToRotate, rotationUnits::deg, pctSpeed, velocityUnits::pct);
}```

You then call this function

`driveTrainForward (how many tiles, how fast);`

I think you had "constant" for the number of tiles, which I wrote as "numTiles" to be clearer. I also don't like "pct" when there are other "pct's" so I called it "pctSpeed." When you call this function it will turn on all four motors, rotate them to where you want to go, and pause the code in the task that calls it until it has gotten there.

Then after calling this function you do whatever you wanted when you get there. So if you want a 20 ms delay, maybe to stop some shaking, and then something else, you would have

```driveTrainForward (how many tiles, how fast); task.sleep(20); something else;```

I guess this works more simply, the constant is simply a factor you multiply the tile by to change the distance the robot travels. Like 1.5x 24 inches. or 1/3 24 inches, etc.

18. ### callen

Jan 9 Braintree, MA, USA

@mvas8037 I guess this works more simply, the constant is simply a factor you multiply the tile by to change the distance the robot travels. Like 1.5x 24 inches. or 1/3 24 inches, etc.

You'll want to change int numTiles to float numTiles. Or you could divide that 360 by 24 to have the conversion factor be for inches, and then use float numInches and directly put in the number of inches instead of figuring out the fraction of 24 inches yourself.

or Sign Up to reply!