EV3 C-code for third party devices (I2C)

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 C-code for third party devices (I2C)

Post by HaWe »

no idea anybody why this effing btn press does not exit the program properly?
totokan
Posts: 45
Joined: 28 Sep 2013, 04:22

Re: EV3 C-code for third party devices (I2C)

Post by totokan »

Code: Select all

    sleep(1);
    if ( checkButtons() )  break;
There's your problem. What does sleep(1) do? How often will your if statement be evaluated?
Furthermore, in a traditional embedded system, you would want a button press to trigger an interrupt, but here we should just make sure the button press is getting checked in every part of the program. Make sure you check the button press in every loop, not just the main one, and make sure it causes functions to return a value (traditionally -1) that indicates to the caller that a button was pressed and it should exit.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 C-code for third party devices (I2C)

Post by HaWe »

I don't understand where you observe the problem.

Code: Select all

while(1)   {
    get_xg1300l_gyro(&angle, &rate, &acc_x, &acc_y, &acc_z);

    sprintf(buf,"Angle = %0.2f [deg]", angle);
    LcdText(1, 0, 10, buf);
    sprintf(buf,"Rate = %0.2f [deg/sec]", rate);
    LcdText(1, 0, 30, buf);
    //... SNIP
     
    sleep(1);
    if ( checkButtons() )  break;
  }

all the code is inside of a perpetual while loop.

sleep(1) waits 1ms before checking the buttons (CMIIW)

The buttons are then checked if pressed or not.
checkButtons returns (0) if no button is pressed and any positve value if one has been pressed.

So if no button is pressed the while loop continues (what it actually does)
and otherwise the while loop exits (what it actually does, too).

After it exits the loop, the program (sensor polling) stops (what it actually does))
and all moduls and devices are closed (what actually happens in some degree- but not correctly, apperently).

Code: Select all

close_xg1300l_gyro();

  OutputClose();
  OutputExit();
  ButtonLedClose();
  ButtonLedExit();
  LcdExit();
 
  return 1;
Where exactly is the mistake?
Last edited by HaWe on 09 Nov 2013, 15:28, edited 2 times in total.
totokan
Posts: 45
Joined: 28 Sep 2013, 04:22

Re: EV3 C-code for third party devices (I2C)

Post by totokan »

Does it exit if you are continually holding down the button?
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 C-code for third party devices (I2C)

Post by HaWe »

it is supposed to exit because it doesn't wait for btn-up.

strangely, I can't compile the code any longer, there suddenly is an error I didn't observe before:

Code: Select all

make: *** No rule to make target `lms2012.o', needed by `all'.  Stop.
here is the complete code:

Code: Select all

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include "lms2012.h"
#include "ev3_lcd.h"

#include <pthread.h>

#include "ev3_constants.h"
#include "ev3_command.h"
#include "ev3_button.h"
#include "ev3_timer.h"
#include "ev3_sound.h"
#include "ev3_output.h"


//Runtime constants
const int MAX_SAMPLES = 1000;

//Global variables and constants used by the sensor handling functions

const int XGL_PACKET_SIZE = 10; //2(gyyro angle) + 2(gyro rate) + 2(acc x) + 2(acc y) + 2(acc z)
const char XGL_PORT = 0x0; //The ports are designated as XGL_PORT_NUMBER-1
int xgl_device_file;

IIC *pXgl;

int init_xg1300l_gyro()
{
    IICDAT IicDat;
    char buf[120];

    //Open the device xgl_device_file
    if((xgl_device_file = open(IIC_DEVICE_NAME, O_RDWR | O_SYNC)) == -1)   {
      sprintf(buf, "Failed to open device");
      LcdText(1, 0, 110, buf);
      return 0;
    }

    pXgl = (IIC*)mmap(0, sizeof(IIC), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, xgl_device_file, 0);

    if (pXgl == MAP_FAILED)  {
      sprintf(buf, "Map failed");
      LcdText(1, 0, 110, buf);
      return 0;
    }

    //Setup IIC to read 2 packets
    IicDat.Port = XGL_PORT;
    IicDat.Time = 0;
    IicDat.Repeat = 0;
    IicDat.RdLng = XGL_PACKET_SIZE;
    IicDat.WrLng = 2;

    // Set the device I2C address
    IicDat.WrData[0] = 0x01;

    // Specify the register that will be read (0x42 = angle)
    IicDat.WrData[1] = 0x42;

    // Setup I2C comunication
    ioctl(xgl_device_file,IIC_SETUP,&IicDat);
    sprintf(buf,"Device is ready");
    LcdText(1, 0, 110, buf);

    return 1;
}

