programming a switch

I want to hit the microswitch and have a motor stop. I set the microswith to the digital input and I can make the light on the control board blink but thats about it.
I changed the line in the definitions from

digital_io_01 = digital_io_02 = digital_io_03 = digital_io_04 = INPUT;
to
digital_io_01 = digital_io_02 = digital_io_03 = digital_io_04 = 0;

I tried a simple if then statement but to no avail.

if (digital_io_01 = 1)
{
pwm01=127;
}

Any suggestions?

I believe you just set the io pins to be outputs rather than inputs.

See ifi_aliases.h

#define INPUT 1
#define OUTPUT 0

/* Used in User_Initialization routine in user_routines.c file. /
/
Used to set pins as digital INPUTS or digital OUTPUTS. */
#define digital_io_01 TRISBbits.TRISB2
#define digital_io_02 TRISBbits.TRISB3

Set them back to inputs and use the io pin name to read the values.

Again, ifi_aliases.h has these defined.

/* Aliases used to read the pins when used as INPUTS. /
#define rc_dig_in01 PORTBbits.RB2 /
external interrupt RB2/INT2 /
#define rc_dig_in02 PORTBbits.RB3 /
external interrupt RB3/INT3 /
#define rc_dig_in03 PORTBbits.RB4 /
external interrupt-on-change RB4 /
#define rc_dig_in04 PORTBbits.RB5 /
external interrupt-on-change RB5 /
#define rc_dig_in05 PORTBbits.RB6 /
external interrupt-on-change RB6 /
#define rc_dig_in06 PORTBbits.RB7 /
external interrupt-on-change RB7 */

So change the code to test rc_dig_in01.

Bud

The digital_io_## names are for determining whether a digital pin is an input or an output. You want an input, so leave their setup the way it is in the default code.

To read the value of the input, use rc_dig_in##.


if (rc_dig_in01 == 1)
  {
  pwm01=127;
  }

Note the double equals sign == for making the comparison. You had a single =, which assigns a value.

First make sure if you want to see if something is equal to something else you use ==. In C = means assign and == means compare.

I love the solution Alan, I can’t wait for the end of school to try it out. The solution also allows me to do a variety of tasks whenever I hit a switch.
thanks.

Didn’t work.
I double/triple checked my wiring, made sure I was downloading the right code to the robot, and a myriad of other possibilities. I never had a compiling problem, the motor would simply not stop. Is this a possibility?
turn on a motor when the swith is hit? Does an if statement require an “else”?

if (rc_dig_in01 == 1)
{
pwm01=155;
}

I tried the above and it didn’t work either…

I assume you set pwm01 by joystick or something else before making your micro switch “stop” check?
It doesn’t accidentally get set again after your check?

Does your switch allow it to be wired by default open or closed?
You may be checking it backwards. A regular on/off switch (on the RC) will be read as “1” when open and “0” when closed. (An OI button is the opposite by the way).

E.g.,


pwm01=200;
if (rc_dig_in01 == 0)     // Act when the RC switch is closed
{
  pwm01=127;
}

The limit switches that come in the KOP have three terminals that give you the option of wiring them either way and can be wired incorrectly. Have you tested your switch with a multi-meter to see if it’s open or closed when you expect?

You’ve never told us how you wired the switch. If you misunderstand how to do it, then no matter how many times you check it you’ll just be ensuring that you did it wrong. :slight_smile:

How do you have the switch connected? Be as detailed as you can, so we can make sure you’re doing it the way the RC needs it to be.

The PWM cable is going to the digital in/out 1 on the board. the cable is going to the microswitch. the white is connected to the ground (com1), the red is going to the NC 2 and the black to NO 3. I’ve also ran it with black and red swapped. I get feedback on the interface ( green light turn on when I hit the switch–or turn off when I hit the switch–depending how I’ve wired it. )
I connect a motor to Pwm01. I know it functions correctly since I can control it with the joystick just fine.
TESTING METHOD:
load the code.
“turn on the motor” by pushing forward on the stick–the motor spins
hit the microswitch–motor keeps spinning.

I cut and pasted your code to where I map the joystick to the pwms in the user_routines.c

That’ll work, but it’s a very unusual way to do it. The RC digital inputs just want to see a contact closure to ground. They already have a +5v pullup built in, so there’s no need to connect the red wire.

The typical way to connect a switch is to connect the black ground wire to the COM pin and the white signal wire to either the NC or NO pin, depending on whether you want the switch to be normally closed or normally open.

Since the OI feedback light is responding as you expect, the problem is not with the switch. It has to be with the way you’re controlling the motor. Make doubly sure that the code that tests the switch and sets the pwm to neutral is executing after anything that sets the pwm to reflect the joystick position. Perhaps you could post the relevant part of your code for us to look over?

Since your LED is lighting it sounds like your circuit is working.

Switches bounce when they switches for milliseconds. This can lead to timing issues reading the switch state.

Try putting a 6.8 microfarad electrolytic capacitor and a .01 microfarad capacitor from the input pin to ground and see if it works better. The positive electrolytic pin should go on the input.

