Jose's Blog

25.09.2021

Automatic Construction of Links

Filed under: Robotics — admin @ 19:28

Sometimes I need to study linkages given the DH-parameters. It is difficult to always model different 3D linkages every time I have new set of DH-parameters. For this reason I thought of creating a script that models them for me. I have done this before for creating STL models of arbitrary DH-parameters and to create Amrose-Format workcells (which was also scripted). Though, the python script I used to create these STL models are far from reality (you cannot really 3D-Print these models and expect to have a miniature mechanism) and were only used for visualization. What I have now are scripts that create workable models that can be 3D-printed and connected.

At the moment I only have scripts for linkages with revolute joints. Originally I created a script for FreeCAD because I knew that this parametric software has quite an extensive python API (almost anything you could do model in the CAD system you could write in a script!). You can download the scripts (for both FreeCAD and Rhino) here.

I will only explain how you can do this in Windows. Linux users can do the same in FreeCAD if they know where the user program data is located.

Here is how you can use this script in FreeCAD:
Copy the python file (from Freecad folder) to %APPDATA%\FreeCAD\Macro. An example (pretty much the documentation) how to use it is given by the following sample script

import dh_links

al = [50,145,60,30,80,140]
a = [1,0.7488,0.1166,0.4,0.7878,0.3926]
a = [i*100 for i in a]
d = [0,0.3,0.7348,0,1.1705,1.3127]
d = [i*100 for i in d]

for i in xrange(len(a)):
  App.newDocument("link")
  App.setActiveDocument("link")
  dh_links.ADoc = App.ActiveDocument
  dh_links.aDoc = App.activeDocument()

  print(i)
  dh_links.make_link(al[i],a[i],d[i])
  dh_links.ADoc.saveAs("C:/temp/link"+str(i+1)+".FCStd")
  App.closeDocument("link")

FreeCAD is based on Open Cascade which is known to have weaknesses when it comes to fillets such as chamfer and rounding. It is far from a complete parametric software, but it is at least free and has a very good scripting API (better than some commercial ones). But because of these weaknesses I decided to create a similar script for a commercial CAD software. I thought of Creo or Inventor, however I really wanted to opt for a CAD software that has a good python API. Since I am not really taking advantage of the parametric capabilities I opted for a non-parametric CAD software with a good python API (the only commercial one that I know). I therefore created a similar script for Rhino. Here is how you can use the script in Rhino:

Copy the python file (from Rhino folder) to anywhere where you want to use the script. In the same location where you have this python file, create another python file to use the script. A sample script (equivalent to the example using FreeCAD) is

from dh_links import *

al = [50,145,60,30,80,140]
a = [1,0.7488,0.1166,0.4,0.7878,0.3926]
a = [i*100 for i in a]
d = [0,0.3,0.7348,0,1.1705,1.3127]
d = [i*100 for i in d]

rs.EnableRedraw(False)

for i in xrange(len(a)):
  print(i)
  make_link(al[i],a[i],d[i])
  rs.Command('-_SaveAs "c:\\temp\\link'+str(i+1)+'.stp" _Enter _Enter')
  ids = rs.AllObjects()
  rs.DeleteObjects(ids)

rs.EnableRedraw(True)

I realize some shortcomings though (besides the fact that Rhino is not parametric). I wasn’t really able to really justify this as much as I wanted. Chamfer and Rounding will require good access to edge IDs of the object and the python API is not as complete as I wanted it to be.

Finally, here are some screenshots of some of the links created

You can then create your own pin to connect links as revolutionary joints (by the design I made, one pin design is sufficient). You can also then combine these links in any CAD software and play around with the linkage there. It is also perfectly all right to just 3D print them and play with them. I’m sure there are bugs and maybe the design may not be robust so feel free to improve on it. Here is a screenshot when I assembled everything (without any screws or pins but with virtual constraints) and played with the linkage in Creo.

14.01.2021

Setting up Maple for startup code and for saving all data of the worksheet.

Filed under: Computer Math,Programming — Tags: — admin @ 15:53

This is about setting up maple so that:

  1. You can load your libraries from a customized location.
  2. You don’t have to execute the whole worksheet to get an old computed result.

I only know this for Windows, for linux this should be the same but probably easier. I had some problems in Maple for Windows because it changed the way it processes the .ini file without correctly documenting it. They kept an old documentation of the .ini file but the location of the .ini file should be corrected:

