Function with (int) called in loop?

I added another sensor to a robot and rewrote the loop() to incorporate it. Now there is one whole function of the sketch left out of the loop.

void FollowBlock(int trackedBlock)

If I try to include that in the loop

void loop()
{
  read_Ir();
  camera();
  ScanForBlocks();
  FollowBlock(int trackedBlock);

I get an error saying I need a primary expression before int.
(int trackedBlock) is earlier in the sketch and not in a void.
How can I fix this?

Thank you

You could post the code, and help others to help you.

FollowBlock(int trackedBlock);

is not correct C syntax.

FollowBlock(trackedBlock);

is probably what you want - you don't include the datatype when calling a function.

If trackedBlock is some other datatype, and you need to cast it to an int, you might do something like this (but you say trackedBlock is already an int):

FollowBlock( (int) trackedBlock);

#include <SPI.h>
#include <Pixy.h>
#include <ZumoMotors.h>
#include <musical_notes.h>

#define X_CENTER    160L
#define Y_CENTER    100L
#define RCS_MIN_POS     0L
#define RCS_MAX_POS     1000L
#define RCS_CENTER_POS  ((RCS_MAX_POS-RCS_MIN_POS)/2)

#define Far 150
#define Middle 225
#define Close 500

int irtemp[10];
byte detpos;
int ir;
boolean dirflag = false;
byte pos = 90;
byte followError;
int speakerPin = 6;

//-----------------------------------------------------------------------------
// Servo Loop Class
// A Proportional/Derivative feedback
// loop for pan/tilt servo tracking of blocks.
// (Based on Pixy CMUcam5 example code)
//-----------------------------------------------------------------------------

class ServoLoop
{
  public:
    ServoLoop(int32_t proportionalGain, int32_t derivativeGain);

    void update(int32_t error);

    int32_t m_pos;
    int32_t m_prevError;
    int32_t m_proportionalGain;
    int32_t m_derivativeGain;
};

//-----------------------------------------------------------------------------
// ServoLoop Constructor
//-----------------------------------------------------------------------------

ServoLoop::ServoLoop(int32_t proportionalGain, int32_t derivativeGain)
{
  m_pos = RCS_CENTER_POS;
  m_proportionalGain = proportionalGain;
  m_derivativeGain = derivativeGain;
  m_prevError = 0x80000000L;
}

// ServoLoop Update
// Calculates new output based on the measured
// error and the current state.

void ServoLoop::update(int32_t error)
{
  long int velocity;
  char buf[32];
  if (m_prevError != 0x80000000)
  {
    velocity = (error * m_proportionalGain + (error - m_prevError) * m_derivativeGain) >> 10;

    m_pos += velocity;
    if (m_pos > RCS_MAX_POS)
    {
      m_pos = RCS_MAX_POS;
    }
    else if (m_pos < RCS_MIN_POS)
    {
      m_pos = RCS_MIN_POS;
    }
  }
  m_prevError = error;
}

//-----------------------------------------------------------------------------
// End Servo Loop Class
//-----------------------------------------------------------------------------

Pixy pixy;  // Declare the camera object

ServoLoop panLoop(200, 200);  // Servo loop for pan
ServoLoop tiltLoop(150, 200); // Servo loop for tilt

ZumoMotors motors;  // declare the motors on the zumo

//-----------------------------------------------------------------------------
// Setup - runs once at startup
//-----------------------------------------------------------------------------

void setup()
{
  Serial.begin(9600);
  Serial.print("Starting...\n");

  pixy.init();
}

uint32_t lastBlockTime = 0;


//-----------------------------------------------------------------------------
// Sound constructor
//-----------------------------------------------------------------------------

void beep (int speakerPin, float noteFrequency, long noteDuration)
{
  int x;
  // Convert the frequency to microseconds
  float microsecondsPerWave = 1000000 / noteFrequency;
  // Calculate how many HIGH/LOW cycles there are per millisecond
  float millisecondsPerCycle = 1000 / (microsecondsPerWave * 2);
  // Multiply noteDuration * number or cycles per millisecond
  float loopTime = noteDuration * millisecondsPerCycle;
  // Play the note for the calculated loopTime.
  for (x = 0; x < loopTime; x++)
  {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(microsecondsPerWave);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(microsecondsPerWave);
  }
}

//-----------------------------------------------------------------------------
// IR sensor constructor
//-----------------------------------------------------------------------------

int read_Ir()
{
  int A = analogRead(3);
  delay(1);
  int B = analogRead(3);
  int number = 0;
  for (int x = 0; x < 10; x++)
  {
    A = analogRead(3);
    B = analogRead(3);
    while (abs(A - B) > 5)
    {
      A = B;
      B = analogRead(3);
    }
    irtemp[x] = (A + B) / 2;
  }
  ir = 0;
  for (int x = 0; x < 9; x++)
    ir = ir + irtemp[x];
  ir = ir / 10;

  if (ir > Far)
    detpos = pos;
}

//-----------------------------------------------------------------------------
// Camera constructor
//-----------------------------------------------------------------------------

void camera()
{
  uint16_t blocks;
  blocks = pixy.getBlocks();

  // If we have blocks in sight, track and follow them
  if (blocks)
  {
    int trackedBlock = TrackBlock(blocks);
    FollowBlock(trackedBlock);
    lastBlockTime = millis();
  }
  else if (millis() - lastBlockTime > 500)
  {
    ScanForBlocks();
  }
}

int oldX, oldY, oldSignature;

//-----------------------------------------------------------------------------
// Track blocks via the Pixy pan/tilt mech
// (based in part on Pixy CMUcam5 pantilt example)
//-----------------------------------------------------------------------------

int TrackBlock(int blockCount)
{
  int trackedBlock = 0;
  long maxSize = 0;

  Serial.print("blocks =");
  Serial.println(blockCount);

  for (int i = 0; i < blockCount; i++)
  {
    if ((oldSignature == 0) || (pixy.blocks[i].signature == oldSignature))
    {
      long newSize = pixy.blocks[i].height * pixy.blocks[i].width;
      if (newSize > maxSize)
      {
        trackedBlock = i;
        maxSize = newSize;
      }
    }
  }

  int32_t panError = X_CENTER - pixy.blocks[trackedBlock].x;
  int32_t tiltError = pixy.blocks[trackedBlock].y - Y_CENTER;

  panLoop.update(panError);
  tiltLoop.update(tiltError);

  pixy.setServos(panLoop.m_pos, tiltLoop.m_pos);

  oldX = pixy.blocks[trackedBlock].x;
  oldY = pixy.blocks[trackedBlock].y;
  oldSignature = pixy.blocks[trackedBlock].signature;
  return trackedBlock;
}

//-----------------------------------------------------------------------------
// Follow blocks via the Zumo robot drive
//
// This code makes the robot base turn
// and move to follow the pan/tilt tracking
// of the head.
//-----------------------------------------------------------------------------

int32_t size = 400;
void FollowBlock(int trackedBlock)
{
  int32_t followError = RCS_CENTER_POS - panLoop.m_pos;  // How far off-center are we looking now?
  // Size is the area of the object.
  // We keep a running average of the last 8.
  size += pixy.blocks[trackedBlock].width * pixy.blocks[trackedBlock].height;
  size -= size >> 3;

  // Forward speed decreases as we approach the object (size is larger)
  int forwardSpeed = constrain(400 - (size / 100), -150, 400);

  // Steering differential is proportional to the error times the forward speed
  int32_t differential = (followError + (followError * forwardSpeed)) >> 8;

  // Adjust the left and right speeds by the steering differential.
  int leftSpeed = constrain(forwardSpeed + differential, -400, 400);
  int rightSpeed = constrain(forwardSpeed - differential, -400, 400);

  // And set the motor speeds
  motors.setLeftSpeed(leftSpeed);
  motors.setRightSpeed(rightSpeed);

  if (forwardSpeed > 1 && forwardSpeed < 3)
  {
    catcall();
  }
  else if (forwardSpeed < -30 && forwardSpeed > -32)
  {
    ohhh();
  }
  pixy.setServos(panLoop.m_pos, tiltLoop.m_pos);
}

//-----------------------------------------------------------------------------
// Random search for blocks
//
// This code pans back and forth at random
// until a block is detected
//-----------------------------------------------------------------------------

int scanIncrement = (RCS_MAX_POS - RCS_MIN_POS) / 65;
uint32_t lastMove = 0;

void ScanForBlocks()
{
  if (millis() - lastMove > 20)
  {
    lastMove = millis();
    panLoop.m_pos += scanIncrement;
    if ((panLoop.m_pos >= RCS_MAX_POS) || (panLoop.m_pos <= RCS_MIN_POS))
    {
      tiltLoop.m_pos = (RCS_MAX_POS * 0.65);
      scanIncrement = -scanIncrement;
      if ((scanIncrement < 0) || (scanIncrement > 0))
      {
        motors.setLeftSpeed(+95);
        motors.setRightSpeed(+95);
      }
    }
    pixy.setServos(panLoop.m_pos, tiltLoop.m_pos);
  }
}

//-----------------------------------------------------------------------------
// Wonder around looking for more red objects
// Avoid other objects
//-----------------------------------------------------------------------------

void loop()
{
  read_Ir();
  camera();
  ScanForBlocks();
  FollowBlock(int trackedBlock);

  if ((panLoop.m_pos < RCS_CENTER_POS) && ir > Middle && (millis() - lastBlockTime > 500))
  {
    motors.setLeftSpeed(+0);
    motors.setRightSpeed(+160);
    delay(500);
  }
  else if ((panLoop.m_pos > RCS_CENTER_POS) && ir > Middle && (millis() - lastBlockTime > 500))
  {
    motors.setLeftSpeed(+160);
    motors.setRightSpeed(+0);
    delay(500);
  }
}

In the loop() function you have
  FollowBlock(int trackedBlock);As previously explained this is wrong.

UKHeliBob:
In the loop() function you have

  FollowBlock(int trackedBlock);

As previously explained this is wrong.

And, the variable trackedBlock does not appear to be defined in a scope available to loop().

I had to post the code by itself for the 9000 character posting limit.

The history of the robot is it originally just had a camera that it would use to find objects of a certain color. Last week I added an IR distance sensor to allow the robot to roam the house and avoid walls, furniture, etc. Originally the loop() was what is called camera() now. I then added the loop() at the end of the sketch with the roaming code. Now the Follow Block code doesn't work. Everything else works, when the camera sees it's assigned color it does respond, but the pan servo won't follow it, the pan servo keep panning.

Thank you again

UKHeliBob:
In the loop() function you have

  FollowBlock(int trackedBlock);

As previously explained this is wrong.

Yes, that’s what I’m having trouble with. Can I fix it an easy way or will it require extensive rewriting?

Thanks again

Put int trackedBlock = 0;

with these:

int irtemp[10];
byte detpos;
int ir;
boolean dirflag = false;
byte pos = 90;
byte followError;
int speakerPin = 6;

You need to pass a value to that function. Previously you said you'd defined a variable of type int called trackedBlock. Now that you've posted the full sketch I see no such declaration in your code, though. You seem to have ignored my original post.

So you are using invalid syntax as I explained above AND don't seem to have that trackedBlock variable defined (except inside other functions as local variables, which are out of scope), nor is it clear to me what you intend to pass to it.

Evenmars that will not work - it'll compile, but the other places where he uses a variable of that name it's defined within the function, so trackedBlock will always be zero, and that's probably not what he wants...

DrAzzy:
You need to pass a value to that function. Previously you said you'd defined a variable of type int called trackedBlock. Now that you've posted the full sketch I see no such declaration in your code, though. You seem to have ignored my original post.

So you are using invalid syntax as I explained above AND don't seem to have that trackedBlock variable defined (except inside other functions as local variables, which are out of scope), nor is it clear to me what you intend to pass to it.

Evenmars that will not work - it'll compile, but the other places where he uses a variable of that name it's defined within the function, so trackedBlock will always be zero, and that's probably not what he wants...

evanmars:
Put int trackedBlock = 0;

with these:

int irtemp[10];
byte detpos;
int ir;
boolean dirflag = false;
byte pos = 90;
byte followError;
int speakerPin = 6;

DrAzzy, I didn't ignore your previous post. I exceeded the amount of posts I can make in 5 minutes earlier and my reply to you was lost when I posted the whole code. I tried what you recommended and still received errors.

I also tried evanmars idea, yes it compiled, and yes the robot went crazy.

But you received different errors!

Scott_Callahan:
DrAzzy, I didn't ignore your previous post. I exceeded the amount of posts I can make in 5 minutes earlier and my reply to you was lost when I posted the whole code. I tried what you recommended and still received errors.

Yes, but you got a different error.

Why are you calling FollowBlock there anyway? I think you should probably delete that line entirely - you are already, in the camera() function, calling FollowBlock if there are any blocks there, and there you're doing it in a manner that looks likely to be what you intend.

What happened when you did what evanmars said was that the call within camera() was being called with the value from TrackBlock, which is assigned to a local variable TrackedBlock, while in loop, it's being called with the global variable TrackedBlock, which is always zero because you never assign another value....

DrAzzy:
Why are you calling FollowBlock there anyway?

First, thank you for all your replies and time with this topic.

When I first wrote the new code I didn't include the followBlock in loop().

I have a bi ped walking robot with the same camera and sensors, that does the same tasks I'm attempting to do here and that robot didn't need the followBlock in the loop to work.

With this robot the issue I had was the pan servo wouldn't follow the "blocks" (color) that is was supposed to. It would recognize the color and the robot would turn towards the color like I want. But it would keep turning beyond the color until the pan servo reached it's next maximum point (either RCS_MAX or RCS_MIN) then would start scanning again. In other words, it recognized color, but wouldn't track it anymore. I'm guessing I was incorrect that followBlock was the missing piece I needed in the loop().

One more quick note.
Any movements the robot does now, it continues to do that movement until the pan servo goes to a full position (RCS_MAX or RCS_MIN) before it will acquire anymore data and begin a new movement. That's why I put in the delay(500); in the loop. Doing that keeps the pan servo still while the robot turned, then the pan servo completes it's sweep and the robot then goes straight again.

My end result is to get real time updates throughout the panning process like it did before I put the IR sensor on.

I deleted the loop from the code I posted and moved the roaming commands into the original loop I had before I added the IR sensor.

void loop()
{
  read_Ir();
  uint16_t blocks;
  blocks = pixy.getBlocks();

  // If we have blocks in sight, track and follow them
  if (blocks)
  {
    int trackedBlock = TrackBlock(blocks);
    FollowBlock(trackedBlock);
    lastBlockTime = millis();
  }
  else if (millis() - lastBlockTime > 200)
  {
    ScanForBlocks();
    {
      if ((panLoop.m_pos < RCS_CENTER_POS) && ir > Middle && (millis() - lastBlockTime > 500))
      {
        motors.setLeftSpeed(+0);
        motors.setRightSpeed(+160);
      }
      else if ((panLoop.m_pos > RCS_CENTER_POS) && ir > Middle && (millis() - lastBlockTime > 500))
      {
        motors.setLeftSpeed(+160);
        motors.setRightSpeed(+0);
      }
    }
  }
}

int oldX, oldY, oldSignature;

The camera works, IR sensor works. The only issue is the pan servo needs to go to either end of it’s sweep before it stops whatever movement it was doing and acquires new data. Then it will do the appropriate action until the pan servo starts panning, once again it will continue the same movement and speed until the panning sweep is complete.

I think the issue is somewhere in here

int scanIncrement = (RCS_MAX_POS - RCS_MIN_POS) / 65;
uint32_t lastMove = 0;

void ScanForBlocks()
{
  if (millis() - lastMove > 20)
  {
    lastMove = millis();
    panLoop.m_pos += scanIncrement;
    if ((panLoop.m_pos >= RCS_MAX_POS) || (panLoop.m_pos <= RCS_MIN_POS))
    {
      tiltLoop.m_pos = (RCS_MAX_POS * 0.65);
      scanIncrement = -scanIncrement;
      if ((scanIncrement < 0) || (scanIncrement > 0))
      {
        motors.setLeftSpeed(+95);
        motors.setRightSpeed(+95);
      }
    }
    pixy.setServos(panLoop.m_pos, tiltLoop.m_pos);
  }
}

Specifically this if ((scanIncrement < 0) || (scanIncrement > 0))
Originally I only had (scanIncrement < 0) but then it would have to pan all the way from left to right and back to left before it would continue on. Adding the || > 0 fixed 50% of needless movements and works fine for object detection, but is not accurate enough for the camera. Any ideas how to correct that? Should I start a new topic?
Thanks again

This:

if ((scanIncrement < 0) || (scanIncrement > 0))

is a very convoluted and inefficient way of writing:

if (scanIncrement != 0)

Regards,
Ray L.

RayLivingston:
This:

if ((scanIncrement < 0) || (scanIncrement > 0))

is a very convoluted and inefficient way of writing:

if (scanIncrement != 0)

Regards,
Ray L.

Thanks! I’m always learning, especially how to clean the sketch up and be more efficient.
Do you have ideas how to get rid of that line all together? So the servo still pans but it’s not waiting to go to full right or left?

Scott_Callahan:
Specifically this if ((scanIncrement < 0) || (scanIncrement > 0))

That’s a difficult way of writing

if(scanIncrement != 0)

// Edit
OOPS, missed the second page; see now it was already mentioned.
// EndEdit

And you have a few other ones like that; e.g.

  if (forwardSpeed > 1 && forwardSpeed < 3)

How many possible values will result in that condition being true? Why not test for the single value?

:slight_smile: :slight_smile:

And there are more like that :wink:

OK, back to the scanIncrement variable
It gets an initial value of 16 (or so) here

int scanIncrement = (RCS_MAX_POS - RCS_MIN_POS) / 65;

And changes here

      scanIncrement = -scanIncrement;

Only possible values are 16 and -16; your test will always be true, so why test?

I’m just trying to make you think about your code :wink: I have no idea how it is supposed to work or how you think it works.

You may want to refresh yourself on functions. The Arduino site has a page on this (see below).

Arduino site: functions

There are also MANY youTube videos on writing C and C++ functions. Start with Pass by Value then it's a good idea to learn Pass by Reference.

sterretje:

  if (forwardSpeed > 1 && forwardSpeed < 3)

How many possible values will result in that condition being true? Why not test for the single value?

Thank you for everyones reply. I can’t answer all the questions because I simply don’t know a lot. That’s why I ask for help.
The the robot uses the size of what ever color it’s programed to see to judge it’s distance. It’s not very accurate for a scientific setting, but it’s accurate enough for how I use . In the code above, if I picked just one value (fowardSpeed > 1) then the robots makes obnoxious noises any time it’s driving forward. So I gave it the range of 1 to 3. 1 to 3 is so low and small the robot isn’t even moving at those values. That just plays a series of R2D2 beeps once before it chases something.

For the question on the scanIncrement the first quote of post sets the speed of the servo, the second one = -scanIncrement, sets the orientation of the servo. If I do = + scanIncrement everything is flip flopped.

Thanks again for everyones help.
I’ll continue working on it.
Scott