void get_xg1300l_gyro(float *angle, float *rate, float *acc_x, float *acc_y, float *acc_z)
{
    //Compute angle, angular rate and accelerations

    *acc_z = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][0]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][1])/100.0;
    *acc_y = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][2]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][3])/100.0;
    *acc_x = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][4]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][5])/100.0;
    *rate  = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][6]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][7])/100.0;
    *angle = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][8]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][9])/100.0;
}

void close_xg1300l_gyro()     //Close the device xgl_device_file
{
    char buf[120];

    sprintf(buf,"Closing device\n");
    LcdText(1, 0, 110, buf);

    close(xgl_device_file);
}

int main()
{
  int   i;
  char  buf[120];

  float angle;
  float rate;
  float acc_x;
  float acc_y;
  float acc_z;

  LcdInit();
  LcdClean();
  OutputInit();
  ButtonLedInit();

  if(!init_xg1300l_gyro())
      return -1;

  LcdClean();

  while(1)   {
    get_xg1300l_gyro(&angle, &rate, &acc_x, &acc_y, &acc_z);

    sprintf(buf,"Angle = %0.2f [deg]", angle);
    LcdText(1, 0, 10, buf);
    sprintf(buf,"Rate = %0.2f [deg/sec]", rate);
    LcdText(1, 0, 30, buf);
    sprintf(buf,"AccX = %0.2f [g]", acc_x);
    LcdText(1, 0, 50, buf);
    sprintf(buf,"AccY = %0.2f [g]", acc_y);
    LcdText(1, 0, 70, buf);
    sprintf(buf,"AccZ = %0.2f [g]", acc_z);
    LcdText(1, 0, 90, buf);

    sleep(1);
    if ( checkButtons() )  break;
  }

  close_xg1300l_gyro();

  OutputClose();
  OutputExit();
  ButtonLedClose();
  ButtonLedExit();
  LcdExit();

  return 1;
}
gloomyandy
Posts: 323
Joined: 29 Sep 2010, 05:03

Re: EV3 C-code for third party devices (I2C)

Post by gloomyandy »

Doc if that is a standard posix c library sleep call (i.e. it has not been redefined by some sort of macro), then it will be sleeping for 1 second not 1mS:
http://linux.die.net/man/3/sleep
you may want to use nanosleep or usleep instead.

As to your error, that seems to be some sort of makefile issue...
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 C-code for third party devices (I2C)

Post by HaWe »

I actually doubt that it's 1sec wait because the values have been changing insanely quick before (see Lauro's original code).
https://sourceforge.net/apps/phpbb/mind ... =10#p17585

About the make file thing: yes, sure, strangely, but why?
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 C-code for third party devices (I2C)

Post by HaWe »

now not at all Lauros code can be compiled - same error!

what the fu** ...
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 C-code for third party devices (I2C)

Post by HaWe »

Slowly I come to the conclusion that this C thing is such a mess that I guess I will finally have to abandon it.
I woud give any non-professional the advice to never try it ever (actually besides myself no one of the > 3500 members of our German forum already tried it ever - or dropped it in case he did, surely because of the same reasons).
lvoc
Posts: 38
Joined: 10 Sep 2013, 13:34

Re: EV3 C-code for third party devices (I2C)

Post by lvoc »

I observed similar issues as the ones you described. However, since I was successful running the button test program, I trued using ButtonWaitForAnyPress (used in the button test program) instead of checkButtons. This time the program worked as expected. The "sleep" function was there in the initial program to introduce one second delays between readings. You could comment it out if you need more frequent readings, alternatively you can use usleep (micro second sleep) to specify delays shorter than one second.