https://www.maplesoft.com/support/help/Maple/view.aspx?path=libname
https://www.maplesoft.com/support/help/Maple/view.aspx?path=worksheet/reference/initialization

In the past, in Windows, .ini was saved in %APPDATA%/Maple/<version>/maple.ini . This file still exist for newer maple version but it is not the same initialization file of the past (where you can write a startup code). The newer versions of Maple (I believe > version 16) uses this .ini file for the UI and not for startup code. However (undocumented) Maple will read another .ini file for startup, which unfortunately is also called maple.ini but located somewhere else. The startup code maple.ini file is now located in %USERPROFILE% (e.g. C:\Users\Jose). If this directory has no maple.ini, I suggest to create one.

Now if you want to have a startup code that:

  1. uses a customized location (for the sake of simplicity we want them to be in C:\my_libs) for libraries, put this in the init file:
    libname:="C:\\my_libs",libname:
    savelibname:="C:\\my_libs":
    
  2.  provides a procedure that saves all user variables from a worksheet (this is useful if you have something that computes for ages and whenever you open maple again you want to have the results). Put this in the maple.ini file:
    SaveAll := proc( fileName :: string )
    subs(_NAMES = anames(':-user'), proc() save _NAMES, fileName end proc)()
    end proc:
    

So now whenever I do some heavy computation in a worksheet before closing the worksheet I always type something like

SaveAll("C:/temp/maple.m");

And now when I open the worksheet again and I don’t want to re-execute the computation but still have the same variables I type
read("C:/temp/maple.m");

04.01.2021

xournal for win32

Filed under: Uncategorized — admin @ 09:38

Since the COVID pandemic I started to get more interested in Xournal. In fact, I was already interested in these kind of softwares but never really had the time to take them seriously. Now I actually need it for work. Most of my work are done via Zoom calls and Xournal doodles via screen sharing. There are many things to be wished in the xournal software and this is delivered in the all new Xournal++ software (for instance LaTeX annotation, drawing circles , splines and arrows turned out to be extremely useful esp. when annotating pdf of students). I looked a bit at the code of Xournal++ and I felt it would be a huge task if I want to try to understand it. It felt also more unstable than the original xournal (which is written in C rather than C++). So I thought I looked at the xournal code and just add the little things I am interested in  and maybe fix some bugs (I still use xournalpp for many things!). It will also help me improve my ability to port some originally developed Linux software into Windows.

My experience lies mostly in win32 development and so it was natural for me to look at xournal from this angle. xournal depends on libpoppler and libpoppler-glib. Both are notorious to be difficult to compile in windows. There is this MSys2 distribution that provided precompiled versions of libpoppler and libpoppler-glib, but I soon found out that the dependencies were quite heavy and I didn’t really needed the very latest version of libpoppler. I could have gotten away by finding another source of precompiled libpoppler library for windows (sourceforge has several of these) but all of them do not have libpoppler with glib wrapper and so I finally decided to do the dirty work myself and compile them myself. This is one of the hardest thing for me to compile that was originally developed in linux (I would put libflint as the hardest one!). libpoppler comes with cmake scripts, but they were so difficult to understand and the resulting makefile were also difficult to read. I also really wanted to compile this library in the most optimized way in windows (i.e. tweak the makefiles when possible). So I ended up doing the following:

  • Install GTK bundle for win32 (I got gtk+2.24.10)
  • Download libpoppler source (for me version 0.12.4 worked)
  • Write my own makefile for libpoppler-glib (I would not need libpoppler.dll in the end)
  • Download the dependencies: libgnomecanvas (I got the dev and bin for version 2.13), libart
  • Download precompiled libcairo for win32 (I go the src and bin of version 1.17.2)
  • Write my own makefile for xournal and finally built the whole thing with gcc and codeblocks.

You may need to edit directories in the makefiles and the package-config .pc files. My makefiles are usually located in a cbp directory created in the root directory of the source. My experience tells me: building a gtk project in windows is a nightmare if it is your first time (esp. if it is libpoppler-glib dependent).

Here is the xournal binary that I built that should be a little faster than the original distribution and has a little less dependencies.

I also make available libpoppler-glib (built together with libpoppler) precompiled win32 build.

02.05.2020

multiscr for Windows 10

Filed under: Uncategorized — admin @ 17:18

