Thanks for all your help...and a question

Quick question

I have the 2006 default code loaded up.

If I wanted the trigger (fire) button on the 1 joystick controlling the robot movement to reduce the robots speed to 50% how would I do that.

I tried:

if (p1_sw_trig == 0)
{
pwm13 = pwm14 = Limit_Mix(2000 + p1_y + p1_x - 127);
pwm15 = pwm16 = Limit_Mix(2000 + p1_y - p1_x + 127);
}
else
{
pwm13 = (pwm13-127)*0.5+127;
pwm14 = (pwm14-127)*0.5+127;
pwm15 = (pwm15-127)*0.5+127;
pwm16 = (pwm16-127)*0.5+127;
}

but when the trigger was pressed nothing moved on teh robot!

Any help?

i dont know what u ment to do…
Dom you want the robot to move at 50% of its speed when u press the trigger and thats it? or do u also move the joystics Y farward?

Basically; I want the joysticks to be waay less sensitive when i press the button. I basically want the speed to be halved at every point when the joystick moves.

oh i get it…
i havent toucked programming for a year but i can tell you what i’d do:
if (p1_sw_trig == 0) && (p1_y==1)
{

pwm13=pwm14=pwm15=pwm16=(127+0.5*127);
}
else if (p1_sw_trig == 0) && (p1_y==-1)
{

pwm13=pwm14=pwm15=pwm16=(127-0.5*127);
}

When would p1_y ever be -1?

Your code never reads the joysticks if the button is pressed, so it repeatedly divides the pwm values by two until it decays to zero. That’s why the robot stops moving.

Try moving the part that reads the joysticks outside the test for the button.

  pwm13 = pwm14 = Limit_Mix(2000 + p1_y + p1_x - 127);
  pwm15 = pwm16 = Limit_Mix(2000 + p1_y - p1_x + 127);

  if (p1_sw_trig == 1)
  {
    pwm13 = (pwm13-127)/2+127;
    pwm14 = (pwm14-127)/2+127;
    pwm15 = (pwm15-127)/2+127;
    pwm16 = (pwm16-127)/2+127;
  }

It’s safe to do it this way because the pwm values don’t actually take effect until the Generate_PWMs() call at the end of Process_Data_From_Local_IO().

By the way, if you plan to use timers and serial communication and encoders and other interrupt-based stuff, avoiding pwms 13-16 would be a good idea. They’re generated by the user processor and can get somewhat twitchy when interrupts are happening often. Put your motor controls on pwms 1-12 if you want to keep things easy.

(Note that I replaced the multiply by 0.5 with a divide by 2. Keeping everything as integers makes sure that the compiler doesn’t try to do floating point calculations, which take up a lot more time and program space.)

Question to Alan (or anyone),

I’m under the impression a >>1 instead of a /2 would work there and would (possibly?) be faster. We’ve tried this in some spots in code before, however, and I think it corrupts signed variables. Do you (or anyone) have any specific knowledge about the >> operator on this PIC? I was sort of hoping that it or some other operator will do a signed >> operation and carry the signed bit.

Thanks a lot guys; Ill try this out today!

Something else to keep in mind when dealing with data types is that, from experience, the default printf function seems to not like to deal with floating point numbers. I have no idea if it can be modified to change that or if anyone’s done that already…

The “>>” in C is the “shift right bitwise” operation. Because of the fact that microprocessors use the binary number system (0s and 1s) a “shift right” results in the same thing as “divide by 2 (but throw away the remainder).”

I was looking throug the MCC18 (Microchip’s C compiler) User Guide and found this in Appendix B.4:

ANSI C Standard: “The result of a right shift of a negative-valued signed integral type (6.3.7).”
Implementation: The value is shifted as if it were an unsigned integral type of the same size (i.e., the sign bit is not propagated).

Sounds to me like the MCC18 compiler does not have a way to make “>>” operate on signed integers.

Good luck!

make a function for it

[from regular code]

if(p1_sw_trig){
dim_down(pwm01);
}

unsigned char dim_down(int input,float factor){
input-=127;
input*=factor //the factor to dim down the output
return input;
}

It won’t work on signed integers, because in order to have fast add and subtract between positive integers most procecssors use a twos complement system.
Basically there is a sign bit, and if the bit is enabled then you reverse the 1 for a 0, so if a number is negative it is instead represented by it’s not’d equivalent

So -2 would be
11111110 (for an 8 bit signed char)
The most significant bit is the sign bit.

Now lets try adding -2 to 3:
00000011
11111110

00000001

Tada …
The extra bit overflows and is discarded… so we can use the same logic adding positive and negative numbers together … yay!

When you try to bit shift a signed int this is what may happen:
11111100 (-3)
becomes 01111110 (126)

You can still bit shift but the sign bit needs to be replaced… you can do this by XORing the result with 10000000

I actually don’t think dividing by two using the bit shift operator really matters, most optimizing compilers should realize that an unsigned int is being divided by two and just swap that in at the assembly level. Secondly most first applications I have seen don’t even come close to being computationally intensive enough to warrant such an optimization.
(I don’t know if this is actually what happens when using MC18 or whatever it’s called)

BTW: for printf I think you can just use %f to print floats

if (p1_sw_trig == 0)
{
pwm13 = pwm14 = Limit_Mix(2000 + p1_y + p1_x - 127);
pwm15 = pwm16 = Limit_Mix(2000 + p1_y - p1_x + 127);
}
else
{
pwm13 = (pwm13-127)*0.5+127;
pwm14 = (pwm14-127)*0.5+127;
pwm15 = (pwm15-127)*0.5+127;
pwm16 = (pwm16-127)*0.5+127;
}