Regarding your concerns about John's functions not being compatible with the Lego “lms2012.h” include file. That should not be a problem, It is always possible to redefine some constants as needed (similar to what I did). That solution is even available with commercial (closed source) libraries.

Here is the code I tested:

Code: Select all

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include "lms2012.h"
#include "ev3_button.h"
#include "ev3_lcd.h"
   
//Runtime constants
const int MAX_SAMPLES = 1000;

//Global variables and constants used by the sensor handling functions

#define TITLE_DELAY 1000
const int XGL_PACKET_SIZE = 10; //2(gyyro angle) + 2(gyro rate) + 2(acc x) + 2(acc y) + 2(acc z)
const char XGL_PORT = 0x0; //The ports are designated as XGL_PORT_NUMBER-1
int xgl_device_file;

IIC *pXgl;

int init_xg1300l_gyro()
{
    IICDAT IicDat;
    char buf[120];

    //Open the device xgl_device_file
    if((xgl_device_file = open(IIC_DEVICE_NAME, O_RDWR | O_SYNC)) == -1)   {
      sprintf(buf, "Failed to open device");
      LcdText(1, 0, 60, buf);
      return 0;
    }

    pXgl = (IIC*)mmap(0, sizeof(IIC), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, xgl_device_file, 0);

    if (pXgl == MAP_FAILED)  {
      sprintf(buf, "Map failed");
      LcdText(1, 0, 60, buf);
      return 0;
    }
   
    //Setup IIC to read 2 packets
    IicDat.Port = XGL_PORT;
    IicDat.Time = 0;
    IicDat.Repeat = 0;
    IicDat.RdLng = XGL_PACKET_SIZE;
    IicDat.WrLng = 2;
   
    // Set the device I2C address
    IicDat.WrData[0] = 0x01;
   
    // Specify the register that will be read (0x42 = angle)
    IicDat.WrData[1] = 0x42;
   
    // Setup I2C comunication
    ioctl(xgl_device_file,IIC_SETUP,&IicDat);
    sprintf(buf,"Device is ready");
    LcdText(1, 0, 60, buf);
   
    return 1;
}

void get_xg1300l_gyro(float *angle, float *rate, float *acc_x, float *acc_y, float *acc_z)
{
    //Compute angle, angular rate and accelerations
   
    *acc_z = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][0]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][1])/100.0;
    *acc_y = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][2]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][3])/100.0;
    *acc_x = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][4]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][5])/100.0;
    *rate  = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][6]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][7])/100.0;
    *angle = (pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][8]*256+pXgl->Raw[XGL_PORT][pXgl->Actual[XGL_PORT]][9])/100.0;
}

void close_xg1300l_gyro()     //Close the device xgl_device_file
{
	char buf[120];

	sprintf(buf,"Closing device\n");
	LcdText(1, 0, 60, buf);

	close(xgl_device_file);
}

int main()
{
  char  buf[120];

  float angle;
  float rate;
  float acc_x;
  float acc_y;
  float acc_z; 
   
  ButtonLedInit();
  LcdInit();
  LcdClean();

  if(!init_xg1300l_gyro())
      return -1;

  LcdClean();

  while(1)
	{
    get_xg1300l_gyro(&angle, &rate, &acc_x, &acc_y, &acc_z);
   
    sprintf(buf,"Angle = %0.2f [deg]", angle);
    LcdText(1, 0, 10, buf);
    sprintf(buf,"Rate = %0.2f [deg/sec]", rate);
    LcdText(1, 0, 30, buf);
    sprintf(buf,"AccX = %0.2f [g]", acc_x);
    LcdText(1, 0, 50, buf);
    sprintf(buf,"AccY = %0.2f [g]", acc_y);
    LcdText(1, 0, 70, buf);
    sprintf(buf,"AccZ = %0.2f [g]", acc_z);
    LcdText(1, 0, 90, buf);
  	if(ButtonWaitForAnyPress(TITLE_DELAY) == BUTTON_ID_ESCAPE)
			break;
    sleep(1);
  }

  close_xg1300l_gyro();
  LcdExit();
  ButtonLedExit();
  return 1;
}

Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests