Search

2015年12月18日 星期五

Electronic Stethoscope DIY

    先到這下載膜面模型:https://github.com/GliaX/Stethoscope,印出來head.stl後先將尾管套上熱縮套然後加熱收縮,另一端套上電容式麥克風加熱,接著再找一層塑膠薄膜套上膜面束緊(我是用實驗用橡膠手套)。




    實驗後敏感度還不錯,不過我下圖Bandpass只有到1~105Hz所以示波器訊號看起來頻率不高但是可以看出心跳,我試著換成人體心肺音1~3100Hz也可以收到第一二心肺音。






MQ Gas Sensors Breakout Board

    MQ系列轉板,搭配一顆SMD 104P電容和10k VR,下面第一張圖是MQ-2,第二張圖是MQ-3,把MQ系列接反或者電壓接反都能Work只影響偵測到目標氣體時電壓曲線上升或下降,板子Pin中間那根就是AnalogOUT。


示波器為酒精棉片靠近時的反應



Download:


2015年10月6日 星期二

Raspberry Pi 2 + Raspicam + wxWidgets + OpenCV

    最近在設計一些Prototype所以先找RPi2實驗後再轉到FPGA,因爲我是裝Raspbian,所以wxWidgets跟OpenCV編法跟Debian一樣,主要就多個Raspicam c++ API直接給OpenCV 2 API的格式,找來編完後依照要的Mode給參數就可以讀取Raspicam的Video Stream了。






2015年10月5日 星期一

換MBPR喇叭

    最近喇叭破音超誇張開音樂時整個機器會震動,試了一下發現喇叭壞了去對岸買了一個來換,換的時候又發現喇叭有三根螺絲,其中一根居然滑牙...?!最後只好把壞掉的喇叭用剪線鉗破壞然後再把螺絲用手轉下來...







2015年9月21日 星期一

中秋節放煙火 XD

    去年中秋節做的東西,用的是Kanthal 鎳鉻合金線,加熱速度要看Datasheet的長度電阻和電流量,短短的不到0.5sec通9v就能加熱到發紅點燃煙火引線了XD,記得把加熱合金線的電源和MCU分開XD



data :

DCMotor PID Speed Controller

    最近實驗需要弄一個簡易的有機溶液攪拌的裝置,就是在馬達轉子有兩個磁鐵並在溶液中放入小的鐵條,馬達轉動時就會帶動鐵條旋轉就能攪拌溶液了,只不過我這邊需要控制轉速否則太快可能破壞有機分子的三維結構。

    實作上用霍爾IC去感測馬達轉速,並且將結果回授到PID控制器,再由PID計算出PWM大小去控制,這邊我PWM OUTPUT直接接上L293D的ENABLE腳位即可,或者接上電晶體的控制Base Pin也可以。

code:


Reference:

2015年9月1日 星期二

Using MSP430 Emulation(Spy-Bi-Wire)

    最近發現Lab有很多MSP430系列的東西,好像是前人做device留下的,搜刮出來發現有大多型號的IC以及幾個MSP-EXP430G2 LaunchPad和Develop kit,剛好可以試著用MSP430 Spy-Bi-Wire Debug。

    下面都用MSP-EXP430G2 LaunchPad內附的東西,首先將板子的J3 jump都拔掉,可以得到TXD RXD RST TEST VCC(注意RXD RST TEST VCC要用Emulation虛線上那排排針,只有TXD用下面那排排針!<參考下方2015/09/01更新>),將內附的MSP430 IC與J3的Emulation部分連接如下:

Emulation            MSP430
   VCC      <=>     DVCC
 GND      <=>     DVSS
       RST        <=>   SBWTDIO
     TEST       <=>   SBWTCK

    接著開啟IDE選擇Board類型並開Blink Example(如下圖程式碼):


    設定完成之後Upload應該就會成功了,此時若用Blink Example,則P1.0的腳位會3.3V-0V變化。

 

    MSP430的User Guide有說RST要上拉47k的電阻以及下拉2.2nf的電容,不過我沒有使用依然可以寫入成功。