They already have a +5v pullup built in

I’m curious about this because it appears that this is not true for all of the pins.

According to the Analog/Digital IO schematic digital inputs 1-6 are internally pulled up. But digital IO 7-18 are not, they must be externally pulled up.

I hope I am missing something, but this seems like an extraordinarily unsafe design. The normal state of the digital inputs are high with the pull ups, however, if the connector is removed, the state will look low, which will look closed or active to the system.

It seems like these digital inputs would need a normally closed system to ensure that they are safe if the connector is removed. It’s often difficult to locate normally closed switches for some items.

Am I missing something? How can these inputs be used in a safe manner?

Where is this “Analog/Digital IO schematic” you mention? According to the one on the IFI web site, there is a 100k resistor to +5v directly to each of digital I/O pins 7-18.

Perhaps there is a misinterpretation of the use of “internal” on that schematic?
They are all pulled up within the confines of the Robot Controller enclosure (internal from our perspective), however, some are pulled up internal to the PIC itself while others are pulled up by IFI designed “external” circuitry.

One big problem I noticed in your code:

You don’t want to FREEZE the motor when a limit switch is hit. If you do that, your device dies as soon as you hit it forever, and you’ll have to manually pull it off!

Instead, you want to prevent further motion in that direction. IOW, you override a motion command ONLY when that direction’s limit is hit AND you’re asking for MORE motion in the SAME direction.

Here’s a code sample, that implements both forward and backwards motion limiting.

BTW, notice I’ve also included the practice of “#define”-ing the hardware assignments, logical states, and all control values. This separates the device assignments and*** device control values*** from the logical control code. (I’m also using the convention of #define’d values being “all caps”, to hint at where to look for them.)

This separation (when combined with proper grouping of the defines), allows for far better device assigment management, AND more readable logical code. The last thing you want to do is to search through code for hard coded values and device assignments when you want to change one thing. That’s a recipe for bugs!

<edit>
(BTW, this is off the top of my head, based on what I’ve done before on other systems. I haven’t tried compiling this on this year’s C18 compiler. Let me know if it won’t compile, this year’s RC digital I/O switch assertion is backwards, etc… Thanks!)
</edit>

I hope this helps!

  • Keith McClary
    Chief Engineer, Team 1502, “Technical Difficulties”
//--------------- Header Snip follows --------------

//
// --- Device Assignment Definitions
//

// DIGITAL I/O Assignments  (Note: EVERY DIO pin has an entry...comment out unused)
#define WIDGET_FWD_LIMIT_SW    rc_dig_in01
#define WIDGET_REV_LIMIT_SW    rc_dig_in02
//#define ________        rc_dig_in03
//                (...etc...)

// PWM Assignments    (Note: EVERY PWM port has an entry...comment out unused)
#define WIDGET_MOTOR        pwm01
//#define ________        pwm02
//                (...etc...)

// (other devices follow, [analog in, relay out, serial ports, etc.]...)

//
// --- Victor Speed Defines
//
#define FULL_FORWARD     254
#define NEUTRAL        127
#define STOP        127
#define FULL_REVERSE    0

// Widget forward & reverse speeds - tweek values HERE, *NOT* inline!
//  This makes changes happen in only ONE PLACE...
#define WIDGET_FWD    200
#define WIDGET_FWD_SLOW 150
#define WIDGET_REV_SLOW 100
#define WIDGET_REV    25

//
// --- Logical Defines
//
#define FALSE   0
#define TRUE    1

// I/O Switch assertion Defines (RC varies by year! Uncomment this year's def)
//    Hardware:  switch pulls to ground against a resistor pullup

// #define SW_OFF    0
// #define SW_ON    1

#define SW_OFF    1
#define SW_ON    0


//--------------- Code snip follows --------------


//-----------------------------------------------------------------------
//  Sample widget limit switch test code follows.
//  Change speed *values defs* in headers, or add more options *there*.
//-----------------------------------------------------------------------

//--Choose one--

    WIDGET_MOTOR = WIDGET_FWD;
//  WIDGET_MOTOR = STOP;    // (or NEUTRAL)
//  WIDGET_MOTOR = WIDGET_REV;

//-----------------------------------------------------------------------
// Widget Limit Switch Handler (locate *after* normal widget control code)
// 
// Stops widget whenever a limit switch is closed *AND* still asking for 
// wrong dir.  It allows the widget to back off from the switch.
// (Assumes WIDGET_MOTOR values greater than NEUTRAL => forward motion)
//-----------------------------------------------------------------------

if (WIDGET_FWD_LIMIT_SW == SW_ON  &&  WIDGET_MOTOR > NEUTRAL )    // Hit Fwd Limit & want more?
      {
       WIDGET_MOTOR = STOP;                    // ..Y, stop widget
      }

if (WIDGET_REV_LIMIT_SW == SW_ON  &&  WIDGET_MOTOR < NEUTRAL )    // Hit Rev Limit & want more?
      {
       WIDGET_MOTOR = STOP;                    // ..Y, stop widget
      }

