RadioHead & Servo

I hope this is the right place, I'm using the latest (I believe, 1.41) Radiohead library for transmitting and receiving via a RF transmitter & receiver (of course) but I'm having a bit of trouble with compiling. I'm using a SparkFun pro micro board, if that matters ^_^;

I am also controlling a Servo which needs to go into the circuit and I think that's what's creating a conflict.
I have including the RH_ASK.h and when I compile the sketch, it claims:

libraries\RadioHead\RH_ASK.cpp.o (symbol from plugin): In function `RH_ASK::maxMessageLength()':

(.text+0x0): multiple definition of `__vector_17'

libraries\Servo\avr\Servo.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board SparkFun Pro Micro.

I have read, when checking up, that it MIGHT be connected to the use of a Timer and adding '#define RH_ASK_ARDUINO_USE_TIMER2' to the RH_ASK.h might deal with it.

So I did that, however, I get this error:

Arduino: 1.8.12 (Windows 10), Board: "SparkFun Pro Micro, ATmega32U4 (5V, 16 MHz)"

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp: In member function 'void RH_ASK::timerSetup()':

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:238:5: error: 'TCCR2A' was not declared in this scope

TCCR2A = _BV(WGM21); // Turn on CTC mode)

^~~~~~

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:238:5: note: suggested alternative: 'TCCR0A'

TCCR2A = _BV(WGM21); // Turn on CTC mode)

^~~~~~

TCCR0A

In file included from c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\io.h:99:0,

from c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\pgmspace.h:90,

from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:28,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RadioHead.h:533,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RHGenericDriver.h:9,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RH_ASK.h:12,

from C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:6:

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:238:18: error: 'WGM21' was not declared in this scope

TCCR2A = _BV(WGM21); // Turn on CTC mode)

^

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:238:18: note: suggested alternative: 'WGM41'

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:240:5: error: 'TCCR2B' was not declared in this scope

TCCR2B = prescaler;

^~~~~~

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:240:5: note: suggested alternative: 'TCCR0B'

TCCR2B = prescaler;

^~~~~~

TCCR0B

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:244:5: error: 'OCR2A' was not declared in this scope

OCR2A = nticks;

^~~~~

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:244:5: note: suggested alternative: 'OCR3A'

OCR2A = nticks;

^~~~~

OCR3A

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:251:5: error: 'TIMSK' was not declared in this scope

TIMSK |= _BV(OCIE2A);

^~~~~

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:251:5: note: suggested alternative: 'TIMSK0'

TIMSK |= _BV(OCIE2A);

^~~~~

TIMSK0

In file included from c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\io.h:99:0,

from c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\pgmspace.h:90,

from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:28,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RadioHead.h:533,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RHGenericDriver.h:9,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RH_ASK.h:12,

from C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:6:

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:251:18: error: 'OCIE2A' was not declared in this scope

TIMSK |= _BV(OCIE2A);

^

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:251:18: note: suggested alternative: 'OCIE0A'

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:30:0,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RadioHead.h:533,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RHGenericDriver.h:9,

from C:\Program Files (x86)\Arduino\libraries\RadioHead/RH_ASK.h:12,

from C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:6:

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp: In function 'void TIMER2_COMPA_vect()':

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:483:32: warning: 'TIMER2_COMPA_vect' appears to be a misspelled 'signal' handler, missing '__vector' prefix [-Wmisspelled-isr]

#define RH_ASK_TIMER_VECTOR TIMER2_COMPA_vect

^

C:\Program Files (x86)\Arduino\libraries\RadioHead\RH_ASK.cpp:513:5: note: in expansion of macro 'RH_ASK_TIMER_VECTOR'

ISR(RH_ASK_TIMER_VECTOR)

^~~~~~~~~~~~~~~~~~~

exit status 1
Error compiling for board SparkFun Pro Micro.

I haven't been able to find too much help on this.. probably looking in the wrong place, but I'm not sure. any help?