The old XScreenSaver codes for windows soon became obsolete in Windows 10. However the original developer (Katayama Hirofumi) made some adjustments so that it will also work in Windows 10 and provided his port in github. There is a downside in windows 10 though:

  • As in the old windows, there is no multi-screensaver
  • It seems that there are limited number (say n) of .scr files that will be installed in the systems directory (even if you put greater than n number of .scr files, the system will only look at the first n file ordered by name).

To deal with this issue for windows 10, I modified multiscr so that it would work. Now multiscr will use a user-preferred directory to switch through the different .scr.

I provide the binary of this code in a zip file here.

To install decompress and (make sure you have write access to windows directories):

  • put multiscr.scr and multiscr.ini in %windir%/system32 (usually C:\Windows\System32)
  • edit multiscr.ini so that the second line (which in the zip is C:\my_scr\) shows the location (it should end with a “\”) where .scr files you want multiscr to use.

If you want to know more about multiscr you may also want to read my original post about it!

01.11.2017

Compiling Giac in Windows (VS2008)

Filed under: Uncategorized — admin @ 22:09

Finally, the day has come when I can proudly write that I have successfully compiled a computer algebra system in windows using visual studio and I actually was able to compile it as a dynamic library and link it with another C++ program that uses it. Maybe in other operating system with gcc compiler this is a trivial task, in windows with msvc this is for me far from trivial.

Here is a walkthrough. It would help if you understood the steps in compiling giac with gcc (either with mingwc or in a cygwin environment) in windows. You can look at my previous blog post to get an idea. If you just want to compile and not think of the technicalities (steps below), you may download a project archive here.