=============2015/09/01===============
    今天用Example CharacterAnalysis實驗UART的功能,將Emulation的UART連到M430G2553(這顆有UART,有的MSP430沒有),即TXD 與 RXD交互對接,發現Emulation必須使用虛線下的TXD與虛線上的RXD才能正常通信(如下圖)。




我比較納悶的是Emulation上的TXD接到RXD居然是Emulation收資料?!反之Emulation的RXD接TXD是接收端發送資料?!這個部分還要釐清。



2015年8月28日 星期五

魯蛇(loser)的一年生活總結

    久久上來更新是因為我實在很忙,追根究底還是我的時間管理一直不是很好,去年一整年只讀兩本關於coding style的書一本傳記一本小說和三本雜書...,七月剛大學畢業的時候讀了某大學研究所一週後馬上休學決心和我的founder認真run startup(一些感想和近況),不過後來又不知道發什麼神經又考了研究所,現在身份又回到了學生,最近在實驗室兩個月了想說可以屁一下對於新生活的看法。



    一開始住學校的暑期單人BOT想說怎麼這麼爛又貴,相較於在台中和同學合租一整層BOT的cp值完全比不上,不過就在沒抽到開學的BOT開始在台大-師大附近找房後才發現BOT即使是屎也是屎中的清流...台北我覺得住起來很不舒服而且步調很明顯比台中高雄快得多,吃的方面也是貴上很多,總之我現在都是週末就溜回台中找女朋友...

    七月進實驗室到現在都在幫忙我老師和某公司產學合作送來的工程師team搞定DSP的演算法再移植CHIP和iOS上,還有幫忙寫一些工具程式,弄放大濾波等等的電路,以及讀讀paper推公式,整體來說我們這邊比較偏向實驗導向,另外我老師也跟某個很愛生醫的肥肉合作搞一些東西,也跟他的博士生學粗淺的微波天線搞AFM研究細胞材料,和弄弄光學盤再寫些工具程式輔助分析實驗,這兩個月有學到一些不同領域的知識算是可以彌補過去一年沒讀多少書的內心掙扎...

    總之對於未來幾年的生活我還是有期待的,不過很怕每次到新環境期待都會變成失望的情況再次重演,總之還是要多修煉自己的身心靈實在。






    最後打個廣告,看到自己的家鄉有人再推廣社群真的很感動,高雄的朋友有空可以去 創客萊吧 MakerLab看看!








2015年6月4日 星期四

HDC1000 Breakout

    HDC1000轉接版實驗用,STM32 PB15連接HDC1000 DRDYn開外部中斷等接收資料即可,轉換公式看Datasheet,下面是STM32 Example,話說STM32的Hardware IIC真的很鳥...


壹圓下面那個

example:

#include "stm32f10x.h"
#include "stdio.h"

#define HDC1000_ADDR  0x40 << 1

#define HDC1000_BOTH_TEMP_HUMI 0x10
#define HDC1000_TEMP_HUMI_14BIT 0x00
#define HDC1000_HEAT_ON 0x20

#define HDC1000_TEMP  0X00
#define HDC1000_HUMI  0X01
#define HDC1000_CONFIG 0x02

#define true 1
#define false 0

uint8_t HDC1000_SYNC = true;

uint8_t HDC1000_FLAG = HDC1000_TEMP;

double temperature = 0,humidity = 0;

volatile uint32_t delay = 0;

void Delay(volatile uint32_t n)
{
   delay = n;
   while(delay != 0);
}

void Init_I2C() {
   I2C_InitTypeDef I2C_InitStructure;
   GPIO_InitTypeDef GPIO_InitStructure;

   I2C_Cmd(I2C1,ENABLE);

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
   GPIO_Init(GPIOB, &GPIO_InitStructure);  

   I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost;
   I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
   I2C_InitStructure.I2C_OwnAddress1 = 0x00;
   I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
   I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
   I2C_InitStructure.I2C_ClockSpeed = 100000 ;
   I2C_Init(I2C1, &I2C_InitStructure);
}