It may be a conflict with two libraries. I would retrace your steps before you tried to fix the first error and post your complete code. I can't tell you more about the errors than you have already been given, except that TIMSK, OCIE2A, OCR2A, TCCR0B, TCCR2B etc. look like registers from the avr specsheet. I am guessing you've lost an important header by redefinition.

okay, Right now.. it's.. erm.. not too much code cause I'm going slowly as i'm fairly new. Adding a feature, breadboarding till I get it right, then moving on, so a lot of commented out code and stuff i'm backwards and forwards with the testing ^_^;

#include <Servo.h>  // servo library
#include <RH_ASK.h> //RadioHead Library for RF
#ifdef RH_HAVE_HARDWARE_SPI
#include <SPI.h> //Needed to compile?
#endif

Servo servoArmL;         // servo control object for the Left Arm
Servo servoArmR;         //Servo control object for the Right Arm
Servo servoHead;          // Servo control for the head

RH_ASK driver;

const int TransmitPin = 12;
const int buttonPin =2;   //the number of the pushbutton pin
int buttonState = 0;      //variable for reading the pushbutton status
int armpos = 0;           //variable for roughtly where the arms are. 0 is down, 1 is up
boolean actionDone = true;//This will tell when an action is done, and there for the next
                          //action can be set
void setup()
{
//  servoArmL.write(0);   //Might be an idea to automatically reset the arm position to down

  servoArmL.attach(15, 900, 2100);  //Connect the servo on the Left arm to pin 6
								//with a minimum pulse width of 900 and a maximum pulse width of
								//2100.
//  servoArmR.write(0); 
//  servoArmR.attach(5, 900, 2100); //Connect the servo on the Right arm to pin 5
                //with a minimum pulse width of 900 and a max of 2100
  //ServoHead.attach(0,900,2100); //Connect the servo for the Head. Pin not stated yet

  //Initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  servoArmL.write(0);   //Might be an idea to automatically reset the arm position to down
  //servoArmR.write(0);
}

void loop()
{
  buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH){
    //If the button is pressed
   // actionDone = false;
    
   // if (armpos == 0){
      servoArmL.write(180);
    //  servoArmR.write(90);
      //This works at full speed. to slow it down, use a variable for loop
      //and delays
      //armpos = 1;  
      //delay(200);
    //} else if (armpos == 1){
    //  servoArmL.write(0);
    //  servoArmR.write(0);
    //  armpos = 0;
      //delay(100);
    //}
  } else {
      //actionDone = true;
    servoArmL.write(0);   //Might be an idea to automatically reset the arm position to down
    //servoArmR.write(0);   //Might be an idea to automatically reset the arm position to down
  //delay(100);
  }
}

the Servo library is, of course, the inbuild library, and the other one is the Radiohead library version 1.4 which.. I found a Sparkfun fork of the library at: GitHub - sparkfun/SparkFun_RadioHead_Arduino_Library: SparkFun Fork of Mike McCauley's RadioHead library (http://www.airspayce.com/mikem/arduino/RadioHead/)

though even when moving back.. which I think I have done (since it was just one line), it seam to have a number of warnings as well as that one error..

So, Here is Servo.cpp and Here is RH_ASK.cpp. They both use timers. Servo appears to use timers 1, 3, 4 and 5 if available. Timer 0 and 2 are used for by the Arduino Core, to my knowledge. RH_ASK appears to use timers 0, 1, and 2. Someone else can probably break it all down more intelligently than I, but it appears on the surface that your problem is a library conflict.

mm.. so.. ..
the RH library uses 2 of the same timers as the core and that's okay... but the problem is with the servo using them as well.. so.. I would need to tell the RH library NOT to use timer 1?... mm.. but is there a timer 6... mm.. is there a better/another library set I could use to deal with the conflict? this is a bit … unsure

I think the sparkfun pro micro only has 3 timers though.. i'm not quite sure

If your target is the Arduino UNO, you only have timer 0, 1 and 2. I have only glanced over the code in each library to explain your error. I would start with writing your code without the libraries first, that is, isolate the RF stuff to simple IO and replace it with a button and led for now, then when you have your code working, add one of the two and get it working. Then, you can work on the other.

