Remora - ethernet NVEM / EC300 / EC500 cnc board
18 Sep 2024 20:40 #310413
by scotta
Replied by scotta on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
Hi, unfortunately no. The QEI is for the STM32 based boards, the QDC for the RT1052. These refer to the decoding circuits integrated into the MCUs. The QDC has the capability to count a single channel, but the current software implementation cannot take advantage it.
Please Log in or Create an account to join the conversation.
18 Sep 2024 20:53 #310415
by Murphy
Replied by Murphy on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
How hard is it to get the single A pulse and Z index working for the spindle? Is it going to be future update ?
Please Log in or Create an account to join the conversation.
18 Sep 2024 23:09 #310419
by cakeslob
Replied by cakeslob on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
for user xaxexa, when you say one pulse output , are you referring to it as only an A channel (x pulse/revolution) or do you mean it is a single pulse like an index channel where 1 pulse/revolution ?
if it is the index channel, you could probably implement it.
Echo to Murphy, we could benefit from having the option for only A/Z as it seems common for lathe users, , Myself and other users are finding increasing need for a non quadratic option so the encoder module can be used for MPG. Using Encoder module vs DIgitial IO for an MPG is a cleaner hal file, but also using digital IO for MPG uses 12% of the available inputs on the SPI version
if it is the index channel, you could probably implement it.
Echo to Murphy, we could benefit from having the option for only A/Z as it seems common for lathe users, , Myself and other users are finding increasing need for a non quadratic option so the encoder module can be used for MPG. Using Encoder module vs DIgitial IO for an MPG is a cleaner hal file, but also using digital IO for MPG uses 12% of the available inputs on the SPI version
The following user(s) said Thank You: Murphy
Please Log in or Create an account to join the conversation.
20 Sep 2024 03:06 #310486
by xaxexa
Replied by xaxexa on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
look, the square encoder gives us the direction and frequency, you can also calculate the angle and so on, depending on the accuracy of the encoder, the Z channel allows you to refer to the position of something, for the MPG Z is not needed, for stepper motor feedback, I would choose a diver with encoder support, and now I want feedback of the spindle speed, in theory it can be implemented using A encoder channel, or the Z channel theoretically could also give such functionality, I don’t need to cut threads, just feedback of revolutions per minute
Please Log in or Create an account to join the conversation.
20 Sep 2024 14:31 #310517
by xaxexa
Replied by xaxexa on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
Today I was sitting with a frequency generator
my notes, if you enter only channel A in txt, the counter counts 0,1,0,1,0,1 instead of 0,1,2,3,4,5, there is no acceleration, and velocity = 0
if you connect A and B to the same pin, then at a low frequency the counter is 0, apparently the board understands that the pulse comes at the same time, if you increase the frequency above 1 kHz, errors begin, and the counter begins to increase or decrease non-linearly, well, it seems the simplest thing is to exclude channel B from the calculation, but I don't have the knowledge at all to write such a commit...
and I also need to use the PRU encoder module, not just an encoder, right?
my notes, if you enter only channel A in txt, the counter counts 0,1,0,1,0,1 instead of 0,1,2,3,4,5, there is no acceleration, and velocity = 0
if you connect A and B to the same pin, then at a low frequency the counter is 0, apparently the board understands that the pulse comes at the same time, if you increase the frequency above 1 kHz, errors begin, and the counter begins to increase or decrease non-linearly, well, it seems the simplest thing is to exclude channel B from the calculation, but I don't have the knowledge at all to write such a commit...
and I also need to use the PRU encoder module, not just an encoder, right?
Please Log in or Create an account to join the conversation.
29 Sep 2024 19:32 #311041
by aDm1N
Replied by aDm1N on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
The fact that I couldn't flash the board is because it is defective for whatever reason. Is on the way back now. Now I'm wondering what happens next. Of course, getting a new NVEM would work. or would an EC300 or EC500 be a better choice? A standard MPG should be connected with individual cables, so an NVEM is probably easier at first. Mesa cards are hard to come by right now, or much more expensive. If you were faced with a choice right now, what would your decision be?
Please Log in or Create an account to join the conversation.
02 Oct 2024 15:22 - 02 Oct 2024 15:24 #311181
by xaxexa
Replied by xaxexa on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
help me figure it out, I'm still trying to make a frequency counter on one wire, with a QDC module, I found a solution, now in the variable pv0 I see a growing counter, with an adequate frequency exactly the same as on the frequency generator, I took the Linux module "counter", removed everything unnecessary from it, connected pv0 with raw_counts I see the value velocity, but it is with an accuracy of 1 kilohertz, how to reduce it to 1 hertz??? is this related to the servo thread refresh rate?
#include "rtapi.h" /* RTAPI realtime OS API */
#include "rtapi_app.h" /* RTAPI realtime module decls */
#include "rtapi_errno.h" /* EINVAL etc */
#include "hal.h" /* HAL public API decls */
#define MODNAME "PRUcounter"
/* module information */
MODULE_AUTHOR("Chris Radek");
MODULE_DESCRIPTION("Pulse Counter for EMC HAL");
MODULE_LICENSE("GPL");
static int num_chan = 1; /* number of channels - default = 1 */
RTAPI_MP_INT(num_chan, "number of channels");
/***********************************************************************
* STRUCTURES AND GLOBAL VARIABLES *
************************************************************************/
/* this structure contains the runtime data for a single counter */
typedef struct {
hal_float_t *raw_count; /* pin: raw binary count value */
hal_float_t *vel; /* scaled velocity (floating point) */
hal_float_t *pos_scale; /* pin: scaling factor for pos */
double old_scale; /* stored scale value */
double scale; /* reciprocal value used for scaling */
hal_s32_t last_count;
} counter_t;
/* pointer to array of counter_t structs in shmem, 1 per counter */
static counter_t *counter_array;
/* other globals */
static int comp_id; /* component ID */
/***********************************************************************
* LOCAL FUNCTION DECLARATIONS *
************************************************************************/
static int export_counter(int num, counter_t * addr);
static void update(void *arg, long period);
static void capture(void *arg, long period);
/***********************************************************************
* INIT AND EXIT CODE *
************************************************************************/
#define MAX_CHAN 8
int rtapi_app_main(void)
{
int n, retval;
/* test for number of channels */
if ((num_chan <= 0) || (num_chan > MAX_CHAN)) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: invalid num_chan: %d\n", num_chan);
return -EINVAL;
}
/* have good config info, connect to the HAL */
comp_id = hal_init("PRUcounter");
if (comp_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "COUNTER: ERROR: hal_init() failed\n");
return -EINVAL;
}
/* allocate shared memory for counter data */
counter_array = hal_malloc(num_chan * sizeof(counter_t));
if (!counter_array) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: hal_malloc() failed\n");
hal_exit(comp_id);
return -ENOMEM;
}
/* export all the variables for each counter */
for (n = 0; n < num_chan; n++) {
/* export all vars */
retval = export_counter(n, &;(counter_array[n]));
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: counter %d var export failed\n", n);
hal_exit(comp_id);
return -EIO;
}
/* init counter */
*(counter_array[n].raw_count) = 0;
*(counter_array[n].pos_scale) = 1.0;
counter_array[n].old_scale = 1.0;
counter_array[n].scale = 1.0;
}
/* export functions */
retval = hal_export_funct("PRUcounter.update-counters", update,
counter_array, 0, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: count funct export failed\n");
hal_exit(comp_id);
return -EIO;
}
retval = hal_export_funct("PRUcounter.capture-position", capture,
counter_array, 1, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: capture funct export failed\n");
hal_exit(comp_id);
return -EIO;
}
rtapi_print_msg(RTAPI_MSG_INFO,
"COUNTER: installed %d counter counters\n", num_chan);
hal_ready(comp_id);
return 0;
}
void rtapi_app_exit(void)
{
hal_exit(comp_id);
}
/***********************************************************************
* REALTIME COUNTER COUNTING AND UPDATE FUNCTIONS *
************************************************************************/
static void update(void *arg, long period)
{
counter_t *cntr;
int n;
for (cntr = arg, n = 0; n < num_chan; cntr++, n++) {
// count on rising edge
(*cntr->raw_count)++;
}
}
static void capture(void *arg, long period)
{
counter_t *cntr;
int n;
for (cntr = arg, n = 0; n < num_chan; cntr++, n++) {
/* check reset input */
int raw_count;
int counts;
/* capture raw counts to latches */
raw_count = *(cntr->raw_count);
counts = (raw_count - cntr->last_count);
cntr->last_count = raw_count;
/* check for change in scale value */
if ( *(cntr->pos_scale) != cntr->old_scale ) {
/* save new scale to detect future changes */
cntr->old_scale = *(cntr->pos_scale);
/* scale value has changed, test and update it */
if ((*(cntr->pos_scale) < 1e-20) && (*(cntr->pos_scale) > -1e-20)) {
/* value too small, divide by zero is a bad thing */
*(cntr->pos_scale) = 1.0;
}
/* we actually want the reciprocal */
cntr->scale = 1.0 / *(cntr->pos_scale);
}
/* scale counts to make floating point velocity */
*(cntr->vel) = counts * cntr->scale * 1e9 / period;
}
}
/***********************************************************************
* LOCAL FUNCTION DEFINITIONS *
************************************************************************/
static int export_counter(int num, counter_t * addr)
{
int retval, msg;
/* This function exports a lot of stuff, which results in a lot of
logging if msg_level is at INFO or ALL. So we save the current value
of msg_level and restore it later. If you actually need to log this
function's actions, change the second line below */
msg = rtapi_get_msg_level();
rtapi_set_msg_level(RTAPI_MSG_WARN);
/* export parameter for raw counts */
retval = hal_pin_float_newf(HAL_IN, &;(addr->raw_count), comp_id,"counter.%d.raw_count", num);
if (retval != 0) {
return retval;
}
/* export pin for scaled velocity captured by capture() */
retval = hal_pin_float_newf(HAL_OUT, &;(addr->vel), comp_id, "counter.%d.velocity", num);
if (retval != 0) {
return retval;
}
/* export parameter for scaling */
retval = hal_pin_float_newf(HAL_IO, &;(addr->pos_scale), comp_id, "counter.%d.position-scale", num);
if (retval != 0) {
return retval;
}
/* restore saved message level */
rtapi_set_msg_level(msg);
return 0;
}
Warning: Spoiler!
#include "rtapi.h" /* RTAPI realtime OS API */
#include "rtapi_app.h" /* RTAPI realtime module decls */
#include "rtapi_errno.h" /* EINVAL etc */
#include "hal.h" /* HAL public API decls */
#define MODNAME "PRUcounter"
/* module information */
MODULE_AUTHOR("Chris Radek");
MODULE_DESCRIPTION("Pulse Counter for EMC HAL");
MODULE_LICENSE("GPL");
static int num_chan = 1; /* number of channels - default = 1 */
RTAPI_MP_INT(num_chan, "number of channels");
/***********************************************************************
* STRUCTURES AND GLOBAL VARIABLES *
************************************************************************/
/* this structure contains the runtime data for a single counter */
typedef struct {
hal_float_t *raw_count; /* pin: raw binary count value */
hal_float_t *vel; /* scaled velocity (floating point) */
hal_float_t *pos_scale; /* pin: scaling factor for pos */
double old_scale; /* stored scale value */
double scale; /* reciprocal value used for scaling */
hal_s32_t last_count;
} counter_t;
/* pointer to array of counter_t structs in shmem, 1 per counter */
static counter_t *counter_array;
/* other globals */
static int comp_id; /* component ID */
/***********************************************************************
* LOCAL FUNCTION DECLARATIONS *
************************************************************************/
static int export_counter(int num, counter_t * addr);
static void update(void *arg, long period);
static void capture(void *arg, long period);
/***********************************************************************
* INIT AND EXIT CODE *
************************************************************************/
#define MAX_CHAN 8
int rtapi_app_main(void)
{
int n, retval;
/* test for number of channels */
if ((num_chan <= 0) || (num_chan > MAX_CHAN)) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: invalid num_chan: %d\n", num_chan);
return -EINVAL;
}
/* have good config info, connect to the HAL */
comp_id = hal_init("PRUcounter");
if (comp_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "COUNTER: ERROR: hal_init() failed\n");
return -EINVAL;
}
/* allocate shared memory for counter data */
counter_array = hal_malloc(num_chan * sizeof(counter_t));
if (!counter_array) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: hal_malloc() failed\n");
hal_exit(comp_id);
return -ENOMEM;
}
/* export all the variables for each counter */
for (n = 0; n < num_chan; n++) {
/* export all vars */
retval = export_counter(n, &;(counter_array[n]));
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: counter %d var export failed\n", n);
hal_exit(comp_id);
return -EIO;
}
/* init counter */
*(counter_array[n].raw_count) = 0;
*(counter_array[n].pos_scale) = 1.0;
counter_array[n].old_scale = 1.0;
counter_array[n].scale = 1.0;
}
/* export functions */
retval = hal_export_funct("PRUcounter.update-counters", update,
counter_array, 0, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: count funct export failed\n");
hal_exit(comp_id);
return -EIO;
}
retval = hal_export_funct("PRUcounter.capture-position", capture,
counter_array, 1, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"COUNTER: ERROR: capture funct export failed\n");
hal_exit(comp_id);
return -EIO;
}
rtapi_print_msg(RTAPI_MSG_INFO,
"COUNTER: installed %d counter counters\n", num_chan);
hal_ready(comp_id);
return 0;
}
void rtapi_app_exit(void)
{
hal_exit(comp_id);
}
/***********************************************************************
* REALTIME COUNTER COUNTING AND UPDATE FUNCTIONS *
************************************************************************/
static void update(void *arg, long period)
{
counter_t *cntr;
int n;
for (cntr = arg, n = 0; n < num_chan; cntr++, n++) {
// count on rising edge
(*cntr->raw_count)++;
}
}
static void capture(void *arg, long period)
{
counter_t *cntr;
int n;
for (cntr = arg, n = 0; n < num_chan; cntr++, n++) {
/* check reset input */
int raw_count;
int counts;
/* capture raw counts to latches */
raw_count = *(cntr->raw_count);
counts = (raw_count - cntr->last_count);
cntr->last_count = raw_count;
/* check for change in scale value */
if ( *(cntr->pos_scale) != cntr->old_scale ) {
/* save new scale to detect future changes */
cntr->old_scale = *(cntr->pos_scale);
/* scale value has changed, test and update it */
if ((*(cntr->pos_scale) < 1e-20) && (*(cntr->pos_scale) > -1e-20)) {
/* value too small, divide by zero is a bad thing */
*(cntr->pos_scale) = 1.0;
}
/* we actually want the reciprocal */
cntr->scale = 1.0 / *(cntr->pos_scale);
}
/* scale counts to make floating point velocity */
*(cntr->vel) = counts * cntr->scale * 1e9 / period;
}
}
/***********************************************************************
* LOCAL FUNCTION DEFINITIONS *
************************************************************************/
static int export_counter(int num, counter_t * addr)
{
int retval, msg;
/* This function exports a lot of stuff, which results in a lot of
logging if msg_level is at INFO or ALL. So we save the current value
of msg_level and restore it later. If you actually need to log this
function's actions, change the second line below */
msg = rtapi_get_msg_level();
rtapi_set_msg_level(RTAPI_MSG_WARN);
/* export parameter for raw counts */
retval = hal_pin_float_newf(HAL_IN, &;(addr->raw_count), comp_id,"counter.%d.raw_count", num);
if (retval != 0) {
return retval;
}
/* export pin for scaled velocity captured by capture() */
retval = hal_pin_float_newf(HAL_OUT, &;(addr->vel), comp_id, "counter.%d.velocity", num);
if (retval != 0) {
return retval;
}
/* export parameter for scaling */
retval = hal_pin_float_newf(HAL_IO, &;(addr->pos_scale), comp_id, "counter.%d.position-scale", num);
if (retval != 0) {
return retval;
}
/* restore saved message level */
rtapi_set_msg_level(msg);
return 0;
}
Last edit: 02 Oct 2024 15:24 by xaxexa.
Please Log in or Create an account to join the conversation.
02 Oct 2024 16:10 #311187
by xaxexa
Replied by xaxexa on topic Remora - ethernet NVEM / EC300 / EC500 cnc board
figured it out, yes it is connected with the servo thread speed... I will continue to do it...
The following user(s) said Thank You: Murphy
Please Log in or Create an account to join the conversation.
Time to create page: 0.181 seconds