-1

I'm working on a forward and inverse kinematic model for a project and can't seem to fix this error. I am very new to classes in C++ and have only used them in python in the past so sorry if it's a stupid problem.

An extract of my code is below, which is everything involved in what seems to give the error. The line showing the error is labelled, I have no idea what is going on and I can't seem to fix it.

#include <Servo.h>


class Leg{
  public:
    //The class's variables that all functions for this class can use
    int PositionX; 
    int PositionY;

    Servo Shoulder();
    Servo Elbow();

    Leg(int SP, int EP){ //-----------This line has the error!
      // This is the constructor function
      const int ShoulderPin = SP;
      const int ElbowPin = EP;
      PositionX = 0
      PositionY = 0

      Shoulder.attach(ShoulderPin);
      Elbow.attach(ElbowPin);
    }

    void GoTo(float DemandS, float DemandE) {
      // Sends this Leg to a certain position (could make this return a True when it is done)
      // Inputs are in degrees (chould change)
      Shoulder.write(DemandS);
      Elbow.write(DemandE);
    }
};

I have tried: Giving the constructor function a variable type (void), Moving the constructor out of the code block using Leg::Leg(....{. Checking everywhere for any unclosed brackets, there are none. Commenting out the Servo library and all of its uses.

I'd really appretiate any help as I feel like I've tried everything and must be missing something somewhere, contemplating doing this without classes, but it will be very annoying to do that. Thanks vey much :)

user4581301
  • 33,082
  • 7
  • 33
  • 54
leon buck
  • 1
  • 1
  • Please show us `Servo.h` – NathanOliver Feb 03 '20 at 22:17
  • 1
    You're missing some semicolons (`;`) in your constructor body. Namely after `PositionX = 0` and `PositionY = 0`. – Jonny Henly Feb 03 '20 at 22:17
  • `Servo Shoulder();` declares a function, but `Shoulder.attach(ShoulderPin);` suggests it should be a variable. Give `Servo Shoulder;` a go. Ditto with `Elbow`. – user4581301 Feb 03 '20 at 22:18
  • 3
    Try changing `SP` and `EP` to `foo` and `bar` respectively – M.M Feb 03 '20 at 22:19
  • 1
    What is the intent of `const int ShoulderPin = SP;`? It doesn't seem to be used anywhere and is scoped by (and thus only visible within) the `Leg` constructor. – user4581301 Feb 03 '20 at 22:22
  • Confirmation of sorts for @M.M 's suggestion: https://forum.arduino.cc/index.php?topic=544326.0. Seems that `SP` is indeed a used as a macro for the Stack Pointer CPU register. – user4581301 Feb 03 '20 at 22:34

3 Answers3

2

These two line:

Servo Shoulder();
Servo Elbow();

should probably be:

Servo Shoulder;
Servo Elbow;

i.e instantiating objects of type Servo rather than declaring functions that take no parameters and return a Servo object.

And from the comments it turns out that you shouldn't be using SP as a name here:

Leg(int SP, int EP)

so use something more like:

Leg(int this_is_for_this, int and_this_is_for_this_other_thing)

or use camel case or whatever is common in your code but be descriptive.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • Yeah oops! I just changed this before posting, these were previously passed parameters. Adding ; does not fix the issue though sadly. – leon buck Feb 03 '20 at 22:20
  • I also initially had without the (), but was looking for any possible solution. Unfortunately removing them still does not fix the issue. – leon buck Feb 03 '20 at 22:22
  • 2
    @leonbuck M.M. has a really good idea up in the comments. You may have a `EP` or `SP` macro somewhere in the program that is silently causing text substitution. `SP`, for example, is a common acronym for Stack Pointer. – user4581301 Feb 03 '20 at 22:24
0

thanks everyone, you did come to a solution! Using m.m 's solution of changing SP and EP to foo and bar respectively worked. I'm not sure if foo and bar are special variables in c++ or if it is because SP has other meanings to the compiler, as user4581301 has suggested.

Thanks all for the help! -Leon

leon buck
  • 1
  • 1
  • `foo` and `bar` have no special meaning. They are common test identifiers used for [cultural reasons](https://stackoverflow.com/questions/4868904/what-is-the-origin-of-foo-and-bar). `SP` has no special meaning to the compiler (if it did I guarantee you the problem would have been identified faster). – user4581301 Feb 05 '20 at 18:18
0

You have run afoul of a Preprocessor Macro and will have to change the name of the variable. sp should be safe to use.

Do not use ALLCAPS for variable names. By convention ALLCAPS is reserved for constants and in early days of C the only way you could get a constant was with a preprocessor macro representing a literal. If you follow convention, the odds of one of your identifiers colliding with a macro and being substituted are dramatically reduced.

TL;DR Version

Somewhere in one of the Arduinio library header files there is something ultimately that looks something like

#define SP ((*(volatile unsigned int *)0xNN)

that takes NN, a number representing the offset of the SP register, and turns it into something a C or C++ program can use more easily. This is so that you can look at the current Stack pointer if you want to (probably for debugging).

#defines are simple text substitution. When SP is found, it is replaced with ((*(volatile unsigned int *)0xNN). So

Leg(int SP, int EP)

is transformed after you see it into

Leg(int ((*(volatile unsigned int *)0xNN), int EP)

before the compiler sees it. The compiler can't parse that mess, so you get an error message that doesn't match the code you wrote. Much fun ensues.

This sounds like a nightmare, and it can be, but sometimes macros are the best tool for the job. Here is more on macros and how to use them without falling into the more common traps: Why are preprocessor macros evil and what are the alternatives??

The simplest thing you can do is adhere to convention and never use ALLCAPS identifiers except when defining a macro. If you use sp instead of SP you're probably safe.

Digging through preprocessor output of some old Arduino code I find

#define SP _SFR_IO16(0x3D)

Which leads to

#define _SFR_IO16(io_addr) _MMIO_WORD((io_addr) + __SFR_OFFSET)

and to

#define _MMIO_WORD(mem_addr) (*(volatile uint16_t *)(mem_addr))

So my initial guess is off by a little bit, but the result is the same.

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54