void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2Cx, ENABLE);

    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    I2C_Send7bitAddress(I2Cx, address, direction);

    if(direction == I2C_Direction_Transmitter){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    } else if(direction == I2C_Direction_Receiver){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    }
}

void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
{
    I2C_SendData(I2Cx, data);
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}

uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){
    uint8_t data;
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    data = I2C_ReceiveData(I2Cx);
    return data;
}

uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){
    uint8_t data;
    I2C_AcknowledgeConfig(I2Cx, DISABLE);
    I2C_GenerateSTOP(I2Cx, ENABLE);
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    data = I2C_ReceiveData(I2Cx);
    return data;
}

void I2C_stop(I2C_TypeDef* I2Cx){
    I2C_GenerateSTOP(I2Cx, ENABLE);
}

void Init_BT(void){
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef interrup;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART2, &USART_InitStructure);

    USART_Cmd(USART2, ENABLE);
}

void BT_Send_String(volatile char *string)
{
   while(*string){
      USART_SendData(USART2,*string);
      ++string;
      while(USART_GetFlagStatus(USART2,USART_FLAG_TC) == RESET){}
   }
}

void HDC1000Start()
{
   uint8_t config = HDC1000_BOTH_TEMP_HUMI | HDC1000_TEMP_HUMI_14BIT | HDC1000_HEAT_ON;

    I2C_start(I2C1, HDC1000_ADDR, I2C_Direction_Transmitter);
    I2C_write(I2C1, HDC1000_CONFIG);
    I2C_write(I2C1, config);
    I2C_write(I2C1, 0x00);
    I2C_stop(I2C1);
    Delay(20);
}

void HDC1000DataRequest(uint8_t reg)
{
   if((HDC1000_FLAG == reg) && HDC1000_SYNC){
      HDC1000_SYNC = false;
      I2C_start(I2C1, HDC1000_ADDR, I2C_Direction_Transmitter);
      I2C_write(I2C1, reg);
      I2C_stop(I2C1);
   }
   else if((HDC1000_FLAG == reg) && HDC1000_SYNC){
      HDC1000_SYNC = false;
      I2C_start(I2C1, HDC1000_ADDR, I2C_Direction_Transmitter);
      I2C_write(I2C1, reg);
      I2C_stop(I2C1);
   }
}

double HDC1000GetTemp()
{
    double temp = 0;

    I2C_start(I2C1, HDC1000_ADDR, I2C_Direction_Receiver);

    temp = I2C_read_ack(I2C1) << 8;
    temp += I2C_read_nack(I2C1);

    return temp / 65536.0 * 165.0 - 40.0;

}

double HDC1000GetHumi()
{
    double humi = 0;

    I2C_start(I2C1, HDC1000_ADDR, I2C_Direction_Receiver);

    humi = I2C_read_ack(I2C1) << 8;
    humi += I2C_read_nack(I2C1);

    return humi / 65536.0 * 100.0;

}

void HDC1000EXTI15()
{
   GPIO_InitTypeDef GPIO_InitStructure;
   NVIC_InitTypeDef NVIC_InitStructure;
   EXTI_InitTypeDef EXTI_InitStructure;

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

   GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_15;
   GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

   GPIO_Init(GPIOB, &GPIO_InitStructure);

   GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource15);

   EXTI_InitStructure.EXTI_Line = EXTI_Line15;
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
   EXTI_Init(&EXTI_InitStructure);

   NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);
}

int main(){
    Init_I2C();
    Init_BT();

    SystemInit();
    if(SysTick_Config(SystemCoreClock / 1000)){
       while(1);
    }

    HDC1000Start();
    HDC1000EXTI15();

    while(true){
       if(HDC1000_FLAG == HDC1000_TEMP){
 HDC1000DataRequest(HDC1000_TEMP);
       }
       else if(HDC1000_FLAG == HDC1000_HUMI){
 HDC1000DataRequest(HDC1000_HUMI);
       }
    }
}