true.. I've been screwing around with some of the other bits and seam to have the right idea, just need to try out some other bits.. I was just trying to see if I could get the RF side working as well but.. okay, I can leave that for now :slight_smile:

I know this is KINDA slightly off the topic but.. It is possible to stall the servos? just for testing, I told it to run to 90 degrees at full speed while a button is pressed, and go back to 0 when it's let go.. and a few times I think if I let go before it's finished, it kinda stalls.. I know about the delays lines and stuff, and I won't be telling it to work like this in the final thing, but.. just wondering if that is a problem with the Servo functions in a way OR a problem with the servo's or Arduino itself..

tempy111:
I told it to run to 90 degrees at full speed while a button is pressed, and go back to 0 when it's let go.. and a few times I think if I let go before it's finished, it kinda stalls..

It's your thread... everything you post is on topic. How are you debouncing the push-button? Is it possible that this stall is the push-button bouncing?

erm.. It's a push-button, power to one pin, ground side to a 10k Ohm resistor, then to ground, and before the resistor, the control pin, which the code just reads if it's HIGH or LOW. I think it might be related to the pin though.. I updated the code for a 90degree loop moving at 2 steps with a 20 whatever delay (I'll speed it up later as that's too slow) and it seams to move about 15 degrees before resetting as if the button has turned low.. wondering if a connection is a bit loose but shouldn't be.. but also.. for some reason.. I seam to get the feeling the numbers when I write, don't work out as degrees.. I guess it's more steps.. so.. doing write(90) isn't 90 degree.. without counting the teeth or something, hard to say the steps it does or anything.. I think it's a pretty cheap standard metal geared Analog servo.

tempy111:
erm.. It's a push-button, power to one pin, ground side to a 10k Ohm resistor, then to ground, and before the resistor, the control pin, which the code just reads if it's HIGH or LOW.

GitHub - thomasfredericks/Bounce2: Debouncing library for Arduino and Wiring is yet another library... But, they do a good job of explaining what bounce is and how they mitigate it. consider that as you push the button with your finger, that you apply force against a spring, just like a plane landing on an airstrip, it may contact the ground a couple of times before making full contact. So, that might start and stop your servo, since you may be polling it rather fast.

ah.. that does look useful, thanks :slight_smile:

FYI, you don't need any library to do "lock out interval" debounce, especially if you only have one or two switches. It's basically change of state detection with an added delay.

okay :slight_smile: might be on the safe side to use it cause of the 'stall'..

I'm wondering about the servo movement though.. like I said, when I tell it to go 90 degrees, it doesn't go 90 degrees. They are Analogue servos but I'm wondering if it's kinda related to power.. I got the speed stats for 4.8v and 6.0v so I'm kinda wondering if they need the extra voltage to 6volts for the write line to do the full movement.. or maybe the command write(90) bases it more on something like steps, like a stepper motor (which I know is different) but most things I can find say there shouldn't really be a difference.. so write(90) should move 90 degrees.. but I've used a couple of types of servo I have and neither of them move 90 degrees for the 90 command.. though I think 180 moves slightly over 90.. not sure why...

it has nothing to do with supplying the servo with 4,8V or 6V. If the suply-voltage is in the specified range it turns always the exaclty same degrees. WIth a higher voltage it turns a little bit faster. That's all.

All servos-types differ in how much they can turn from min to max and on which servosignal they turn 90 degrees.
The basic function of a servosignal is send a high-pulse once every 20 milliseconds. The length of this high-pulse is varyied between 1,0 milliseconds and 2,0 milliseconds.
1,0 milliseconds for most left 2,0 milliseconds for most right position. That's the standard. Some servos go even beyound this and start at 0,6 milliseconds and go up to 2,4 milliseonds. Also it can happen one servo will turn to the left with a pulse-length of 1,0 milliseconds others will turn to the right. That is all not standadized.

So for your servo to move exactly 90 degrees you have to make adjustements.
Servos need an endless pulsetrain of short high-pusles every 20 milliseconds to work properly.
Regardless of what your main-code does the pulses must be created in this regular manner.
That's the reason why a hardware-timer is needed.