I almost understand Keith
Let me explain the application…
Our robot has an omni drive, although this year its really a tricycle drive. The main wheel can rotate on a plate. The plate is driven by a window motor. The problem is that the window motor turns too quickly, so we put the window motor on a victor to slow it down. There is wire wrapped around the housing around the window motor which limits the amount of turns the motor can turn on the plate.

I have problems with the limit switch test code
Do I write the widget limit switch handler code for each widget motor speed?

The use of the widget motor speed also evades me. Why can’t I have the standard pwm output?

If you have it wired correctly, the code is fairly straightforward.

You should test the switches with a printf and then proceed with any code.

Wow. You really need to make sure that you don’t inadverdently break it by going too far.

Try putting the joystick drive in an else after the if. You might be changing the motor value to the number you want and then immediately changing it to the value of the joystick.

The reason for defining the widget motor speed is code readability. If you forget what pwm1 is, you need to check your robot or another sheet. You probably won’t forget what motor Wigit_Motor is.
Defining the speeds has two reasons. The first, same as above, is that it is a lot easier to remember what WIGIT_SPEED_REV is than, say, 72. Also, if that’s the wrong speed, it’s a lot easier to change one number in a #define than hunt down every time you put down a 72 and change it to a 64.

Ans A) NO. A limit switch is a limit switch, regardless of motor speed. HOWEVER, you always need to physically locate the limit switch back far enough, so that you won’t break anything physically when it “coasts to a stop”, even at the highest motor speed allowed by the system. There’s a difference between the LOGICAL limit (where you locate the switch, ie at the end of the “operating zone”), and the PHYSICAL limit (where the thing breaks, tears out wires, runs off the track, etc).

Note that with massive loads, (and assuming you don’t have a potentiometer or other way to “know” where the axis is) then if the axis tends to coast more than the distance between the logical limit and the physical limit, you may need to either locate the switch further out, or add an additional “SLOW DOWN” switch on each end’s approach, to reduce speed in that zone. But most of the time, that’s overkill. You can normally either reduce the speed of the motor, or move the limit switch further out.

Ans B) You CAN, but it’s not a good idea. I was illustrating the VERY important concept in industry programming, of writing Device Independent Code (something that FIRST default code example tends NOT to do very well.)

*** In industry, it is VERY bad programming practice to “hard code” device names within a program suite******.** *If you do, that’s an engraved invitation for bugs! A raw PWM name has nothing in common with a logical device’s name. (Ex: It’s hard to “recognize” errors when you’re always talking about “pwm14” when you really should be talking about “ELBOW_MOTOR”. The latter makes more logical sense.)

Assume you wish to REUSE some code on a new machine. Well, it may very well have a DIFFERENT pwm channel assignment. If that happens, you’d have to go through every line of every programming module, and edit it, both to move the original device to the new pwm assignment, AND to make sure it doesn’t conflict with anything else! Now you have TWO modules instead of one, which can screw you up if you ever need to recompile and reload the OLDER machine! (I’m ignoring source code control systems here, as many teams tend not to use them…) If you miss even ONE occurance, either in THIS routine, or ANOTHER routine that happens to hard code the same PWM, suddenly something ELSE is commanding your device!

This can be VERY frustrating to diagnose! …And… it’s a software maintenance nightmare!

Also, if the I/O map must change on the same machine (“oops, we need a HIGH speed channel for this app”), you again have to go through every lousy module, searching for and editing every occurance of pwm_xxx, AND pwm_yyy… <augh!>

INSTEAD: You refer to devices within all code by its functional name (IOW, “WIDGET_MOTOR”, etc…) NOW, in ONE place, in ONE header, you ASSIGN the name of each device to an appropriate channel for THIS machine, via a #define statement. IOW, you have one set of #defines, that assign the entire machine’s PWM, Digital I/O, Relay outputs, AND Analog inputs to the appropriate widget(s) all on the same page. This makes it almost selfdocumenting, for to change the device’s assignment, you only edit ONE line of code, in a header file. NOTHING changes in the C module!

It is not a problem to nest defines with an additional layer. IOW, in FIRST’s header files, “pwm_xxx” is defined as some hardware location, used by the RC. But in YOUR application’s header file, you “redefine” <widget_motor> as pwm_xxx. As long as your defines occur after FIRST’s, they all refer to the same thing. (It’s OK. The compiler deals with this nesting automatically.)

NOW you can reuse modules! Robot #1 has <widget> on PWM6. Robot #2 has the SAME widget (and uses the SAME widget code), but its widget is assigned to PWM12, etc… NO lines of actual widget handler code had to change at all for the same device handler to be used on two different machines, because your code refered to everything by the WIDGET’s naming convention, NOT by fixed hardware locations.

THIS allows you to start building up “libraries” of useful, reusable functions over time.

I tried to illustrate this with a “header snippet” of a typical “device assignment (define) block”.

Sorry for the length, but does this explain the concept better (and the reasoning behind it)?

  • Keith McClary
    Chief Engineer, Team 1502, “Technical Difficulties”