First I explain how to compile the project (not link)

  1. Make sure you make a project with the following c++ source files:
    alg_ext.cc
    cocoa.cc
    csturm.cc
    derive.cc
    desolve.cc
    ezgcd.cc
    first.cc
    gauss.cc
    gausspol.cc
    gen.cc
    global.cc
    help.cc
    identificateur.cc
    ifactor.cc
    index.cc
    input_lexer.cc (and input_lexer.ll)
    input_parser.cc
    intg.cc
    intgab.cc
    isom.cc
    lin.cc
    maple.cc
    mathml.cc
    misc.cc
    modfactor.cc
    modpoly.cc
    moyal.cc
    pari.cc
    permu.cc
    plot.cc
    plot3d.cc
    prog.cc
    quater.cc
    risch.cc
    rpn.cc
    series.cc
    solve.cc
    sparse.cc
    subst.cc
    sym2poly.cc
    symbolic.cc
    tex.cc
    threaded.cc
    ti89.cc
    tinymt32.cc
    unary.cc
    usual.cc
    vecteur.cc
    
  2. For the sake of completeness I provided a sample project file with the corresponding source codes. global.cc had to be patched because we use MPIR.

  3. Visual studio may not have stdint.h and some code may use it. I have included a stdint.h in the project archive that I am going to share. Otherwise, it is easy to add the necessary typedef from stdint.h. You can create your own stdint.h by creating the following file:

    typedef __int8 int8_t;
    typedef unsigned __int8 uint8_t;
    typedef __int32 int32_t;
    typedef unsigned __int32 uint32_t;
    typedef __int64 int64_t;
    typedef unsigned __int64 uint64_t;
    

    I also patched global.cc (also in the project archive I am sharing) because mpir already defines R_OK (which is defined in global.cc). See the next item for explanation. The patch just changes line ca. 172 that defines R_OK for the first time. To avoid conflict with mpir I changed this definition to

    #ifndef HAVE_LIBMPIR 
      int R_OK=4;
    #endif
    
  4. Make sure you have the following preprocessor definition set in the Project Properties->Configuration Properties->Preprocessor
    WIN32
    WINDOWS
    HAVE_CONFIG_H
    IN_GIAC
    GIAC_VECTOR
    _USE_MATH_DEFINES
    VISUALC (not __VISUALC__)
    _CRT_SECURE_NO_WARNINGS
    _SCL_SECURE_NO_WARNINGS
    _CRT_NON_CONFORMING_SWPRINTFS
    STATIC_BUILTIN_LEXER_FUNCTIONS
    NO_CLOCK (clock() is not standardly defined in msvc)
    HAVE_NO_CWD (getcwd is not standardly defined in msvc)
    MS_SMART (otherwise in gen.cc #include "../../../_windows/src/stdafx.h" would cause error, stdafx.h does not reside in this relative directory by default, without this we also get error in ifactor.cc when calling PREFETCH)
    NO_UNARY_FUNCTION_COMPOSE
    MS_SMART
    HAVE_LIBMPIR (needed for a patch in global.cc when using mpir, R_OK is already defined. See attached files)
    
  5. Make sure in config.h of the original giac source code, the following are NOT defined:
    HAVE_GETCWD (getcwd  is not standardly defined in msvc)
    HAVE_SYS_TIME_H
    HAVE_LIBPTHREAD (otherwise you get a lot of VLA errors in vecteur.cc)
    HAVE_PTHREAD_H (otherwise you get a lot of VLA errors in vecteur.cc)
    HAVE_READLINE_HISTORY_H (they are not standardly available in msvc)
    HAVE_READLINE_READLINE_H (they are not standardly available in msvc)
    

    Also uncomment

     #define HAVE_NO_CWD 1 //(getcwd  is not standardly defined in msvc) 
  6. In line ca. 1634 of vecteur.cc where the method rand_1 is defined, the code uses rand() which is ambiguous in VS2008 (error C2660). I took the liberty and changed rand() to std::rand() (I hope this is what the author of the code wanted).
  7. In line ca. 35 of rpn.cc, after #ifndef NSPIRE there is #include which is nonexistent in MSVC. Workaround:
    changed #ifndef NSPIRE to #if !defined(NSPIRE) && !defined(__VISUALC__)
  8. In the original static_lexer.h, for some reasons the unicode literals are not understood as variables (probably an msvc setting that I have not figured out how to set). At the moment the fast and dirty (since I don’t think I am going to use these specific giac commands) solution I could think of is to enclose the line with at_LINEAR? and the last two lines of the code of static_lexer.h (where unorthodox characters are used as “at” variables) between #ifndef __VISUALC__ and #endif. This patch of static_lexer.h is also in the archive I am sharing.
  9. In some compilers input_lexer.ll and input_lexer.cc will cause some problems when only std::log(10) is used (compiler cannot detect what type of overload of log this is). Therefore I replace std::log(10) with std::log(10.0)

After doing all these, you should not get any serious compile errors (maybe you get some that I have overlooked, but I am sure they are easy to resolve). The next hurdle is to link. I made a fix but I am not sure if this is the best fix. There are global unary functions that are supposed to be defined somewhere and called by static_extern.h. The linker initially complained about unresolved external symbols: at_ugamma, at_regroup, at_is_inside, at_igamma, at_IP and at_FP. Maybe Bernard can help me on this, but the only way I could find to link was just to enclose these external global initialization (which should be defined somewhere, but where?) within #ifndef __VISUALC__ and #endif. This I did in both static_lexer.h and static_extern.h

After doing this, I was able to finally link and compile. One thing that is not mentioning is that I used CMake to export dll as it is often required in Visual Studio to apply __declspec(dllexport) to the methods we want to export when compiling the dynamic library and apply __declspec(dllimport) when importing from the library. The new CMake (not so new anymore) allows you to do this (with additional parameters in Pre-Link Build Events of Visual Studio). I will not go into detail about this, this can be read here .
This allowed me to both created a giac dll and a lib. The end result is around 8.7Mb for both the dll and the lib, but since the dll is only shared I find this a significant improvement to the size you get from compiling with mingw32.

Finally, to test that it works. I linked giac to another project having only one source (make sure you add the include directories of giac, mpir and mpfir in C/C++ -> Additonal Include Directories of the project property):

#include <giac/config.h>
#include <giac/giac.h>

using namespace std;
using namespace giac;

gen pgcd(gen a,gen b){
  gen q,r;
  for (;b!=0;){
    r=irem(a,b,q);
    a=b;
    b=r;
  }
  return a;
}

int main(){
  cout << "Enter 2 integers ";
  gen a,b;
  cout << "Trying a giac self-implementation of gcd:\n";
  cin >> a >> b;
  cout << pgcd(a,b) << endl;
  return 0;
}

I was able to compile, link and execute this program and get the result similar to the one I got in my last blog (compiling in mingw32).

As promised here is a 7zip file containing the project and the giac source I compiled with (and the setup needed in VS2008). Note: I only set Release configuration and you still need to link/compile with mpir (you can get the source here) and set it up in the project for this to work.

Older Posts »

Powered by WordPress