The way this is set up, you are only getting data from the joysticks when the trigger is not on. You always want to get that data, so first, take
pwm13 = pwm14 = Limit_Mix(2000 + p1_y + p1_x - 127);
pwm15 = pwm16 = Limit_Mix(2000 + p1_y - p1_x + 127);
out of the if block, so that you get new data from the joysticks every loop.
Then, if the trigger is on, you want to divide by 2, not multiply by a decimal


pwm13 = pwm14 = Limit_Mix(2000 + p1_y + p1_x - 127);
pwm15 = pwm16 = Limit_Mix(2000 + p1_y - p1_x + 127);
if (p1_sw_trig == 1)
{
pwm13 = (pwm13-127)/2+127;
pwm14 = (pwm14-127)/2+127;
pwm15 = (pwm15-127)/2+127;
pwm16 = (pwm16-127)/2+127;
}

Because you are getting the data every loop, and the pwm values aren’t set until the end of the loop, you can modify them all you want before that point. Previously, you when the trigger was enabled, you were taking the pwm value, which defaults to 127, subtracting 127, making it 0, multiplying that by .5, making it 0 again, and adding 127, making it neutral on the motors.

Another way to do this would be:


if (p1_sw_trig == 0)
{
pwm13 = pwm14 = Limit_Mix(2000 + p1_y + p1_x - 127);
pwm15 = pwm16 = Limit_Mix(2000 + p1_y - p1_x + 127);
}
else
{
pwm13 = pwm14 = (Limit_Mix(2000 + p1_y + p1_x - 127)-127)/2+127;
pwm15 = pwm 16 (Limit_Mix(2000 + p1_y - p1_x + 127)-127)/2+127;
}

In this case, you are getting the data from the joysticks in both if and else.

if(p1_sw_trig == 1)
{
pwm13=pwm14=(p1_y/2);
pwm15=pwm16=(p2_y/2);
}
else
{
pwm13=pwm14=(p1_y);
pwm15=pwm16=(p2_y);
}

isnt it as simple as that.

that would work for “tank style” drive, i think he meant using a single stick drive.

oh… i dont really have experience with single. personally i prefer tank.
although reducing speed with a button is a nice idea. i might try that out.

just make sure to test the code with the robot up on blocks or something. just to make sure it wont do any damage
…forest

Another way to do it would be to make a few lookup tables. We set up custom curves, so we had a large area that was slow for fine adjustments, and an area of full speed. This also makes so no calculations are needed on the fly, you just load them into the ram.

You would toss something like this (what we used) under the #include’s in user_routines.c


rom unsigned short int Joystick_Array] = {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,61,62,63,63,64,65,66,67,68,69,69,70,71,72,73,74,75,75,
76,77,78,79,80,81,81,82,83,84,85,86,87,87,88,89,90,90,91,91,92,92,93,93,94,94,94,95,95,96,96,97,97,98,98,99,99,99,100,100,101,101,102,102,103,
103,103,104,104,105,105,106,106,107,107,107,108,108,109,109,110,110,111,111,111,112,112,113,113,114,114,115,115,116,116,116,117,117,118,
118,119,119,120,120,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,135,135,136,136,136,136,137,137,137,138,
138,138,139,139,139,139,140,140,140,141,141,141,141,142,142,142,143,143,143,144,144,144,144,145,145,145,146,146,146,146,147,147,147,148,
148,148,149,149,149,149,150,150,150,151,151,151,151,152,152,152,153,153,153,154,154,154,154,155,155,156,157,158,158,159,160,161,162,163,
164,164,165,166,167,168,169,170,170,171,172,173,174,175,176,176,177,178,179,180,181,182,182,183,184,185,190,194,199,204,208,213,218,222,
227,232,236,241,246,250,255,};

Then to call it:


Left_Drive = Joystick_Array[p1_y];
Right_Drive = Joystick_Array[p3_y];

(Again, here we use tank style, and used p1 and p3 due to custom control systems (p2 and p4 have all of the button outputs)

That makes so the variable “Left_Drive” and “Right_Drive” are modified pwm values, but not assigned to the pwm yet.

To go with one joystick:


if (p1_sw_trig == 0)
{
pwm13 = pwm14 = Limit_Mix(2000 + p1_y + p1_x - 127);
pwm15 = pwm16 = Limit_Mix(2000 + p1_y - p1_x + 127);
}
else
{
pwm13 = pwm14 = Limit_Mix(2000 + Joystick_Array[p1_y] + Joystick_Array[p1_x] - 127);
pwm15 = pwm16 = Limit_Mix(2000 + Joystick_Array[p1_y] - Joystick_Arrayp1_x + 127);
}

In this case, you would make an array with new values (halves if you want). the joystick gives a value of 0 to 255, so it looks in spot 0, if full reverse in the array, and in this example, would grab a value of 0. 127 points to the 127th. Remember, the first one is spot 0, not 1 in the array. Doing it this way allows you to have multiple curves for drivers, or just change the values completely so you have a larger slow area so you do not need to cut it in half at all.

(This is in regard to the post above mine, which I will not quote, for space considerations)

We do essentially the same thing, the only differences are, we use a slightly different equation, and our lookup table uses unsigned chars instead of short ints (although, in theory both should work, unsigned chars just take up less space). However, instead of just using ours for only our drive system, ours is used for every single joystick controlled movement on our robot. We have found that this greatly increases usability and driveability of our robot and its mechaisms by allowing fine control when necessary (like positioning the wrist for a ringer) and fast control when you need the speed (like driving across the field to a ringer). I would highly recommend at least trying exponential lookup tables, you may be amazed by the improvement such a small change can make.