void SysTick_Handler(void)
{
   if(delay != 0){
      delay--;
   }
}

void EXTI15_10_IRQHandler(void) {
   if(EXTI_GetITStatus(EXTI_Line15) != RESET) {
      if(HDC1000_FLAG == HDC1000_TEMP){
HDC1000_FLAG = HDC1000_HUMI;
temperature = HDC1000GetTemp();
      }
      else if(HDC1000_FLAG == HDC1000_HUMI){
HDC1000_FLAG = HDC1000_TEMP;
humidity = HDC1000GetHumi();
      }

      char str[256];
      sprintf(str, "temperature:%.2f humidity:%.2f%%\n",temperature,humidity);
      BT_Send_String(str);

      HDC1000_SYNC = true;
   }
   EXTI_ClearITPendingBit(EXTI_Line15);
}


 Download:

2015年5月14日 星期四

OVC3860

    OVC3860是藍芽音訊IC,只要上電源就可以直接用還不用直流阻隔電容,能直推40mW/32ohm不用放大器,也能從UART做操控,由於沒找到這個郵票孔接腳的Eagle Packge所以我畫了一個放在我的github。過去一年囤積太多材料,所以最近做的東西都是些實驗的小模組,到時候可以整到其他地方,最近消耗一些後才會再從淘寶買其他東西來玩玩。



Download:


2015年5月6日 星期三

一些感想和近況

關於近況:

    大約兩年前的大三暑假同學找我加入創業後,只要長假我都會在中壢,去年八月畢業我才一直住在公司直到現在,這段期間其實發生不少事情,例如公司政策方向,或者我個人的事情。

    先說說我個人畢業後的生活,本來畢業有打算直接去讀某大資工研究所,然後一邊做公司的業務和接一些案子維持生活,跟大四的生活模式一樣,不過就是那個時候思考了許久決定不再繼續讀想先以工作為重,最主要的原因就是我不想像我的同學們盲目的往上讀,大多數理工科學生繼續讀研究所的目的只是要謀得一份mMGG等大公司的工作,但對我來說追求真理比起追求金錢更為重要,因此這段期間我幾乎都生活在中壢,週末才會回台中找找女朋友和散心。

    剛開始這段期間除了持續改進過去的RFID與Fingerprint設備外也開發APP,原本我認為我是一個沈默寡言而且生活單調的人,所以這樣的生活對我來說沒有什麼壓力,一樣都是睡起來寫程式,設計電路,逆向分析各種軟硬體,但是差別在於畢業前其實有一半的時間我還是以做自己的研究或者讀書,另一半的時間寫寫外包案子,搞公司業務,陪女朋友。但是由於十月討論後決定公司要以APP為主力並加強開發力度,所以即使到現在我幾乎整個工作天(最少12hr)都投注在這塊,久而久之便會出現厭倦感,再加上由於之前有兩個月內幫人上架一款影像處理的Android APP,所以我認為我們要開發的Android版APP也能在兩個月如期完成,但事實上我錯估了一點就是我們的APP需要大量的API配合,甚至很多流程修修改改以及API在後來接手的人設計上有問題幾乎打掉重寫,整個開發時程增加一個多月,這些事情加起來除了效率變差外生活的壓力也變很大。後來開始反思我認為是我個人可以利用的時間太少以及做太多對我來說都是雜工沒有成就感的事情(例如寫APP的動機只是沒人會寫我就跳下去),因為沒有個人時間導致我在影像處理或軟體逆向及機器人等等我熟習的領域都沒有持續閱讀書籍和研究,使我有一種脫鉤變弱的壓力,目前我也在想辦法克服這個部分。

    當然,如旁人所說這段時間除了技術外的能力都有提升是肯定的,包含各種公司有關的事情或者團隊合作等等,在處理上也更圓融,同時由於常接觸創業圈的人其實多多少少也算看了不少人,並且也知道自己所缺乏和想要的,因此才促使我在十二月報考台大研究所,四月上榜後決定今年九月入學,對我來說讀台大研究所除了可以有更多自己的時間空間,我也認為若要在機器人領域有所突破從醫學的角度是一個好的切入點。

    在這段期間也和同學發生過爭執,不過令人意外的是我當下腦中想的是如何解決問題才是對公司有利,所以最後只變成對方單方面的潑婦罵街,當然這次之後讓我有一些陰影,目前時不時也會再觀察各種情況,同時我也悟出一個道理,就是要別人接受自己的理想是不可能的,最多是在走向各自的理想上有共同的道路,或者提供利益交換讓別人幫忙走自己理想的道路,不過總結還是不可能強迫別人接受自己的理想,甚至還認為自己的理想才是宇宙真理這種愚蠢的行為。

