I am trying to make a S-Function (written in C and using SDL library) in Simulink to read joystick values from the device and output them to Simulink. I used before the standard aerospace library joystick block, however, this does not support compiling (which is needed for Rapid Acceleration). Hence, I decided to write my own S-Function.
I managed to make a simple C program that uses SDL (I downloaded https://www.libsdl.org/download-2.0.php) to read values of joystick and print to terminal:
#include <stdio.h>
#include <unistd.h>
#include "SDL2/SDL.h"
static SDL_Joystick *joy = NULL;
int
main(int argc, char *argv[])
{
// ITIALIZE:
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
// Check for joystick
if (SDL_NumJoysticks() > 0) {
// Open joystick
joy = SDL_JoystickOpen(0);
if (joy) {
printf("Opened Joystick 0\n");
printf("Name: %s\n", SDL_JoystickNameForIndex(0));
printf("Number of Axes: %d\n", SDL_JoystickNumAxes(joy));
printf("Number of Buttons: %d\n", SDL_JoystickNumButtons(joy));
printf("Number of Balls: %d\n", SDL_JoystickNumBalls(joy));
} else {
printf("Could not open Joystick 0\n");
return 0;
}
}
SDL_JoystickEventState(SDL_IGNORE);
// READ VALUES:
for (int i = 1; i < 100; ++i){
SDL_JoystickUpdate();
for (int j = 0; j < SDL_JoystickNumAxes(joy); ++j) {
int value = (((int) SDL_JoystickGetAxis(joy, j)) + 32768);
printf("Axes %d: %d ", j, value);
}
printf("\n");
usleep(100000);
}
// CLOSE:
if (SDL_JoystickGetAttached(joy)) {
SDL_JoystickClose(joy);
}
return 1;
}
I compile the C code in Code::Blocks with linkers:
-lmingw32 -lSDL2main -lSDL2
The compiled .exe requires runtime binary SDL.dll, which is simply located in the same folder as the compilation, and everything works.
The problem is, how to transfer the above to work in Simulink environment? I have transferred the code into Simulink S-Function builder:
/* Includes_BEGIN */
#include "SDL2/SDL.h"
#include <stdio.h>
/* Includes_END */
/* Externs_BEGIN */
static SDL_Joystick *joy = NULL;
/* Externs_END */
void sunf_joystick_Start_wrapper(void)
{
/* Start_BEGIN */
// ITIALIZE:
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
// Check for joystick
if (SDL_NumJoysticks() > 0) {
// Open joystick
joy = SDL_JoystickOpen(0);
if (joy) {
ssPrintf("Opened Joystick 0\n");
ssPrintf("Name: %s\n", SDL_JoystickNameForIndex(0));
ssPrintf("Number of Axes: %d\n", SDL_JoystickNumAxes(joy));
ssPrintf("Number of Buttons: %d\n", SDL_JoystickNumButtons(joy));
ssPrintf("Number of Balls: %d\n", SDL_JoystickNumBalls(joy));
} else {
ssWarning("Warning:Joystick","Could not open Joystick 0\n");
}
}
SDL_JoystickEventState(SDL_IGNORE);
/* Start_END */
}
void sunf_joystick_Outputs_wrapper(real_T *y0)
{
/* Output_BEGIN */
SDL_JoystickUpdate();
for (int j = 0; j < SDL_JoystickNumAxes(joy); ++j) {
y0[j] = (((int) SDL_JoystickGetAxis(joy, j)) + 32768);
}
/* Output_END */
}
void sunf_joystick_Terminate_wrapper(void)
{
/* Terminate_BEGIN */
if (SDL_JoystickGetAttached(joy)) {
SDL_JoystickClose(joy);
}
/* Terminate_END */
}
and added the LIB_PATH and INCL_PATH to point for the SDL library:
S-function builder Libraries tab
However, I get a lot of similar error messages when trying to build through the GUI:
C:\Users\user\AppData\Local\Temp\mex_121831936796334_22096\sunf_joystick_wrapper.obj:sunf_joystick_wrapper.c:(.text+0xe): undefined reference to `SDL_InitSubSystem'
To me it seems that the libraries are not linked correctly. An idea how to fix this? I have tried to build it also with mex through MATLAB command line, not successful, and feels also wrong way to do it.
Also, any advice where the the runtime library SDL.dll should be stored or referenced if the compilation is successful?
All files in: https://github.com/JohannesSoikkeli/Simulink_joystick
Many thanks!
Related
I have STM32F4 Discovery. I use IAR embedded Workbench. I am new to this kit. I want to measure distance. my code does not give an error. the distance is always zero. What could be the error? please help me . thanks everyone
#include "stm32f4_discovery.h"
#include "delay.h"
uint32_t Read_Distance(void);
void Init();
uint32_t distance ;
int main()
{
Init(); // initialisation de pin
SysTick_Init(); // pour pouvoire utiliser la fonction delay :)
while (1)
{
distance=Read_Distance();
delay_nms(100);
}
}
void Init()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitTypeDef gpioStructure;
gpioStructure.GPIO_Pin = GPIO_Pin_10;
gpioStructure.GPIO_Mode = GPIO_Mode_OUT;
gpioStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &gpioStructure);
gpioStructure.GPIO_Pin = GPIO_Pin_11;
gpioStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(GPIOD, &gpioStructure);
}
//Les Pins pour le Test sont PD10 (Trig) et PD11(echo)
uint32_t Read_Distance(void)
{
__IO uint8_t flag=0;
__IO uint32_t disTime=0;
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(10);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
while(flag == 0)
{
while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == SET)
{
disTime++;
flag = 1;
}
}
return disTime;
}
Looks like you're using one of those ultrasonic distance measurement modules
Try this:
while(flag == 0)
{
disTime++;
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == SET)
{
flag = 1;
}
}
You should use one of the hardware timers to get a more accurate time measurement.
Now I've had time to think more about it I remember now that you get a pulse sent back with a width proportional to the distance. I think this is the correct answer:
// Wait for pulse to start
while (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == RESET)
{
NOP;
}
// Measure pulse width
while(flag == 0)
{
disTime++;
// Has pulse ended
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == RESET)
{
flag = 1;
}
}
You may also want to tackle the case where the pulse is never received because this could will block forever.
If I understand correctly, D10 is wired to D11 and you want to check how long your signal remains high. If this is the case, you should increment a counter in timer interrupt handler when your pin is high and reset that counter variable once you've read it.
I have an Arduino with a Seeedstudio sd card shield v4.0 with a prototpye shield above that, and on that is a TMP36 temperature sensor and a red and two green LEDs, the red to show that it is "Ready" to log data, the first green to show that it is currently "logging data" and the last LED to show that the data was "Saved" to the SD card, which it dosent, at the beggining of the file, however, it creates the line "Testing 1, 2, 3..." in a txt file called TEST. in that same file there should be the data, but there is no data, it will write to the card in setup, but not in loop. Can anyone help me?
Code:
#include <toneAC.h>
#include <SPI.h>
#include <SD.h>
int readyLED = 2;
int startLED = 8;
int buzzer = 7;
int tempSensor = A0;
int readyButton = 5;
int sampleNo = 0;
int button_mode = 1;
int saveLED = 4;
File myFile;
void setup() {
// put your setup code here, to run once:
pinMode(readyLED, OUTPUT);
digitalWrite(readyLED, HIGH);
pinMode(saveLED, OUTPUT);
digitalWrite(saveLED, LOW);
pinMode(startLED, OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(10, OUTPUT);
pinMode(tempSensor, INPUT);
pinMode(readyButton, INPUT);
digitalWrite(readyLED, HIGH);
digitalWrite(startLED, LOW);
Serial.begin(9600);
while (!Serial){}
Serial.println("Initializing SD card...");
if(!SD.begin(4)){
Serial.println("Failed!");
return;
}
Serial.println("Success!");
myFile = SD.open("test.txt", FILE_WRITE);
if (myFile) {
Serial.println("Writing to test.txt...");
myFile.println("testing 1, 2, 3.");
delay(500);
myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(readyLED, HIGH);
digitalWrite(startLED, LOW);
delay(700);
digitalWrite(startLED, HIGH);
delay(650);
int reading = analogRead(tempSensor);
float voltage = reading * 5.0;
voltage /= 1024.0;
float temperatureC = (voltage - 0.5) * 100;
float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
Serial.print("Sample No. ");
sampleNo = sampleNo + 1;
Serial.print(sampleNo);
Serial.print(" Temperature: ");
Serial.print(temperatureF);
Serial.println(" F");
myFile = SD.open("test.txt", FILE_WRITE);
if(myFile){
Serial.println("Test.txt");
}
while(myFile.available()){
myFile.print("Sample No. ");
myFile.print(sampleNo);
myFile.print(" Temperature: ");
myFile.print(temperatureF);
myFile.println(" F");
}
delay(30);
digitalWrite(saveLED, HIGH);
delay(10);
digitalWrite(saveLED, LOW);
delay(10);
myFile.close();
}
You may want to check to make sure your while loop is actually being run. Since you know you can write to the SD card from void setup() you know your code inside the while loop works, but is the while loop actually being run, or is it evaluating to false and being skipped?
Have you considered the time it takes to write down data as an issue? You may be asking for it write down data before the Arduino code has time to process.
i,v downloaded SDL2 library on windows7 64bit i,m using MinGW compiler and my IDE is : eclipse Mars
so the problem is when i build my SDL program i face this problem :
C:\Users\{C}\Desktop\eclipse\MinGW\lib/libSDL2main.a(SDL_windows_main.o):SDL_windows_main.c:(.text+0x18): undefined reference toSDL_main'`
i did every thing correctly but i keep facing this issue and that,s the whole CDT build :
13:19:24 Incremental Build of configuration Debug for project
boring **** Info: Internal Builder is used for build g++
"-LC:\\Users\\{C}\\Desktop\\eclipse\\MinGW\\lib" -o boring.exe
"src\\boring.o" -lmingw32 -lSDL2main -lSDL2
C:\Users\{C}\Desktop\eclipse\MinGW\lib/libSDL2main.a(SDL_windows_main.o):SDL_windows_main.c:(.text+0x18):
undefined reference to `SDL_main' collect2.exe: error: ld returned 1
exit status 13:19:27 Build Finished (took 3s.337ms)
and here,s my source code:
#include <iostream>
#include <SDL2/SDL.h>
using namespace std;
int main() {
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
cout << "SDL init failed." << endl;
return 1;
}
SDL_Window *window = SDL_CreateWindow("Particle Fire Explosion",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH SCREEN_HEIGHT, SDL_WINDOW_SHOWN);,
if (window == NULL) {
SDL_Quit();
return 2;
}
bool quit = false;
SDL_Event event;
while (!quit) {
// Update particles
// Draw particles
// Check for messages/events
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
thanks;
SDL requires that you define your main exactly as main(int argc, char *argv[]). Please check if this resolves your problem.
i have written a simple s-function which calls a function inside a c code which models the single track model. i am using constant variables for storing mass,yaw moment of inertia,steering ratio etc. I wanted to know how to make these variables tunable. i want to create a subsystem out of my s-function and then use realtime workshop->generate s-function and select the tunable parameters from the list. but for now am not able to find any tunable parameters since i have not specified anything as tunable
this is my s-function code
#define S_FUNCTION_NAME single_track
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
#include "single_track_func.c"
#define MDL_START /* Change to #undef to remove function */
#if defined(MDL_START)
static void mdlStart(SimStruct *S)
{
initialization();
}
#endif
static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0);
if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
return; /* Parameter mismatch will be reported by Simulink */
}
if (!ssSetNumInputPorts(S, 2)) return;
ssSetInputPortWidth(S, 0, 1);
ssSetInputPortDirectFeedThrough(S, 0, 1);
ssSetInputPortWidth(S, 1, 1);
ssSetInputPortDirectFeedThrough(S, 1, 1);
if (!ssSetNumOutputPorts(S,3)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetOutputPortWidth(S, 1, 1);
ssSetOutputPortWidth(S, 2, 1);
ssSetNumSampleTimes(S, 1);
ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
ssSetOptions(S,
SS_OPTION_WORKS_WITH_CODE_REUSE |
SS_OPTION_EXCEPTION_FREE_CODE |
SS_OPTION_USE_TLC_WITH_ACCELERATOR);
}
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
ssSetModelReferenceSampleTimeDefaultInheritance(S);
}
static void mdlOutputs(SimStruct *S, int_T tid)
{
retvale obj_b;
InputRealPtrsType v_1 = ssGetInputPortRealSignalPtrs(S,0); //velocity
InputRealPtrsType delta_1 = ssGetInputPortRealSignalPtrs(S,1); //steering angle
real_T *a_y_1 = ssGetOutputPortRealSignal(S,0); //lateral acceleration
real_T *psi_dot_1 = ssGetOutputPortRealSignal(S,1); //yaw velocity
real_T *beta_1 = ssGetOutputPortRealSignal(S,2); //attitude angle
obj_b=singletrack((double)*(*v_1),(double)*(*delta_1));
*a_y_1 = obj_b.a_y; //lateral acceleration
*psi_dot_1 =obj_b.psi_dot; //yaw velocity
*beta_1 =obj_b.beta;
}
static void mdlTerminate(SimStruct *S)
{
}
#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
and this is the logic file which has the function singletrack()
#include "single_track_func.h"
float a_1_1,a_1_2,a_2_1,a_2_2,b_1_1,b_2_1,psi_dot_prev,beta_prev;
int count;
const int cv=75000; //cornering stiffness front
const int ch=150000; //cornering stiffness rear axle
const int m=1550; //mass of the vehicle kg
const int lv=1.344; //distance from center of gravity to front wheel
const int lh=1.456; //distance from center of gravity to rear wheel
const int theta=2800; //yaw moment of inertia
const int I_s=16; //overall steering ratio
const float dt=0.001;
retvale singletrack(double a,double b)
{
retvale my_obj;
static float beta_dot=0;
static float psi_double_dot=0;
static float beta_previous=0;
static float psi_dot_previous=0;
beta_previous = beta_prev;
psi_dot_previous = psi_dot_prev;
a_1_1 = ((-cv-ch)/((m)*(a)));
a_1_2 = ((m*(a)*(a))-((ch*lh)-(cv*lv)))/(m*(a)*(a));
a_2_1 = (-(ch*lh)+(cv*lv))/theta;
a_2_2 = ((-ch*lh*lh)-(cv*lv*lv))/(theta*(a));
b_1_1 = -cv/(m*(a));
b_2_1 = (cv*lv)/(theta);
beta_dot = a_1_1 * beta_previous + a_1_2 * psi_dot_previous - b_1_1*((b)/I_s);
psi_double_dot = a_2_1 * beta_previous + a_2_2 * psi_dot_previous + b_2_1*((b)/I_s);
my_obj.beta = beta_dot * dt + beta_previous;
my_obj.psi_dot = psi_double_dot * dt + psi_dot_previous;
my_obj.a_y = (a*((my_obj.psi_dot)-(beta_dot)));
beta_prev=my_obj.beta;
psi_dot_prev=my_obj.psi_dot;
return my_obj;
}
void initialization()
{
psi_dot_prev=0;
beta_prev=0;
}
and the corresponding .h file
#ifndef _SINGLE_TRACK_FUNC_
#define _SINGLE_TRACK_FUNC_
typedef struct retvale
{
double a_y;
double psi_dot;
double beta;
} retvale;
extern struct retvale singletrack(double a,double b);
extern void initialization();
#endif
I know i have to use ssSetSFcnParamTunable() but even after looking at examples have no idea how to do it!!
update:
i declared the variables as global real_T
real_T *m_s,*cv_s,*ch_s,*lv_s,*lh_s,*theta_s,*I_s_s,*dt_s;
and added these lines of codes in my mdlInitializeSizes(). i mex it and everything is fine. but when i use the s-function block and just change the name of the s-function to the mex file the matlab crashes. also i pass these arguments as pointers to my single_track () function
ssSetNumSFcnParams(S, 8);
m_s=mxGetPr(ssGetSFcnParam(S,0));
cv_s=mxGetPr(ssGetSFcnParam(S,1));
ch_s=mxGetPr(ssGetSFcnParam(S,2));
lv_s=mxGetPr(ssGetSFcnParam(S,3));
lh_s=mxGetPr(ssGetSFcnParam(S,4));
theta_s=mxGetPr(ssGetSFcnParam(S,5));
I_s_s=mxGetPr(ssGetSFcnParam(S,6));
dt_s=mxGetPr(ssGetSFcnParam(S,7));
ssSetSFcnParamTunable(S,0,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,1,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,2,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,3,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,4,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,5,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,6,SS_PRM_SIM_ONLY_TUNABLE);
ssSetSFcnParamTunable(S,7,SS_PRM_SIM_ONLY_TUNABLE);
any idea why there is a crash?
For a parameter to be tunable it must be passed as an input from Simulink to your S-Function.
This is done by specifying them in the Parameters part of the S-Function block's dialog (as a comma separated list), and using the ssSetNumSFcnParams method within the S-Function itself to tell the S-function how many parameters to expect (you currently have that set to 0).
Also, within the S-Function you'll need to
Use the ssGetSFcnParam method to get the data (from the dialog into the code).
Use the ssSetSFcnParamTunable method to say that the parameter(s) is tunable.
Then you'll need to rewrite your singletrack function so that all of the parameters are passed into it as inputs rather than being hard coded into the file.
However, looking at the code you've given, it would be far easier to do this all as a MATLAB Function than it would as an S-Function.
I'm trying to use feature detection via OpenCV on iOS and I'm running into a conundrum:
features2d relies on highgui
highgui can't be built on iOS (or at least not that I can figure out).
This leads me to believe: features2d just can't be used on iOS without rewriting the module to remove the calls to cvSaveImage() and cvLoadImage(). Is this wrong? Anyone run into this and solved it?
You are taking the wrong aproach, you dont need highgui since that library is only ment to make it easier for you to handle the results of your processing, you can simply do those steps manually.
for example, consider this HOG example:
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
int
main(int argc, char *argv[])
{
const char *imagename = argc > 1 ? argv[1] : "../../image/pedestrian.png";
cv::Mat img = cv::imread(imagename, 1);
if(img.empty()) return -1;
cv::HOGDescriptor hog;
hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());
std::vector<cv::Rect> found;
// 画像,検出結果,閾値(SVMのhyper-planeとの距離),
// 探索窓の移動距離(Block移動距離の倍数),
// 画像外にはみ出た対象を探すためのpadding,
// 探索窓のスケール変化係数,グルーピング係数
hog.detectMultiScale(img, found, 0.2, cv::Size(8,8), cv::Size(16,16), 1.05, 2);
std::vector<cv::Rect>::const_iterator it = found.begin();
std::cout << "found:" << found.size() << std::endl;
for(; it!=found.end(); ++it) {
cv::Rect r = *it;
// 描画に際して,検出矩形を若干小さくする
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height*0.07);
r.height = cvRound(r.height*0.8);
cv::rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
}
// 結果の描画
cv::namedWindow("result", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
cv::imshow( "result", img );
cv::waitKey(0);
}
it is made for a non iOS enviroment, however you can simply replace all highgui calls for
native iOS stuff.
You can get a very good image handling for opencv library from here:
http://aptogo.co.uk/2011/09/opencv-framework-for-ios/
so what you should really care about in that code is just this part:
cv::HOGDescriptor hog;
hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());
std::vector<cv::Rect> found;
// 画像,検出結果,閾値(SVMのhyper-planeとの距離),
// 探索窓の移動距離(Block移動距離の倍数),
// 画像外にはみ出た対象を探すためのpadding,
// 探索窓のスケール変化係数,グルーピング係数
hog.detectMultiScale(img, found, 0.2, cv::Size(8,8), cv::Size(16,16), 1.05, 2);
std::vector<cv::Rect>::const_iterator it = found.begin();
std::cout << "found:" << found.size() << std::endl;
for(; it!=found.end(); ++it) {
cv::Rect r = *it;
// 描画に際して,検出矩形を若干小さくする
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height*0.07);
r.height = cvRound(r.height*0.8);
cv::rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
}
For a BRIEF:
// You get your img into a cv mat from the uiimage or whatever.
cv::Mat gray_img;
cv::cvtColor(img, gray_img, CV_BGR2GRAY);
cv::normalize(gray_img, gray_img, 0, 255, cv::NORM_MINMAX);
std::vector<cv::KeyPoint> keypoints;
std::vector<cv::KeyPoint>::iterator itk;
cv::Mat descriptors;
//
// threshold=0.05, edgeThreshold=10.0
cv::SiftFeatureDetector detector(0.05,10.0);
detector.detect(gray_img, keypoints);
// Brief に基づくディスクリプタ抽出器
cv::BriefDescriptorExtractor extractor;
cv::Scalar color(50,50,155);
extractor.compute(gray_img, keypoints, descriptors);
// 32次元の特徴量 x keypoint数
for(int i=0; i<descriptors.rows; ++i) {
cv::Mat d(descriptors, cv::Rect(0,i,descriptors.cols,1));
std::cout << i << ": " << d << std::endl;
}
And you have your result.