today i put the ir board on our robot after some preliminary testing and I have managed to get the robot to respond to the IR signals sent to the IR board.
however, the motors only run for as long as the IR board recieves a signal (less than a second)
i am not surprised at the result i am getting, but all attempts to create constant motion have failed. the only way i can think of is to have the remote cause a variable to be “true” and so that
You are on the right track. You should start developing routines that do things like ‘go forward’ and ‘go left’. Next, when you get an IR signal you will set a variable that says which routines to run ‘forward’, ‘left’, ‘stop’ , etc. You will probably not be able to control the robot in real-time with the IR inputs.
Instead think if it as sending ‘commands’ that you will execute until told otherwise. There is going to be a lot of IR scatter and interference so don’t expect to get a low latency response from the controller.
yea thats the plan, i just needed it to be doing something by tomorrow because im supposed to be showing it off.
as far as routines go and such, im not really sure how i go about doing that because i really only started programming…uhh…today…i have some basic knowledge in C++ and python, so i know enough to fake as much as i have so far…
Or, even simpler, just put a wait in after you set your pwm’s to 255. Make it so your robot goes a reasonable distance (10-15 feet maybe)? That way your motion won’t be jerky, and your driver will have some choice in what’s going on. Also, if the IR signal goes bad, your robot won’t do something silly like ram into a wall, or if you only get one signal through, it’ll still move.
This is a simple example we used in a workshop on Saturday for a full-sized RC. We also have an alternative style we ran on an Edu mini-robot. Everything is self-contained in the Default_Routine().
sensorReading = PORTJ>>4; // Combined digital inputs 15-18
if (latch == 1)
{
if (sensorReading == 0)
{
latch = 0; // Take only the 1st reading to avoid being caught by a half & half state of the IR sensor
}
}
else if (sensorReading != 0)
{
latch = 1;
if (sensorReading == 8) IR_cmd = 1;
else if (sensorReading == 4) IR_cmd = 4;
else if (sensorReading == 2) IR_cmd = 2;
else if (sensorReading == 1) IR_cmd = 3;
printf("IR_cmd = %d
", IR_cmd);
}
what exactly does this do? especially the first part.
One thing that might help you quite a bit would be to lay everything out in a state diagram, or a state machine. Wikipedia does an ok job with the general idea, with a few decent pictures. http://en.wikipedia.org/wiki/State_machine
The basic concept is to draw a bubble to represent discrete thing you want your robot to do during hybrid mode (for example, drive straight, turn to the left, stop). Then you draw arrows between the state and set conditions for those transitions. For example, you might have an arrow to the stop state and trigger that with a “4” signal. Then an arrow from stop to drive forward with a “1” signal. Other cases, you might have it time based - drive forward, and 5 seconds later turn left 180 degrees.
State machines are extremely powerful things, and are especially great for an application like this.
sensorReading = PORTJ>>4; // Combined digital inputs 15-18
Digital inputs 15,16,17,18 are all just the last 4 bits in a byte named PORTJ, so you can capture all the pin values in one step and avoid the half-and-half state you might get by checking the pins one at a time while the IR sensor is possibly changing states.
Since we only want the last 4 bits of PORTJ, >>4 is used to shift them 4 bits to the right thereby eliminating the other bits in that byte.
So sensorReading now has one of these possible (values)/states for the 4 signal pins from the IR sensor:
(0) 0, 0, 0, 0 - no button
(1) 0, 0, 0, 1 - button 3
(2) 0, 0, 1, 0 - button 2
(4) 0, 1, 0, 0 - button 4
(8) 1, 0, 0, 0 - button 1
This does depends on which signal pin got which wire from the IR sensor.
if (latch == 1)
{
if (sensorReading == 0)
{
latch = 0; // Take only the 1st reading to avoid being caught by a half & half state of the IR sensor
}
}
That section only captures the first reading when the IR sensor sends a command. It latches onto the first value and then doesn’t pay any more attention until the IR sensor stops sending the command and all signal inputs = 0 again.
else if (sensorReading != 0)
{
latch = 1;
if (sensorReading == 8) IR_cmd = 1;
else if (sensorReading == 4) IR_cmd = 4;
else if (sensorReading == 2) IR_cmd = 2;
else if (sensorReading == 1) IR_cmd = 3;
printf("IR_cmd = %d
", IR_cmd);
}
The last part just converts the possible sensorReading values into the command corresponding to the IR wire plugged into that signal pin. It sets the command and then keeps that command until the IR sensor sends another command.
Another thing i’ve been considering however, is that if you print the value of GetDigitalInput(x), you get either a 1 or a 0. While the board is receiving a modulated IR signal, you get so many 1’s and so many 0’s in a row, alternating. Thus I think you can do something like this:
int n = 0;
int nmax = number; //This value will be different per controller and button
if (GetDigitalInput(1) = 1)
{
while (n < nmax)
{
SetPWM(1,255);
SetPWM(2,255);
if (GetDigitalInput(1) = 0)
{
n++
}}}
This will keep the PWMs set, as long as the string of 0’s (between the 1’s) does not exceed a certain number. This number can be determined by adding a simple print and monitoring, and stopping at the right time, your terminal while pressing a button.
I’m not sure how well this would work, maybe something I’ll play with tomorrow.
NOTE: Programmers with more experience than I, feel free to chime in…I’ve learned that my methods are sometimes not the shortest/best route from A to B…
Also note that the post above mine is in easyC–it looks like you are using MPLAB. That’s all right, just as long as you don’t try to insert easyC snippets into your MPLAB project.
That’s basically what you want to do; if you want an IR command to send the robot x amount of feet forward, a simple way of doing this would be to define a variable used for time.
Now, if you define said variable inside the function (where you are writing the code snippets you posted), the variable will lose its value every time the function is called. There are two ways to fix this problem. One way (the preferred method, I’d say) is to define the variable as static–instead of
int variable;
you’d put
static int variable;
What this does is it makes the variable hold onto its value even when the processor isn’t calling the function. Another way to make the variable keep its value is to define it outside of the function. Instead of putting the “int variable;” inside your function, you can put it at the top of the file, where it will hold its value between function calls. Note that this method should only really be used if more than one function need access to this variable; otherwise the first method I mentioned provides better readability.
Once you have the variable defined, one way of doing what you desire is to use that variable as a countdown to when the robot is going to stop. That way, when you recieve an IR signal, you can set it to a value that means “1 second” (will not be 1–let me explain in a moment), and each loop, the robot will subtract 1 from that value. Once the counter reaches 0, it will shut off the motors and stop subtracting.
Realize that if you write this code inside of Process_Data_From_Master_uP (sorry if I have the function name wrong…I don’t have MPLAB in front of me right now) or it calls the function that executes this code, it will run about every 23 milliseconds–a millisecond is a thousandth of a second. Using that bit of information, you can calculate how big your counter should be: 5 seconds = 5000 milliseconds / 23 milliseconds per tick = 217 ticks.
I would post some sample code, but I’d like to see you try to write it first–I want you to know this inside-and-out before the first regional.
Check your remote to see if it’s the repeating type. That means when you hold down a button on the remote, the output on the IR board will pulse every 100ms until you release the button.
If that’s not the case, I’d highly recommend finding a remote that does this. The first Sony remote we picked up worked nicely for us in this manner.
The code below hasn’t been tested or compiled since we’ve just been “pulsing” our motors, and our chassis isn’t ready to go full-speed yet.
The code below should sets a timer to run the motors for 150ms after it receives a pulse from the IR board. If you have a signal pulsing every 100ms, that means that the timer will keep resetting before it ever expires = constant power.
Your robot WILL continue to run for 150ms after you’ve released the button on the remote, but I’ll leave it up to you whether you feel that is acceptable.
-Shawn T. Lim…
// set your timer's limit
// see JBot's post, 7 ticks is a little more than 150ms
static char variable = 8;
// ...other code goes here...
// whenever you receive a signal from your IR board, reset your timer
if (rc_dig_in01)
{
variable = 0;
}
// whenever there is no signal, run your timer until it expires
else
{
if (variable < 8)
{
variable++;
}
}
// run your motors if the timer is running
if (variable < 8)
{
pwm03 = pwm04 = 1;
pwm07 = pwm08 = 255;
}
else
// stop motors when timer expires
{
pwm03 = pwm04 = 128;
pwm07 = pwm08 = 128;
}
thank you all who have helped so far. One more problem though… we have come to the conclusion the one pin #17 on the rc doesn’t work. we can wire it all different ways and it is always that pin that doesn’t send the signal properly. ITS NOT THE IR BOARD.
the code we’re using right now has been copied and modified from Mark McLeod (thank you by the way). We understand the bit shift idea, but since pin 17 doesn’t work (don;t worry, its last year’s rc), it limits us to 3 commands. can you explain how to bit shift it two more so we’re using pins 13-16 instead.