一些感想:

 

    最近看到大學同學轉貼此文後的一些討論,我覺得很多人都把本質跟本職學能搞混,對於非職業用途來說達到目的本身才是重點,就像國中我改遊戲私服也是用Lua腳本改外掛也是從C++開始。但若是職業用途我認為這牽扯到職業道德,也不是說就不能用這種夶們都鄙視覺得LOW的工具,最重要的是對工具的掌握度要達到可靠。

    去年畢業前看到資工系上越來越多人用Arduino,不過讓我很驚訝的是,很多人除了對整套Toolchain不熟悉其原理,也不了解如何操作register(很多Arduino的問題都要從register直接操作Ex.WDT),更別說有人認為有用到所謂的「晶片」就是嵌入試系統??一個嵌入式還沒有系統的裝置都搞的亂七八糟了加上系統還得了,由於之前覺得官方的Java IDE很爛,所以有試著寫一個C++版本,過程中有研究一下Arduino的Toolchain(後來沒時間只有完成Arduino-C Library Parser &AVR Toolchain打包,編輯器部分用Compiler前端的技術就能搞了),趁畢業前有時間把這些腦中資料整理起來在系上辦過一次讀書會希望將這些知識分享給同學,藉此精進大家的本職學能。

    就結論來說不論是資電的學生或者職業用途(我也用Arduino幫飲料店做過果汁機)只要選對問題最佳的工具,並且熟悉工具使其結果可靠即可。對其他人則是能夠達到目的就好,最重要就是要有結果要有成就感,還能利於推廣科普知識何樂不為。

    記得高中開始有逛程式相關論壇的習慣就會常看到有人戰程式語言...寫C/C++看不起Java/.net,寫ASM又看不起C/C++,搞reserve寫shellcode看不起玩web hacking或掛網馬用現成exploit的等等...還是專注研究自己的東西比較實在啦...

PCM5102A

    兩年前拿到的I2S DAC IC,無奈最近一直很忙上週才找一天時間設計實驗版然後做出來,現在接在喬治查爾斯的系統(PCM2706+真空管buffer+前級放大)聽起來解析度明顯提高,接下來就在把PCM2706畫在一起,真不知道啥時有空,還有我的IV-18鐘要做...

    話說手邊有很多模組都找不到Eagle PCB的Packge,所以我建了一些放在Github,目前有PCM5102A,TEA5767,PJ-327A,S3860M-S等等...未來可能會再增加



Download:

github

PCM5102a.zip

2015年3月6日 星期五

Kossel mini E3D-V6 堵料

    前陣子把這問題搞定後做一個總結,其實當初真的很蠢試了一大堆方法搞了一兩週結果發現根本是賣家的PLA料列印溫度要高達240度?!我確認過不是ABS但是也不知道為什麼他要這麼高溫才能融化,後來印時候偶爾還是會卡料,結果我把喉管換成有內襯鐵佛龍的喉管這個問題就解決了...就最後我覺得只要確定幾步就可以了。


  1. 喉管有內襯鐵佛龍
  2. 確定列印料的溫度
  3. 確定進料長度正確(ex:進10mm就是進10mm如果少則,如只進9mm就將DEFAULT_AXIS_STEPS_PER_UNIT第四個數值乘上10/9重新寫入firmware即可)
  4. 有風扇且正確運轉(我覺得有風扇就好換大一點的感覺效果普通)

