Controlling A Robotic Arm With Potentiometers

Hello all, I am working on an arm made of potentiometers that, when moved, will wirelessly move another arm made of servos. You can see what I'm talking about in this video at about the halfway point. . I'm going to use two Parallax Activity Boards and two XBees to control 5 servos and 1 linear actuator using potentiometers. I have already controlled a servo with a potentiometer on an activity board. I tried controlling two servos with two potentiometers on an Activity Board, but one potentiometer moved both servos and the other potentiometer didn't do anything. Just to be clear I am using Propeller C. I am also having trouble figuring out how to wirelessly control a servo using the Xbees. Thank you so much for reading, and any help is appreciated.

Comments

  • 21 Comments sorted by Date Added Votes
  • ercoerco Posts: 17,819
    Cool project, but why Xbee? Wx/WiFi using ESP8266 is the boss. First get your servo arm (output) going.

    "When you make a thing, a thing that is new, it is so complicated making it that it is bound to be ugly. But those that make it after you, they don’t have to worry about making it. And they can make it pretty, and so everybody can like it when others make it after you."

    - Pablo Picasso
  • Thanks for the tip :) And do you have any tips on wiring and programming the Activity Board to control multiple servos with multiple potentiometers?
  • It would also be nice to have code for sending the potentiometer's position to another Activity Board using Xbee.
  • Please post your code and a photo of your wiring so we can see what you have. The simple IDE servo library should be able to control 14 servos.

    The way you translate the potentiometer position into a servo value will be important.

    Tom
  • ercoerco Posts: 17,819
    Something like this, sans wires?

    "When you make a thing, a thing that is new, it is so complicated making it that it is bound to be ugly. But those that make it after you, they don’t have to worry about making it. And they can make it pretty, and so everybody can like it when others make it after you."

    - Pablo Picasso
  • How are you reading the pot values?
    Jim
  • The Activity board has 4 analog inputs, and it sounds like you need 6. You'll probably want to use a different ADC before you get too far.

    There's a great little ADC called the MCP3208, 8 channels and 12 bit resolution. Here's a thread on getting it working with PropC - http://forums.parallax.com/discussion/141893/spi-mcp3208-in-c

    If you can get away with only 4 channels, as mentioned post your code and setup, it sounds like you're very close on reading the ADC/pots, let's get that going and then work on the XBee part.

    Which XBee radios do you have?
  • W9GFOW9GFO Posts: 3,700
    edited March 22 Vote Up0Vote Down
    Here is a short clip of the control system we made for our 2011 FRC robot. The controller has three pots to sense position and a toggle switch for the gripper.

  • @W9GFO can you add the URL below the video? On my PC I see white space where the video should be.
  • xanadu wrote: »
    @W9GFO can you add the URL below the video? On my PC I see white space where the video should be.

    At first I was using the "YouTube" link to add the URL but it was't working. Just pasting the raw link without any tags did the trick.
  • Yes erco I am working on something similar. My robotics team uses a lot of Parallax products, so we will likely stick with that. Today, using the Activity Board we figured out how to control 4 servos at once by using 4 potentiometers. Since we have 5 servos in our other arm we need an MCP 3208 just like xanadu was saying. A friend gave me some code for the MCP 3208 although I have yet to try it out, but I have done much of the wiring. RS_Jim, I am reading the pot values by telling the program to print the value to the terminal. And xanadu I am using the Xbee that says S1 on it.
  • Anyone have any tips on wirelessly controlling 5 servos with 5 potentiometers? I am programming in Propeller C and I'm not an experienced programmer. As stated before I am using the Activity Board, but since there are only 4 analog inputs on the board I am using the MCP 3208, which I am not sure how to program. Today I tried to control a servo on another Activity Board. I used Xbees and it didn't work.
  • I was also looking at this thread http://forums.parallax.com/discussion/157946/xbee-to-xbee-communication-propeller-activity-board-2-axis-joystick-c
    I tried using the code that was given in that thread, and while there were no errors it didn't work.

    Here is my code for trying to control a servo with the MCP 3208 on the Activity Board (not wireless)

    #include "simpletools.h"

    #include "abvolts.h"

    #include "servo.h"


    //Set these parameters to the pins where your ADC chip is plugged in
    #define ADC_CLK 15
    #define ADC_DO 14
    #define ADC_DI 13
    #define ADC_CS 12
    #define ADC_AVERAGE 1
    //ADC Channels - Do not change these numbers or reading from the ADC chip will not work
    #define CHANNEL_1 24
    #define CHANNEL_2 25
    #define CHANNEL_3 26
    #define CHANNEL_4 27
    #define CHANNEL_5 28
    #define CHANNEL_6 29
    #define CHANNEL_7 30
    #define CHANNEL_8 31

    //This function returns a value from the ADC chip. The value returned is between is 0 - 4096
    //Use the channel constants to call this function
    double readADCVal(int channel);
    double readADCVal(int channel);
    double readADCVal(int channel);
    double readADCVal(int channel);

    //code for function

    double readADCVal(int channel)
    {
    double adcVal;
    double tempAdcVal = 0;
    for (int x = 0; x < ADC_AVERAGE; x++)
    {
    low(ADC_CS); //Turn ADC chip on
    shift_out(ADC_DI, ADC_CLK, MSBFIRST, 5, channel); //Select channel
    tempAdcVal += shift_in(ADC_DO, ADC_CLK, MSBPOST, 13); //Read value
    high(ADC_CS); //Turn ADC chip off
    low(ADC_CLK); //Stop giving clock signals
    pause(1);
    }
    adcVal = tempAdcVal / ADC_AVERAGE;
    return adcVal;
    }



    int main() // Main function

    {

    print("Twist knob to control servo.");


    while(1)

    {

    double x = readADCVal(1);//ad_in(7);
    print("%f", x);

    double y = x * 1800 / 2703;

    servo_angle(14, y);

    // x = ad_in(2);

    //y = x * 1800 / 2703;

    //servo_angle(15, y);

    //x = ad_in(1);

    //y = x * 1800 / 2703;

    //servo_angle(16, y);

    //x = ad_in(0);

    //y = x * 1800 / 2703;

    //servo_angle(17, y);


    }

    }


  • While I haven't had a chance to try your code, the first thing I would recommend is that you do not declare your variables a doubles. Integers (int) in propeller C are 32 bit longs. So they will be sufficient.

    The values that the servo function uses are integers (0 to 1800).
    Did print("%f", x); print out a reasonable number? Try printing y to make sure it is between 0 and 1800.
    My mind is slow right now, but where did 2703 come from?

    Tom
  • twm47099twm47099 Posts: 532
    edited March 25 Vote Up1Vote Down
    Some slight modifications to your program. The code below works. I only used 2 servo's and potentiometers. One on channel 1 and one on channel 5. I also changed the pins for the MCP3208 based on a set up I already had. I changed the servos pins to use the P16 and P17 servo headers on the Activity Board.

    Be sure to power the activity board with a battery pack; the usb port can't power the servos. Also be sure to turn on the Activity board to the second on position.

    The 2703 in the book is because the voltage being read was 3.3v max. If you set VDD and Vref to 5 v you should use 4096. (2703 = 3.3 * 4096/5)

    As a demo, this works. But the motion is not smooth, so the delays need work, and the limits on the servos need to be set for your servos.

    I'm not sure why your program didn't work, because I only made a few tweeks.

    Tom
    // testing mcp3208 using channels 1 and 5
    // my 3208 is plugged in so ckl = P0, ADC-DO = P1 (with3k series resistor), ADC-DI = P2, CS = P3
    // servo for  channel 1 = P16 header, Channel 5 = P17 header
    // Be sure to use battery power to the activity board.
    
    #include "simpletools.h"
    #include "abvolts.h"
    #include "servo.h"
    
    
    //Set these parameters to the pins where your ADC chip is plugged in
    #define ADC_CLK 0
    #define ADC_DO 1
    #define ADC_DI 2
    #define ADC_CS 3
    #define ADC_AVERAGE 1
    //ADC Channels - Do not change these numbers or reading from the ADC chip will not work
    #define CHANNEL_1 24
    #define CHANNEL_2 25
    #define CHANNEL_3 26
    #define CHANNEL_4 27
    #define CHANNEL_5 28
    #define CHANNEL_6 29
    #define CHANNEL_7 30
    #define CHANNEL_8 31
    
    //This function returns a value from the ADC chip. The value returned is between is 0 - 4096
    //Use the channel constants to call this function
    
    int channel;
    int x, y;
    
    //code for function
    
    int readADCVal(int channel)
    {
    int adcVal;
    int tempAdcVal = 0;
    for (int x = 0; x < ADC_AVERAGE; x++)
    {
    low(ADC_CS); //Turn ADC chip on
    shift_out(ADC_DI, ADC_CLK, MSBFIRST, 5, channel); //Select channel
    tempAdcVal += shift_in(ADC_DO, ADC_CLK, MSBPOST, 13); //Read value
    high(ADC_CS); //Turn ADC chip off
    //low(ADC_CLK); //Stop giving clock signals, not sure this is needed  (it worked without it).
    pause(1);
    }
    adcVal = tempAdcVal / ADC_AVERAGE;
    return adcVal;
    }
    // *************
    int main() // Main function
    {
    print("Twist knob to control servo.");
    while(1)
    {
    
    channel = CHANNEL_1;
    
    x = readADCVal(channel);    
    print("%d ", x);
    
    y = x * 1800 / 4096;     //  4096 because 3208 gives 4096 at 5v if 5v is ref voltage
    if(y<250) y=250;          // my servo hit stops at less than 250
    if(y>1750) y=1750;
    print("y1=%d ",y);
    servo_angle(16,y);
    pause(1000);      // delay to read print x & y.  Delay should be long enough to allow servo to reach
                                  // commanded angle, but short enough for smooth motion
    channel = CHANNEL_5;
    
    x = readADCVal(channel);   
    print("%d ", x);
    
    y = x * 1800 / 4096;
    if(y<250) y=250;
    if(y>1750) y=1750;
    print("y5=%d ",y);
    servo_angle(17, y);
    pause(1000);
    
    }
    
    }
    
    
  • The link you posted for the XBEE communication is sending and receiving bytes of data. I've never sent longs using XBEEs, but I have taken 16 bit values, separated them into 2 bytes, sent and received the bytes, and the recombined them into 16 bit values. The values from the 3208 ADC are only 12 bits so that method could be used.

    The first thing I would try is having the program on the sending A-board just create a bunch of 16 bit words (or you could just enter some values from the terminal and store them as words), then break into 8 bit bytes, send to the receiving A-board, recombine them, and print them. You want to make sure that they are the same values that you typed.

    Tom
  • twm47099twm47099 Posts: 532
    edited March 25 Vote Up0Vote Down
    I see your error. In your statement:
    double x = readADCVal(1);
    
    "channel" in the function is being set to the number 1.

    But the value being sent to the mcp3208 in the function statement:
    shift_out(ADC_DI, ADC_CLK, MSBFIRST, 5, channel);
    
    should not be just the channel number. It needs to be a 5 bit command value that includes the mode and channel number. Those are the numbers in the #define section. The full 5 bit number for channel 1 is 24 (0b11000). Note what we are calling channel 1 is actually channel 0 since the 3208 channels are numbered 0 -7.

    So you have to call the function
    x = readADCVal(CHANNEL_1);
    // or 
    x = readADCVal(24);
    // or like I did
    
  • Thank you
  • Once you get your project working, please post the code and wiring diagrams. I think it would be very interesting.
    Tom
  • Okay, I'm working on wirelessly controlling a servo using two Xbees and two Activity Boards. I am having trouble finding resources on this though. Any help would be greatly appreciated.
Sign In or Register to comment.