If you are running out of timers maybe a very small board that does nothing else than creating the servo-signal could be a solution. Another solution for wireless communicating could be two WeMos D1-Mini boards.

They are based on the ESP8266-modules which have WiFi on Board. ESP8266 and ESP32-boards offer radio-transmission over WiFi . Additional to "classical" WiFi connected to an accesspoint ESP-boards have a functionality called ESP-NOW which allows to send and receive datapackets at high speed and you can do it even between up to 20 modules.
Send and receive with ESP-NOW is done directly without the need for an accesspoint.

best regards Stefan

Okay.. I don't fully understand all that :slight_smile:
but.. okay, I kinda understand how a servo moves via pulse modulation..

the pinout for the Pro Micro has one of the pins also labelled as SDA (a Data line of some time), and one as SCL (a clock line of some kind) and I understand the pins which are also PWM, but don't understand the SPI (SCLK, MISO and MOSI), or the Analog lines.. Any of them important in this kinda thing?

anyway.. so. when everything says that the Servo.write(degrees) it isn't quite right cause.. if the pulse modulation is a bit different, then the shaft rotation needs to be adjusted by a different amount to get the degrees required?

so.. I think write(180) is just past 90 degrees, to a point that maybe if I set it as 170 that might be 90.. and that does the adjustment for the modulation?

0 degress is "mapped" to 1,0 milliseconds 180 degrees is mapped to 2,0 milliseconds. So set to 170 will make any servo move to their "almost" max-position. For most servos this is around 180 degrees compared to their min position. they turn to when you send them 1,0 millisecond pulses.

What do the specs of the servo say about it? What is the brand and exact type of the servo that you are using?

Here is a picture that show it

here is a video that shows the high-pulse changing from 1,0 milliseocnds to 2,0 milliseconds

And this website explains the options of the optional parameters

here is an example of a servo that can be bought with different maximum-degrees
https://www.aliexpress.com/item/32907126360.html?src=google&src=google&albch=shopping&acnt=494-037-6276&isdl=y&slnk=&plac=&mtctp=&albbt=Gploogle_7_shopping&aff_atform=google&aff_short_key=UneMJZVf&&albagn=888888&albcp=9317151805&albag=93621837065&trgt=296730740870&crea=de32907126360&netw=u&device=c&albpg=296730740870&albpd=de32907126360&gclid=EAIaIQobChMI3NbBy5j86QIVTOJ3Ch2I9AsXEAkYAyABEgJ8NvD_BwE&gclsrc=aw.ds

most common servos do have a turnarngle of aproximately 180 degrees.
Just use a small test-code that does nothing else than sweeping your servo from min to max.

the servo's are generic no brand markings.. cheap ish ones..

the only real stats I have are based on torque and size.. though looking.. mm.. one type does comment about speed and give it as /60Degress... i'm not starting to wonder if this standard high torque ones... only have a very limited turn circle... Looks like there are hacking methods for tweaking servos to increase the range, so i'll probably have to look into that..

StefanL38:
0 degress is "mapped" to 1,0 milliseconds 180 degrees is mapped to 2,0 milliseconds. So set to 170 will make any servo move to their "almost" max-position. For most servos this is around 180 degrees compared to their min position. they turn to when you send them 1,0 millisecond pulses.

Not quite right. If you're using the standard Servo library then write(0) = 0.544ms and write(180) = 2.4ms. For some servos this is too much and bangs them onto their end stops. If you want to restrict the value then you can do that in servo.attach(). attach(pinNumber, 1000, 2000) will do that.

But it's true that some servos have only a restricted range of movement, sometimes as low at 120 degrees total. There's nothing you can easily do about that.

Steve

mm.. hang on...

the Attach line for the Servo.. does something which tells the minimum pulse width and the maximum.. (900 and 2100).. I used them values cause the guide I was looking at said to.. maybe the values aren't right for the servo OR attach can be defined without them?

EDIT: Silly me.. looks like it is optional.. and that value isn't even the default.. so I can screw around more by removing it and toying around.. that guide was pretty limited if it didn't even explain that bit ¬_¬ oh well