2015年1月28日 星期三

Kossel mini MarlinFirmware手動校正

    禮拜一收到料之後因為印出來X與Y的比例有問題,例如印10x10方塊會變成9x10,所以又只好再度研究是什麼問題,參考很多文章後和FB網友李派克說明後,最重要的其實是確定x與y的行程等比例接著再進行三點校正即可,以下我也把步驟整理出來,參考最關鍵的文章是日本人的以及FB網友李派克和Marlin的code。


  1. 首先你得先確定以下機器設計的參數並寫入Marlin。
  2. 將噴頭移動到 X 80 ~ -80與Y 80 ~ -80做記號(可用gcode,G1 X80 F2000以此類推去移動)
  3. 量測X兩點的長度與Y兩點的長度相加除以2(假設X = 155mm , Y = 163.6mm , L = (X+Y)/2 = 159.3)。
  4. 將L減去DELTA_EFFECTOR_OFFSET(假設32)與DELTA_CARRIAGE_OFFSET(假設25)得到102.3,接著將 ((102.3 / 15.93) x 16)得到新的L(102.7)。
  5. 將新的L加上DELTA_EFFECTOR_OFFSET與DELTA_CARRIAGE_OFFSET得到159.7。
  6. 將159.7寫入DELTA_SMOOTH_ROD_OFFSET後更新至Controller。
  7. 此時重複一次2~3步驟理論上X與Y兩點的長都應該都會接近160mm,如果沒有則再重複1~6步驟。
  8. 回到原點(G28),接著將噴頭移動到離盤面0.1mm的位置,然後輸入G114記下Z的值並且在列印平台做中心記號,此時將MANUAL_Z_HOME_POS加上此數值重新寫入控制板,接著輸入G28。
  9. 接著進行三點調整水平(即盤面靠近三個柱子的位置),我的分別是:Z:G1 X0 Y85 Z10 F3000,Y:G1 X73.6 Y-42.5 Z10 F3000,X:G1 X-73.6 Y-42.5 Z10 F3000。
  10. 將噴頭移動到這三個點接著將噴頭移動到離盤面0.1mm的位置然後輸入G114記下Z的值,一共有Xz Yz Zz三個數值要記。
  11. 假設Xz = 2.6 Yz = -1.6 Zz = 0.8。
  12. 若要以Zz作為基準調整水平,則你要將X柱子的滑快觸發現為開關的螺絲往下轉1.8mm,而Y柱子的滑快觸發現為開關的螺絲往上轉2.4mm以此類推。
  13. 接著重新回到原點(G28),再重複步驟9~12,直到Xz Yz 都和Zz一樣是0.8為止。
  14. 接著將MANUAL_Z_HOME_POS減去Zz的值重新寫入,到這邊應該盤面水平就調整完成了。
  15. 如果用自動校正則可以跳過步驟9~14。

    不過目前遇到的另一個問題是擠料不順暢...等我解決了再將方法整理上來...


參考:

2015年1月18日 星期日

Kossel mini MarlinFirmware自動校正(探針+限位開關)

    前天看code的公式理解後終於弄出來了,最後其實是我依照公式微調某個DELTA參數就可以了。這種方式還是會有誤差的缺點,但誤差已經在xy的z高0.1mm左右,所以印出來精度可以控制在0.1mm左右,如果要更精準可以用FSR Sensor還可以省一些步驟,我整理一下使用這個方法的順序,不過我目前放下與收起探針都是手動還沒調整修改Firmware :p。

  1. 打開調整Configuration.h(以下步驟提到的預定義編譯參數都在此),與printrun(有MAC版,以下步驟若要重新寫入控制板要記得切斷與printrun的連結)。
  2. 檢查步進馬達帶動齒輪幾齒並計算修改相應的DEFAULT_AXIS_STEPS_PER_UNIT。
  3. 輸入G28回原始點。
  4. 確認幾個機身的參數尺寸輸入無誤,且要確認在原點時噴頭中心距三軸距離一樣,如果不一樣則看要依照哪軸作為參考,然後調整其他兩軸滑塊上的限位開關觸發螺絲高低最後在輸入一次G28(此步驟重要)。
  5. 取消ENABLE_AUTO_BED_LEVELING註解。
  6. 量測RAMPS的ENDSTOP_Z_MIN是否輸出5VDC。
  7. 將探測的ENDSTOP安裝到RAMPS Z_MIN。
  8. 輸入G1 X0 Y0 Z20(Z的數值以不會碰撞到為準,可用printrun慢慢調整),接著將噴頭移動到離盤面0.1mm的位置,然後輸入G114記下Z的值並且在列印平台做中心記號,此時將MANUAL_Z_HOME_POS加上此數值重新寫入控制板,接著輸入G28。
  9. 用printrun將探針移動到中心上,接著慢慢將下Z一次以0.1mm為單位,每用將下一次就用G119看Z_MIN狀態有無改變,若發生改變時輸入G114記下X Y Z的數值並且乘上-1分別填入X_PROBE_OFFSET_FROM_EXTRUDER Y_PROBE_OFFSET_FROM_EXTRUDER Z_PROBE_OFFSET_FROM_EXTRUDER,重新寫入控制板(若步驟4量測錯誤此處數值會是錯的)。
  10. 輸入G29看是否能自動校正,如果會撞頭則快按停止檢查2-4步驟,如果一下G29後噴頭一直呈現階梯狀往上跑則修改Z_MIN_ENDSTOP_INVERTING的狀態。
  11. 若能自動校正則先跑一個列印,在start gcode的G28後插入G29,接著跑一次看是否程跑完自動校正,此時進到列印步驟看是否噴頭會撞到平台或者離平台太高,如果會要快停止並且修改Z_PROBE_OFFSET_FROM_EXTRUDER參數。
  12. 如果步驟11最後列印時的誤差太誇張要重新跑一次流程尤其確認2-4是正確的,如沒問題基本上就成功了。

    組裝到現在三天搞校正就花了快兩天最後還放棄手動校正直接弄自動,還好當初真的沒繼續念機械XD



STM32F10X Nano ver1.0.0

    跟STM32F10X Nano v0.0.1一樣,不過修正一些地方並且取消BOOT0的選擇,因為我實在太愛ST-LINK了XD,最後一樣是好製作的單面板。





Download:

2015年1月16日 星期五

Kossel mini 組裝心得



    很久以前就想要弄一台了,直到上週才把機構相關的零件找齊動工,過程中有遇到大大小小的問題啦...,我在拆上半部的三角固定時,太用力把一個列印角件弄爆...裝皮帶把一片咬合弄斷...還有我發現工具會影響某些部位的安裝順序,總之一些組裝技巧我想就記錄一下。



  1. 上面角件的皮帶軸承要先裝。
  2. 下面角件的步進馬達要先裝。
  3. 擠鋁裝不進角件要先幫擠鋁修切割面的毛邊。
  4. 如果末端效應器跟連桿連接是用釹鐵棚磁鐵,千萬要注意在用AB膠黏之前的方向。
  5. 運動時末端效應器的連桿會稍微脫落,可以在它和滑塊上各自裝個羊眼釘,再連接一個橡皮筋。



    目前我還在校正這一關有問題,官方的頂針我還不會用,有想過將頂針跟金屬底盤各連一條線到Z min 限位的孔,改成機械式接觸導通校正,或者用壓力及光學等等的方式,不過我現在還是手動校正,依然不太好搞等我有心得再補充吧。









    也因為弄了這台讓我又想重寫之前的Project XD , 3D Scanner - wxWidgets+OpenCV