How to output on custom device block?

3 次查看(过去 30 天)
Greetings,
I am having trouble with my Device Driver Block.
It never outputs a 1 even though I have confirmed that the device is connecting via the Arduino IDE and a Logic Analyzer. Where am I going wrong?
Have a look at the wrapper code:
#include "C:\Users\Coach\MATLAB Drive\DriverBlocks\RoboClaw\RoboClawDriver.h"
#include <Arduino.h>
#include "RoboClaw.h"
// SerialPins uint8 [2,1] Non tunable
HardwareSerial *hSerial = &Serial1;
RoboClaw myRoboClaw(hSerial, 2000);
void setupFunctionRoboClawDriver(uint8_T * SerialPins,int size_vector__1){
hSerial->begin(38400);
Serial.println("Testing Connection");
char version[32];
if (myRoboClaw.ReadVersion(0x80, version)) {
Serial.println("Connected to the RoboClaw!");
} else {
Serial.println("Failed to read RoboClaw version.");
}
}
void stepFunctionRoboClawDriver(boolean_T *Connected,int size_vector_1){
int retries = 3;
char version[32];
while(retries-- > 0){
if(myRoboClaw.ReadVersion(0x80, version)) {
*Connected = true;
Serial.println(*Connected);
break;
} else {
*Connected = false;
Serial.println("Error");
}
}
if (!*Connected) {
Serial.println("Failed to connect to RoboClaw after retries.");
}
delay(10);
}
In my System Object Code, I am asking it to send the output of the wrapper to the output port on my block. I can see it works in simulation mode. However, it does not work in external mode.
classdef RoboClawDriver < matlab.System ...
& coder.ExternalDependency ...
& matlabshared.sensors.simulink.internal.BlockSampleTime
% RoboClaw Arduino Driver
%#codegen
%#ok<*EMCA>
properties
end
properties(Access = protected)
Logo = 'IO Device Builder';
end
properties (Nontunable)
SerialPins = uint8([10;11]);
end
properties (Access = private)
end
methods
% Constructor
function obj = RoboClawDriver(varargin)
setProperties(obj,nargin,varargin{:});
end
end
methods (Access=protected)
function setupImpl(obj)
if ~coder.target('MATLAB')
coder.cinclude('RoboClawDriver.h');
coder.ceval('setupFunctionRoboClawDriver', (obj.SerialPins),2);
end
end
function validateInputsImpl(obj,varargin)
% Check the input size
if nargin ~=0
end
end
function Connected = stepImpl(obj)
Connected = boolean(zeros(1,1));
if isempty(coder.target)
Connected = true;
else
coder.ceval('stepFunctionRoboClawDriver',coder.ref(Connected),1);
end
end
function releaseImpl(obj)
if isempty(coder.target)
else
end
end
end
methods (Access=protected)
%% Define output properties
function num = getNumInputsImpl(~)
num = 0;
end
function num = getNumOutputsImpl(~)
num = 1;
end
function varargout = getInputNamesImpl(obj)
end
function varargout = getOutputNamesImpl(obj)
varargout{1} = 'Connected';
end
function flag = isOutputSizeLockedImpl(~,~)
flag = true;
end
function varargout = isOutputFixedSizeImpl(~,~)
varargout{1} = true;
end
function varargout = isOutputComplexImpl(~)
varargout{1} = false;
end
function varargout = getOutputSizeImpl(~)
varargout{1} = [1,1];
end
function varargout = getOutputDataTypeImpl(~)
varargout{1} = 'boolean';
end
function maskDisplayCmds = getMaskDisplayImpl(obj)
outport_label = [];
num = getNumOutputsImpl(obj);
if num > 0
outputs = cell(1,num);
[outputs{1:num}] = getOutputNamesImpl(obj);
for i = 1:num
outport_label = [outport_label 'port_label(''output'',' num2str(i) ',''' outputs{i} ''');' ]; %#ok<AGROW>
end
end
inport_label = [];
num = getNumInputsImpl(obj);
if num > 0
inputs = cell(1,num);
[inputs{1:num}] = getInputNamesImpl(obj);
for i = 1:num
inport_label = [inport_label 'port_label(''input'',' num2str(i) ',''' inputs{i} ''');' ]; %#ok<AGROW>
end
end
icon = 'RoboClawDriver';
maskDisplayCmds = [ ...
['color(''white'');',...
'plot([100,100,100,100]*1,[100,100,100,100]*1);',...
'plot([100,100,100,100]*0,[100,100,100,100]*0);',...
'color(''blue'');', ...
['text(38, 92, ','''',obj.Logo,'''',',''horizontalAlignment'', ''right'');',newline],...
'color(''black'');'], ...
['text(52,50,' [''' ' icon ''',''horizontalAlignment'',''center'');' newline]] ...
inport_label ...
outport_label
];
end
function sts = getSampleTimeImpl(obj)
sts = getSampleTimeImpl@matlabshared.sensors.simulink.internal.BlockSampleTime(obj);
end
end
methods (Static, Access=protected)
function simMode = getSimulateUsingImpl(~)
simMode = 'Interpreted execution';
end
function isVisible = showSimulateUsingImpl
isVisible = false;
end
end
methods (Static)
function name = getDescriptiveName(~)
name = 'RoboClawDriver';
end
function tf = isSupportedContext(~)
tf = true;
end
function updateBuildInfo(buildInfo, context)
coder.extrinsic('codertarget.targethardware.getTargetHardware');
hCS = coder.const(getActiveConfigSet(bdroot));
targetInfo = coder.const(codertarget.targethardware.getTargetHardware(hCS));
% Added this env variable to fetch the comm libraries required only for Arduino target.
% The env variable is cleared at the end of
% "GenerateWrapperMakefile.m" file.
if contains(targetInfo.TargetName,'arduinotarget')
setenv('Arduino_ML_Codegen_I2C', 'Y');
end
addDefines(buildInfo, '__AVR__');
addIncludePaths(buildInfo, 'C:\ProgramData\MATLAB\SupportPackages\R2024b\aCLI\data\packages\arduino\hardware\avr\1.8.3\libraries\SoftwareSerial\src');
addSourceFiles(buildInfo, 'SoftwareSerial.cpp', 'C:\ProgramData\MATLAB\SupportPackages\R2024b\aCLI\data\packages\arduino\hardware\avr\1.8.3\libraries\SoftwareSerial\src');
buildInfo.addIncludePaths('C:\Users\Coach\Downloads\arduino\RoboClaw');
buildInfo.addIncludePaths('C:\Users\Coach\MATLAB Drive\DriverBlocks\RoboClaw');
addSourceFiles(buildInfo,'RoboClaw.cpp','C:\Users\Coach\Downloads\arduino\RoboClaw');
addSourceFiles(buildInfo,'RoboClawDriver.cpp','C:\Users\Coach\MATLAB Drive\DriverBlocks\RoboClaw');
end
end
end
  4 个评论
