Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 49 additions & 62 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -279,37 +279,25 @@ $(sort $(CUSEROBJS)) : objects/%.o: %.c
-MP -MD -MF "${@:.o=.d}" -MT "$@" \
$< -o $@

# Ruckig files need C++20
RUCKIG_CXX_FILES := $(filter emc/tp/ruckig%,$(CXXUSERSRCS))
NON_RUCKIG_CXX_FILES := $(filter-out emc/tp/ruckig%,$(CXXUSERSRCS))

$(sort $(patsubst %.cpp,objects/%.o,$(filter %.cpp,$(RUCKIG_CXX_FILES)))) : objects/%.o: %.cpp
# Cruckig (pure C) source files — compiled as C, no C++ needed
# Headers are local ("" includes relative to cruckig/), no -I needed
objects/emc/tp/cruckig/%.o : emc/tp/cruckig/%.c
$(ECHO) Compiling $<
@mkdir -p $(dir $@)
@rm -f $@
$(Q)$(CXX) -c $(CXXFLAGS) $(EXTRAFLAGS) -std=c++20 \
-I$(BASEPWD)/emc/tp/ruckig/include \
-MP -MD -MF "${@:.o=.d}" -MT "$@" \
$< -o $@

$(sort $(patsubst %.cc,objects/%.o,$(filter %.cc,$(RUCKIG_CXX_FILES)))) : objects/%.o: %.cc
$(ECHO) Compiling $<
@mkdir -p $(dir $@)
@rm -f $@
$(Q)$(CXX) -c $(CXXFLAGS) $(EXTRAFLAGS) -std=c++20 \
-I$(BASEPWD)/emc/tp/ruckig/include \
$(Q)$(CC) -c $(CFLAGS) $(EXTRAFLAGS) \
-MP -MD -MF "${@:.o=.d}" -MT "$@" \
$< -o $@

$(sort $(patsubst %.cpp,objects/%.o,$(filter %.cpp,$(NON_RUCKIG_CXX_FILES)))) : objects/%.o: %.cpp
$(sort $(patsubst %.cpp,objects/%.o,$(filter %.cpp,$(CXXUSERSRCS)))) : objects/%.o: %.cpp
$(ECHO) Compiling $<
@mkdir -p $(dir $@)
@rm -f $@
$(Q)$(CXX) -c $(CXXFLAGS) $(EXTRAFLAGS) \
-MP -MD -MF "${@:.o=.d}" -MT "$@" \
$< -o $@

$(sort $(patsubst %.cc,objects/%.o,$(filter %.cc,$(NON_RUCKIG_CXX_FILES)))) : objects/%.o: %.cc
$(sort $(patsubst %.cc,objects/%.o,$(filter %.cc,$(CXXUSERSRCS)))) : objects/%.o: %.cc
$(ECHO) Compiling $<
@mkdir -p $(dir $@)
@rm -f $@
Expand Down Expand Up @@ -1198,17 +1186,25 @@ motmod-objs += emc/motion/stashf.o
motmod-objs += emc/motion/dbuf.o
motmod-objs += emc/tp/sp_scurve.o
motmod-objs += emc/tp/ruckig_wrapper.o
motmod-objs += emc/tp/ruckig/src/ruckig/brake.o
motmod-objs += emc/tp/ruckig/src/ruckig/position_first_step1.o
motmod-objs += emc/tp/ruckig/src/ruckig/position_first_step2.o
motmod-objs += emc/tp/ruckig/src/ruckig/position_second_step1.o
motmod-objs += emc/tp/ruckig/src/ruckig/position_second_step2.o
motmod-objs += emc/tp/ruckig/src/ruckig/position_third_step1.o
motmod-objs += emc/tp/ruckig/src/ruckig/position_third_step2.o
motmod-objs += emc/tp/ruckig/src/ruckig/velocity_second_step1.o
motmod-objs += emc/tp/ruckig/src/ruckig/velocity_second_step2.o
motmod-objs += emc/tp/ruckig/src/ruckig/velocity_third_step1.o
motmod-objs += emc/tp/ruckig/src/ruckig/velocity_third_step2.o
motmod-objs += emc/tp/cruckig/block.o
motmod-objs += emc/tp/cruckig/brake.o
motmod-objs += emc/tp/cruckig/calculator.o
motmod-objs += emc/tp/cruckig/cruckig.o
motmod-objs += emc/tp/cruckig/input_parameter.o
motmod-objs += emc/tp/cruckig/output_parameter.o
motmod-objs += emc/tp/cruckig/profile.o
motmod-objs += emc/tp/cruckig/roots.o
motmod-objs += emc/tp/cruckig/trajectory.o
motmod-objs += emc/tp/cruckig/position_first_step1.o
motmod-objs += emc/tp/cruckig/position_first_step2.o
motmod-objs += emc/tp/cruckig/position_second_step1.o
motmod-objs += emc/tp/cruckig/position_second_step2.o
motmod-objs += emc/tp/cruckig/position_third_step1.o
motmod-objs += emc/tp/cruckig/position_third_step2.o
motmod-objs += emc/tp/cruckig/velocity_second_step1.o
motmod-objs += emc/tp/cruckig/velocity_second_step2.o
motmod-objs += emc/tp/cruckig/velocity_third_step1.o
motmod-objs += emc/tp/cruckig/velocity_third_step2.o

obj-m += homemod.o
homemod-objs := emc/motion/homemod.o
Expand All @@ -1225,17 +1221,25 @@ tpmod-objs += emc/nml_intf/emcpose.o
tpmod-objs += libnml/posemath/_posemath.o
tpmod-objs += emc/tp/sp_scurve.o
tpmod-objs += emc/tp/ruckig_wrapper.o
tpmod-objs += emc/tp/ruckig/src/ruckig/brake.o
tpmod-objs += emc/tp/ruckig/src/ruckig/position_first_step1.o
tpmod-objs += emc/tp/ruckig/src/ruckig/position_first_step2.o
tpmod-objs += emc/tp/ruckig/src/ruckig/position_second_step1.o
tpmod-objs += emc/tp/ruckig/src/ruckig/position_second_step2.o
tpmod-objs += emc/tp/ruckig/src/ruckig/position_third_step1.o
tpmod-objs += emc/tp/ruckig/src/ruckig/position_third_step2.o
tpmod-objs += emc/tp/ruckig/src/ruckig/velocity_second_step1.o
tpmod-objs += emc/tp/ruckig/src/ruckig/velocity_second_step2.o
tpmod-objs += emc/tp/ruckig/src/ruckig/velocity_third_step1.o
tpmod-objs += emc/tp/ruckig/src/ruckig/velocity_third_step2.o
tpmod-objs += emc/tp/cruckig/block.o
tpmod-objs += emc/tp/cruckig/brake.o
tpmod-objs += emc/tp/cruckig/calculator.o
tpmod-objs += emc/tp/cruckig/cruckig.o
tpmod-objs += emc/tp/cruckig/input_parameter.o
tpmod-objs += emc/tp/cruckig/output_parameter.o
tpmod-objs += emc/tp/cruckig/profile.o
tpmod-objs += emc/tp/cruckig/roots.o
tpmod-objs += emc/tp/cruckig/trajectory.o
tpmod-objs += emc/tp/cruckig/position_first_step1.o
tpmod-objs += emc/tp/cruckig/position_first_step2.o
tpmod-objs += emc/tp/cruckig/position_second_step1.o
tpmod-objs += emc/tp/cruckig/position_second_step2.o
tpmod-objs += emc/tp/cruckig/position_third_step1.o
tpmod-objs += emc/tp/cruckig/position_third_step2.o
tpmod-objs += emc/tp/cruckig/velocity_second_step1.o
tpmod-objs += emc/tp/cruckig/velocity_second_step2.o
tpmod-objs += emc/tp/cruckig/velocity_third_step1.o
tpmod-objs += emc/tp/cruckig/velocity_third_step2.o
tpmod-objs += libnml/posemath/sincos.o $(MATHSTUB)

TORTOBJS = $(foreach file,$($(patsubst %.o,%,$(1))-objs), objects/rt$(file))
Expand All @@ -1257,7 +1261,7 @@ modules: $(patsubst %.o,../rtlib/%.so,$(obj-m))
RTFLAGS += -fno-strict-aliasing -fwrapv

# Rules to make .o (object) files for C files
$(sort $(filter-out objects/rtemc/tp/ruckig_wrapper.o objects/rtemc/tp/ruckig/src/ruckig/%,$(RTOBJS))) : objects/rt%.o : %.c
$(sort $(filter-out objects/rtemc/tp/cruckig/%,$(RTOBJS))) : objects/rt%.o : %.c
$(ECHO) Compiling realtime $<
@rm -f $@
@mkdir -p $(dir $@)
Expand All @@ -1266,30 +1270,13 @@ $(sort $(filter-out objects/rtemc/tp/ruckig_wrapper.o objects/rtemc/tp/ruckig/sr
-MP -MD -MF "${@:.o=.d}" -MT "$@" \
$< -o $@

# C++ flags for Ruckig: drop C-only -Wno-declaration-after-statement, and suppress
# false-positive -Warray-bounds and -Wunused-parameter in Ruckig library
RUCKIG_CXXFLAGS := $(filter-out -Wno-declaration-after-statement,$(EXTRA_CFLAGS)) \
-Wno-array-bounds -Wno-unused-parameter

# Rules for C++ .cc files in realtime modules
objects/rtemc/tp/ruckig_wrapper.o : emc/tp/ruckig_wrapper.cc
# Rules for cruckig C files in realtime modules
objects/rtemc/tp/cruckig/%.o : emc/tp/cruckig/%.c
$(ECHO) Compiling realtime $<
@rm -f $@
@mkdir -p $(dir $@)
$(Q)$(CXX) -c $(OPT) $(DEBUG) $(EXTRA_DEBUG) -DRTAPI -std=c++20 \
-I$(BASEPWD)/emc/tp/ruckig/include \
$(RUCKIG_CXXFLAGS) \
-MP -MD -MF "${@:.o=.d}" -MT "$@" \
$< -o $@

# Rules for C++ .cpp files in realtime modules
objects/rtemc/tp/ruckig/src/ruckig/%.o : emc/tp/ruckig/src/ruckig/%.cpp
$(ECHO) Compiling realtime $<
@rm -f $@
@mkdir -p $(dir $@)
$(Q)$(CXX) -c $(OPT) $(DEBUG) $(EXTRA_DEBUG) -DRTAPI -std=c++20 \
-I$(BASEPWD)/emc/tp/ruckig/include \
$(RUCKIG_CXXFLAGS) \
$(Q)$(CC) -c $(OPT) $(DEBUG) $(EXTRA_DEBUG) -DRTAPI \
$(EXTRA_CFLAGS) \
-MP -MD -MF "${@:.o=.d}" -MT "$@" \
$< -o $@
endif
Expand Down
40 changes: 24 additions & 16 deletions src/emc/motion-logger/Submakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,31 @@ MOTION_LOGGER_SRCS := \
emc/motion/axis.c \
emc/motion/simple_tp.c \
emc/tp/sp_scurve.c \
emc/tp/ruckig_wrapper.cc
emc/tp/ruckig_wrapper.c

RUCKIG_SRCS := \
emc/tp/ruckig/src/ruckig/brake.cpp \
emc/tp/ruckig/src/ruckig/position_first_step1.cpp \
emc/tp/ruckig/src/ruckig/position_first_step2.cpp \
emc/tp/ruckig/src/ruckig/position_second_step1.cpp \
emc/tp/ruckig/src/ruckig/position_second_step2.cpp \
emc/tp/ruckig/src/ruckig/position_third_step1.cpp \
emc/tp/ruckig/src/ruckig/position_third_step2.cpp \
emc/tp/ruckig/src/ruckig/velocity_second_step1.cpp \
emc/tp/ruckig/src/ruckig/velocity_second_step2.cpp \
emc/tp/ruckig/src/ruckig/velocity_third_step1.cpp \
emc/tp/ruckig/src/ruckig/velocity_third_step2.cpp
CRUCKIG_SRCS := \
emc/tp/cruckig/block.c \
emc/tp/cruckig/brake.c \
emc/tp/cruckig/calculator.c \
emc/tp/cruckig/cruckig.c \
emc/tp/cruckig/input_parameter.c \
emc/tp/cruckig/output_parameter.c \
emc/tp/cruckig/profile.c \
emc/tp/cruckig/roots.c \
emc/tp/cruckig/trajectory.c \
emc/tp/cruckig/position_first_step1.c \
emc/tp/cruckig/position_first_step2.c \
emc/tp/cruckig/position_second_step1.c \
emc/tp/cruckig/position_second_step2.c \
emc/tp/cruckig/position_third_step1.c \
emc/tp/cruckig/position_third_step2.c \
emc/tp/cruckig/velocity_second_step1.c \
emc/tp/cruckig/velocity_second_step2.c \
emc/tp/cruckig/velocity_third_step1.c \
emc/tp/cruckig/velocity_third_step2.c

USERSRCS += $(MOTION_LOGGER_SRCS) $(RUCKIG_SRCS)
USERSRCS += $(MOTION_LOGGER_SRCS) $(CRUCKIG_SRCS)

../bin/motion-logger: $(call TOOBJS, $(MOTION_LOGGER_SRCS) $(RUCKIG_SRCS)) ../lib/libnml.so.0 ../lib/liblinuxcnchal.so.0
../bin/motion-logger: $(call TOOBJS, $(MOTION_LOGGER_SRCS) $(CRUCKIG_SRCS)) ../lib/libnml.so.0 ../lib/liblinuxcnchal.so.0
$(ECHO) Linking $(notdir $@)
$(Q)$(CXX) $(LDFLAGS) -o $@ $^ -lm
$(Q)$(CC) $(LDFLAGS) -o $@ $^ -lm
4 changes: 4 additions & 0 deletions src/emc/tp/ruckig/LICENSE → src/emc/tp/cruckig/LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
MIT License

cruckig - Pure C99 port of the Ruckig trajectory generation library
Copyright (c) 2025 Yang Yang (mika-net@outlook.com)

Based on Ruckig (https://github.com/pantor/ruckig)
Copyright (c) 2021 Lars Berscheid

Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down
132 changes: 132 additions & 0 deletions src/emc/tp/cruckig/block.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "cruckig_compat.h"

#include "block.h"

static inline double cruckig_profile_total_duration(const CRuckigProfile *p) {
return p->t_sum[6] + p->brake.duration + p->accel.duration;
}

static void remove_profile(CRuckigProfile *valid_profiles, size_t *valid_profile_counter, size_t index) {
for (size_t i = index; i < *valid_profile_counter - 1; ++i) {
valid_profiles[i] = valid_profiles[i + 1];
}
*valid_profile_counter -= 1;
}

static void interval_from_profiles(CRuckigInterval *iv, const CRuckigProfile *profile_left, const CRuckigProfile *profile_right) {
const double left_duration = cruckig_profile_total_duration(profile_left);
const double right_duration = cruckig_profile_total_duration(profile_right);
if (left_duration < right_duration) {
iv->left = left_duration;
iv->right = right_duration;
iv->profile = *profile_right;
} else {
iv->left = right_duration;
iv->right = left_duration;
iv->profile = *profile_left;
}
iv->valid = true;
}

void cruckig_block_init(CRuckigBlock *block) {
cruckig_profile_init(&block->p_min);
block->t_min = 0.0;
block->a.valid = false;
block->b.valid = false;
}

void cruckig_block_set_min_profile(CRuckigBlock *block, const CRuckigProfile *profile) {
block->p_min = *profile;
block->t_min = cruckig_profile_total_duration(profile);
block->a.valid = false;
block->b.valid = false;
}

bool cruckig_block_calculate(CRuckigBlock *block, CRuckigProfile *valid_profiles,
size_t valid_profile_counter, size_t max_profiles) {
(void)max_profiles;

if (valid_profile_counter == 1) {
cruckig_block_set_min_profile(block, &valid_profiles[0]);
return true;

} else if (valid_profile_counter == 2) {
if (fabs(valid_profiles[0].t_sum[6] - valid_profiles[1].t_sum[6]) < 8 * DBL_EPSILON) {
cruckig_block_set_min_profile(block, &valid_profiles[0]);
return true;
}

/* numerical_robust = true */
{
const size_t idx_min = (valid_profiles[0].t_sum[6] < valid_profiles[1].t_sum[6]) ? 0 : 1;
const size_t idx_else_1 = (idx_min + 1) % 2;

cruckig_block_set_min_profile(block, &valid_profiles[idx_min]);
interval_from_profiles(&block->a, &valid_profiles[idx_min], &valid_profiles[idx_else_1]);
return true;
}

/* Only happens due to numerical issues */
} else if (valid_profile_counter == 4) {
/* Find "identical" profiles */
if (fabs(valid_profiles[0].t_sum[6] - valid_profiles[1].t_sum[6]) < 32 * DBL_EPSILON && valid_profiles[0].direction != valid_profiles[1].direction) {
remove_profile(valid_profiles, &valid_profile_counter, 1);
} else if (fabs(valid_profiles[2].t_sum[6] - valid_profiles[3].t_sum[6]) < 256 * DBL_EPSILON && valid_profiles[2].direction != valid_profiles[3].direction) {
remove_profile(valid_profiles, &valid_profile_counter, 3);
} else if (fabs(valid_profiles[0].t_sum[6] - valid_profiles[3].t_sum[6]) < 256 * DBL_EPSILON && valid_profiles[0].direction != valid_profiles[3].direction) {
remove_profile(valid_profiles, &valid_profile_counter, 3);
} else {
return false;
}

} else if (valid_profile_counter % 2 == 0) {
return false;
}

/* Find index of fastest profile */
size_t idx_min = 0;
for (size_t i = 1; i < valid_profile_counter; ++i) {
if (valid_profiles[i].t_sum[6] < valid_profiles[idx_min].t_sum[6]) {
idx_min = i;
}
}

cruckig_block_set_min_profile(block, &valid_profiles[idx_min]);

if (valid_profile_counter == 3) {
const size_t idx_else_1 = (idx_min + 1) % 3;
const size_t idx_else_2 = (idx_min + 2) % 3;

interval_from_profiles(&block->a, &valid_profiles[idx_else_1], &valid_profiles[idx_else_2]);
return true;

} else if (valid_profile_counter == 5) {
const size_t idx_else_1 = (idx_min + 1) % 5;
const size_t idx_else_2 = (idx_min + 2) % 5;
const size_t idx_else_3 = (idx_min + 3) % 5;
const size_t idx_else_4 = (idx_min + 4) % 5;

if (valid_profiles[idx_else_1].direction == valid_profiles[idx_else_2].direction) {
interval_from_profiles(&block->a, &valid_profiles[idx_else_1], &valid_profiles[idx_else_2]);
interval_from_profiles(&block->b, &valid_profiles[idx_else_3], &valid_profiles[idx_else_4]);
} else {
interval_from_profiles(&block->a, &valid_profiles[idx_else_1], &valid_profiles[idx_else_4]);
interval_from_profiles(&block->b, &valid_profiles[idx_else_2], &valid_profiles[idx_else_3]);
}
return true;
}

return false;
}

/* cruckig_block_is_blocked is now inlined in block.h */

const CRuckigProfile* cruckig_block_get_profile(const CRuckigBlock *block, double t) {
if (block->b.valid && t >= block->b.right) {
return &block->b.profile;
}
if (block->a.valid && t >= block->a.right) {
return &block->a.profile;
}
return &block->p_min;
}
37 changes: 37 additions & 0 deletions src/emc/tp/cruckig/block.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef CRUCKIG_BLOCK_H
#define CRUCKIG_BLOCK_H

#include "cruckig_compat.h"
#include "profile.h"
#include "cruckig_config.h"

typedef struct {
double left, right;
CRuckigProfile profile;
bool valid;
} CRuckigInterval;

typedef struct {
CRuckigProfile p_min;
double t_min;
CRuckigInterval a;
CRuckigInterval b;
} CRuckigBlock;

void cruckig_block_init(CRuckigBlock *block);
void cruckig_block_set_min_profile(CRuckigBlock *block, const CRuckigProfile *profile);

/* Calculate block from valid profiles. Returns true if successful. */
bool cruckig_block_calculate(CRuckigBlock *block, CRuckigProfile *valid_profiles,
size_t valid_profile_counter, size_t max_profiles);

/* Inlined for hot-path performance (called in tight synchronization loop) */
CRUCKIG_FORCE_INLINE bool cruckig_block_is_blocked(const CRuckigBlock *block, double t) {
return (t < block->t_min)
|| (block->a.valid && block->a.left < t && t < block->a.right)
|| (block->b.valid && block->b.left < t && t < block->b.right);
}

const CRuckigProfile* cruckig_block_get_profile(const CRuckigBlock *block, double t);

#endif /* CRUCKIG_BLOCK_H */
Loading
Loading