Clayton Allen
Clayton Allen 2024-11-28
I tried several permutations of the following solution. And still can't get the outputs to work.
extern "C" void stepFunctionRoboClaw_ReadTemp(uint8_t address, int32_t *temp, bool *valid) {
delay(100);
uint16_t temperature;
bool isValid = myRoboClaw.ReadTemp(address, temperature);
Serial.println(temperature);
*temp = static_cast<int32_t>(temperature); // Convert uint16_t to int32_t for MATLAB compatibility
*valid = isValid;
Serial.print("Address: ");
Serial.println(address);
Serial.print("Temperature: ");
Serial.println(*temp);
Serial.print("Valid: ");
Serial.println(*valid);
}
The above code will print to the Serial Monitor of the Arduino IDE just fine as long as I comment out the ReadVersion as seen below.
void stepFunctionRoboClaw_Basic_Driver(bool * Connected_Status,int size_vector_1,uint32_T * L_Encoder,int size_vector_2,uint32_T * R_Encoder,int size_vector_3,uint32_T * L_Motor_Speed,int size_vector_4,uint32_T * R_MotorSpeed,int size_vector_5,uint8_T L_Motor_Cmd,int size_vector_a,uint8_T R_Motor_Cmd,int size_vector_b){
// delay(100);
// char version[32];
// Serial.println("Requesting Version...");
// bool success = myRoboClaw.ReadVersion(0x80, version);
//
// if (success) {
// Connected_Status = 1;
// Serial.print("Version: ");
// Serial.println(version);
// } else {
// Connected_Status = 0;
// Serial.println("Failed to read version.");
// }
}
I notice the Serial Monitor will eventually show 0s in the temp and valid lines
function [Connected_Status,L_Encoder,R_Encoder,L_Motor_Speed,R_MotorSpeed, Temperature] = stepImpl(obj ,L_Motor_Cmd,R_Motor_Cmd)
Connected_Status = boolean(zeros(1,1));
L_Encoder = uint32(zeros(1,1));
R_Encoder = uint32(zeros(1,1));
L_Motor_Speed = uint32(zeros(1,1));
R_MotorSpeed = uint32(zeros(1,1));
Temperature = int32(zeros(1, 1)); % Add Temperature as an output
if isempty(coder.target)
else
temp = int32(0);
valid = false;
coder.ceval('stepFunctionRoboClaw_ReadTemp', uint8(128), coder.ref(temp), coder.ref(valid));
Temperature = temp; % Assign output
coder.ceval('stepFunctionRoboClaw_Basic_Driver',coder.ref(Connected_Status),1,coder.ref(L_Encoder),1,coder.ref(R_Encoder),1,coder.ref(L_Motor_Speed),1,coder.ref(R_MotorSpeed),1, L_Motor_Cmd,1, R_Motor_Cmd,1);
end
end
This is how I am calling it in the object. Nothing but 0s...
Clayton Allen
Clayton Allen 2024-11-29
This is so FRUSTRATING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
I am STILL NOT getting the output ports to display anything!!!!!!!!!!!!!!!!!!!!! Even with hardcoded values.
#include "C:\Users\Coach\MATLAB Drive\DriverBlocks\motorDriver\include\motorDriver.h"
#include <Arduino.h>
#include "RoboClaw.h"
HardwareSerial *hSerial = &Serial1;
RoboClaw myRoboClaw(hSerial,2000);
extern "C" void setupFunction() {
delay(100);
hSerial->begin(38400);
Serial.println("Setup");
}
extern "C" void stepFunction(uint8_T address, int32_T *temp, boolean_T *valid) {
delay(100);
uint16_t temperature;
bool isValid = myRoboClaw.ReadTemp(address, temperature);
*temp = static_cast<int32_t>(temperature);
*valid = isValid;
Serial.print("Temperature: ");
Serial.println(temperature);
Serial.print("Valid: ");
Serial.println(isValid);
}
and
#ifndef _MOTORDRIVER_H
#define _MOTORDRIVER_H
#if !( defined(MATLAB_MEX_FILE) || defined(RSIM_PARAMETER_LOADING) || defined(RSIM_WITH_SL_SOLVER))
#include "rtwtypes.h"
#ifdef __cplusplus
extern "C" {
#endif
void stepFunction(uint8_T address, int32_T *temp, boolean_T *valid);
void setupFunction();
#ifdef __cplusplus
}
#endif
#else
#define loop(void) (0)
#define setup(void) (0)
#endif
#endif
and
classdef MotorDriver < matlab.System & coder.ExternalDependency
% Another attempt to implement the RoboClaw Driver at an ever futher
% incremental level. I hope this doesn't suck.
%#codegen
%#ok<*EMCA>
properties
% Public, tunable properties.
end
properties (Nontunable)
% Public, non-tunable properties.
end
properties (Access = private)
% Pre-computed constants.
Temperature
Valid
end
methods
% Constructor
function obj = MotorDriver(varargin)
% Support name-value pair arguments when constructing the object.
setProperties(obj,nargin,varargin{:});
end
end
methods (Access=protected)
function setupImpl(obj) %#ok<MANU>
if coder.target("Rtw")
% Place simulation setup code here
coder.cinclude("motorDriver.h");
coder.ceval('setupFunction');
else
% Something
end
end
function [Temperature, Valid] = stepImpl(obj,u) %#ok<INUSD>
if coder.target("Rtw")
temp = int32(0);
valid = false;
coder.cinclude("motorDriver.h");
coder.ceval('stepFunction',uint8(128), coder.ref(temp), coder.ref(valid));
Temperature = temp;
Valid = valid;
else
Temperature = int32(98);
Valid = false;
end
end
function releaseImpl(obj) %#ok<MANU>
if isempty(coder.target)
% Place simulation termination code here
else
% Call C-function implementing device termination
%coder.ceval('sink_terminate');
end
end
end
methods (Access=protected)
%% Define input properties
function num = getNumInputsImpl(~)
num = 1;
end
function num = getNumOutputsImpl(~)
num = 2;
end
function varargout = getOutputNamesImpl(obj)
varargout{1} = 'Temperature';
varargout{2} = 'Valid';
end
function flag = isOutputSizeLockedImpl(~,~)
flag = true;
end
function varargout = isOutputFixedSizeImpl(~,~)
varargout{1} = true;
varargout{2} = true;
end
function varargout = isOutputComplexImpl(~)
varargout{1} = false;
varargout{2} = false;
end
function varargout = getOutputSizeImpl(~)
varargout{1} = [1,1];
varargout{2} = [1,1];
end
function varargout = getOutputDataTypeImpl(~)
varargout{1} = 'int32';
varargout{2} = 'boolean';
end
function icon = getIconImpl(~)
% Define a string as the icon for the System block in Simulink.
icon = 'Sink';
end
end
methods (Static, Access=protected)
function simMode = getSimulateUsingImpl(~)
simMode = 'Interpreted execution';
end
function isVisible = showSimulateUsingImpl
isVisible = false;
end
end
methods (Static)
function name = getDescriptiveName(~)
name = 'motorDriver';
end
function tf = isSupportedContext(~)
tf = true;
end
function updateBuildInfo(buildInfo, context)
buildInfo.addDefines('USE_HARDWARESERIAL');
if context.isCodeGenTarget("rtw")
% Update buildInfo
srcDir = fullfile(fileparts(mfilename("fullpath")), 'src');
includeDir = fullfile(fileparts(mfilename("fullpath")), 'include');
libDir = fullfile(fileparts(mfilename("fullpath")), 'libraries');
% Include header files
addIncludePaths(buildInfo, includeDir);
addIncludePaths(buildInfo, libDir);
addSourceFiles(buildInfo, 'motorDriver.cpp', srcDir);
addSourceFiles(buildInfo, 'RoboClaw.cpp', libDir);
boardInfo = arduino.supportpkg.getBoardInfo;
switch boardInfo.Architecture
case 'avr'
addIncludePaths(buildInfo, 'C:\ProgramData\MATLAB\SupportPackages\R2024b\aCLI\data\packages\arduino\hardware\avr\1.8.3\libraries\SoftwareSerial\src');
addSourceFiles(buildInfo, 'SoftwareSerial.cpp', 'C:\ProgramData\MATLAB\SupportPackages\R2024b\aCLI\data\packages\arduino\hardware\avr\1.8.3\libraries\SoftwareSerial\src');
% case 'sam'
% case 'samd'
otherwise
warning('Unexpected board type. Please check your board and try again');
end
end
end
end
end
At this point I am posting this here as a function of git and version control posting to this community is basically futile.

请先登录,再进行评论。

采纳的回答

Aditya Shah
Aditya Shah 2024-11-29
Hello Clayton,
I've noticed that you've included numerous "Serial.println" statements in your code. Note that Simulink interfaces with Arduino in external mode using a serial connection over USB.
Try removing all the serial print statements and see if that resolves the issue.
  1 个评论
Clayton Allen
Clayton Allen 2024-11-29
I did just that last nite right after my last input and it works! I have been smacking my head against this problem for a week. And it was all about the serial.println... Thanks for you answer and I hope that is helps some other person in the future.

请先登录,再进行评论。

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Arduino Hardware 的更多信息

产品


版本

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by