PDA

Просмотр полной версии : Как я дружил GTI и iPad Mini (+++)


stivan
04.09.2014, 21:49
Идея проекта возникла совершенно случайно, как это обычно и бывает, когда руки хотели где-нибудь поковыряться, а мозг немного поработать, ну и чтобы от всего вместе получить удовольствие.

На тот момент в машине уже давно не было штатной магнитолы, на ее месте стояла процессорная Alpine 9887, источником звуков был iPod Classic, 
а от магнитолы до багажника лежали 3 пары межблочных проводов по 5 метров, которые нет-нет, да и ловили помехи. Далее также стандартная схема – 4х канальный Polk PA 4000 с поканальным усилением на фронт, состоящий из мидбасов Eton WRS-160 и твитеров ScanSpeak 602010, а также 2х канальный Polk PA250 мостом на саб Polk MM1040. 

Весь этот зоопарк в общем и целом играл, но счастья не приносил. Ну и естественно что машина была самостоятельно проклеена виброшумкой полтора года назад. Обычная такая процессорная система на основе магнитолы.


Будущая концепция выработалась следующая - по максимуму цифровой сигнал, минимум аналога. 
Поскольку в жизни я уже достаточно плотно сработался с экосистемой Apple, источник был выбран единственный из возможных - iPad mini. 
Близкие к 2 DIN размеры и наличие необходимого мне функционала - музыка, пробки, интернет повлияли на выбор.


Следующим этапом был изучен вопрос вывода цифрового сигнала из айпада - в последнее время появилось много устройств, лицензированных Apple, которые выводят честный цифровой сигнал без участия встроенного в iPad ЦАПа.
Я выбрал док Pure i-20.
Есть еще Onkyo DS-A5 с встроенным AirPlay и совсем экзотические (читай дорогие) варианты от Wadia и Cambridge. 
Предварительно уточнял у разработчиков дока возможность работы в устройствами с разьемом Lightning (5,5C,5S,iPad mini) сказали должно работать.

Док в Москве не продается, по крайней мере я не нашел, поэтому заказал с Амазона.
 На выходе дока есть 2 варианта цифрового сигнала - оптика Toslink и электрический коаксиал.
 Выбираем оптику, как наименее подверженную влиянию других электрических сигналов (по сути вообще развязанную с ними).



Теперь, после того как получили цифровой сигнал, нужен максимально качественный девайс для преобразования цифры в аналог.
 У меня это процессор Helix DSP - немецкой машине - немецкий процессор. 
http://brax.ru/index.php?sessid=1043039&prod_id=2597

Девайс очень приятный как своим звуком, так и внешним видом.
 Процессор умеет работать с оптикой, причем в отличии от Alpine оптический вход активируется автоматически при появлении на нем сигнала, это большой плюс.
Настраивается исключительно с ноутбука при подключении через USB.
Из внешних регулировок доступен опциональный проводной пульт с общей громкостью и уровнем сабового звена.


Для того чтобы навсегда (ну или хотя бы на долгое время) закрыть для себя вопрос с межблочными кабелями, из Японии были заказаны 12 разьемов Furutech http://www.allcables.ru/furutech_126(G).html
а из Магнитогорска раритетная медная моножила с серебряным припоем.

Схема уже вроде бы складывалась, но оставался вопрос управления с руля всем этим зоопарком - использовать интерфейс айпада на ходу – неудобно да и нетехнологично.
 Американские пионеры интеграции айпадов в машину http://www.soundmanca.com в своих проектах предлагают ставить целый набор устройств:

адаптер для приведения сигналов из CAN шины в формат Х

адаптер для преобразования сигнала формата Х в У

адаптер работающий с сигналом У и преобразующий его в bluetooth команды для iPad


Стоимость такой грозди адаптеров примерно 4оо$ при это возможность кастомизации отсутствует в принципе.


Ок, будем придумывать сами, для этого понадобятся:

Arduino UNO - 1000 рублей

CAN Bus shield - 1000 рублей

ИК диод и ИК приемник - 100 рублей


Берем штатный пульт дока, при помощи ИК приемника и ардуины считываем коды каждой кнопки.

#include <IRremote.h>
int RECEIVE_PIN = 2;
IRrecv irrecv(RECEIVE_PIN);
decode_results results;

long unsigned time;
long unsigned prev_time;
long unsigned diff_time;

void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
Serial.println("IR init ok");
}

void loop() {
if (irrecv.decode(&results)) {
time = millis();
//prints time since program started
Serial.println(time-prev_time);
Serial.print(" ");
irrecv.resume();
Serial.print("0x");
Serial.println(results.value, HEX);
//delay(50);
prev_time = time;
irrecv.resume();// Receive the next value
}
}


Подключаем ардуину к CAN шине, учимся ловить пакеты от блока, к которому подключены кнопки руля (помогла эта тема).
http://pccar.ru/showthread.php?t=20274
И вот еще список адресов блоков и соответствующих им событий/команд
https://docs.google.com/spreadsheet/ccc?key=0AkdcRjaPK8bSdGdZOG9uWWtsQkk0dUlfTUNySGlTV EE#gid=0


Скрещиваем два модуля, оптимизируем, работает!
Открылись следующие возможности (по сути именно те, что предоставляет штатный пульт дока):
- Громкость айпада больше/меньше
- Play/пауза
- Standby – переход на экран блокировки с одновременной паузой музыки
- Треки next/prev
- Shuffle
- Repeat

Любую из этих команд а также их сочетание можно повесить на любую из 6 кнопок на левой стороне руля. Также можно отдельно выделить долгие нажатия и обрабатывать их по другому, т.е. навесить другую функцию/сочетание. Еще при подаче питания на ардуину (включение зажигания) через 5 секунд автоматически включается музыка.

По технике все решили (пока все ::::)))), переходим к интерьеру.
Москва – город температурных контрастов, летом на солнце планшет очень сильно нагревается в стоящей машине, даже пару раз говорил что ему жарко и что не включится пока не охладить, зимой ночью будет мерзнуть.
Поэтому айпад будем интегрировать в центральную консоль с возможностью быстро снять/поставить.
 Изначально я планировал напечатать всю переходную рамку на 3D принтере, но после
недели вечернего моделирования в Blender понял что несколько переоценил свои ресурсы, да и модель получилась бы слишком большая для того принтера, который мне доступен.
 Поэтому на 3D принтере была напечатана лишь слегка доработанная готовая модель - бампер для айпада.
Дальше рецепт простой: дремелем срезаем лишнее с рамки, приклеиваем напечатанную на принтере часть, шпаклюем, шкурим и обтягиваем матовой пленкой снаружи, а углубление для планшета самоклеющейся алькантарой.

С тыльной стороны рамки приклеены 2 неодимовых магнита от старых HDD, на планшете ответная часть (сейчас это лезвие канцелярского ножа, буду менять на тонкие магнитные наклейки). Таким образом планшет надежно держится со стороны водителя на разьеме, с правой стороны на магнитах. Как обычно бывает, первый блин вышел немного комом, поэтому рамку буду переделывать, но как пока не решил. Может быть это будет целиком отпечатанная деталь, может быть отфрезерованная из пластика на CNC станке. В идеале конечно можно заказать у тех же www.soundmanca.com готовую “ванночку” для iPad mini (200$), останется лишь встроить ее в штатную рамку. Самое сложное (по крайней мере было для меня) сделать аккуратный переход между “ванночкой” и оригинальной рамкой.

После реализации первоначального варианта системы я покатался с ней месяц и решил переделать управление громкостью с iPad’а через док и ардуину на управление через процессор.
Правильнее всегда на источнике звука установить максимальный уровень громкости, а громкость регулировать на ЦАПе, в данном случае на процессоре. Helix имеет возможность подключения проводного пульта для управления громкостью, его схема лежит в интернете, по сути это просто переменный резистор (точнее два – таким же образом есть возможность регулировать уровень сабвуфера).

Для того чтобы управлять сопротивлением на ардуине будем использовать цифровой потенциометр.
Подключаем цифровой потенциометр вместо переменного резистора, пишем соответствующий код для управление и теперь ардуина всегда имеет возможность задать абсолютный уровень громкости, при этом на айэпаде уровень громкости всегда максимальный. При включении ардуина устанавливает дефолтный уровень громкости, хотя можно и восстанавливать последний установленный (если сохранять уровень в EEPROM), также заработал Mute (а не пауза) и в теории можно реализовать плавное изменение громкости в зависимости от скорости движения машины


Теперь о проблемах/нюансах с которым столкнулся.

Питание системы:
Док и ардуину желательно питать от 8 вольт (штатный адаптер дока именно такой), поэтому перед ними ставится DC-DC преобразователь на 8 вольт. При этом я использовал адаптер для рулевых кнопок AVC из прошлой инсталляции для того чтобы получить временные 12 вольт при включении зажигания. При желании этот адаптер можно выкинуть и заменить на ардуину, но она будет всегда под напряжением.
Когда вытаскиваешь ключ из замка зажигания на доке пропадает питание и музыка на айпаде ставится на паузу и после некоторого таймаута экран гаснет и планшет засыпает – это штатно.
Проблема в некоторых программах, например Яндекс Карты, которые препятствуют отключению экрана и продолжают работать бесконечно долго. Я рассчитывал поймать в CAN шине пакет, который указывает на только что заглушенный мотор и отключенное зажигание, с тем чтобы отправлять на док команду standby. И мне удалось поймать эти пакеты, но уже в тот момент, когда сбрасывается временное питание на ардуине и доке. Не придумал пока ничего лучше кроме мощного конденсатора в цепи питания дока/ардуины или реле времени. 


Подключение планшета к доку:
На доке старый разьем 30pin, а на планшете Lightning, нужен переходник.
У меня настоящий Apple (1500 рублей), с китайским может не заработать.

Аудио баги:
К сожалению ничего идеального не бывает и немецкий проц – не исключение.
Когда глушишь машину музыка играет, как только вытаскиваешь ключ зажигания – отключается, но остается очень тихий шум в колонках, через 15 секунд (таймаут процессора на пропадание сигнала в оптике) раздается легкий щелчок (похоже отключается процессор) и наступает совсем тишина. Щелчок мне не нравится, он идет через колонки, но что с ним делать, не знаю. Может быть эта помеха и в усилителе рождается.

Общий список компонентов (по порядку прохождения сигнала):

Источник: iPad mini
Кабель: Apple Lightning to 30pin
Док: Pure i-20
Оптический кабель: Inakustik Premium Opto 5m
Процессор: Helix DSP
Межблочные кабели: собственного производства – медная моножила + Furutech 126G
Усилитель на фронт: Polk PA 4000
Акустические кабели: Daxx S52
Твитеры: ScanSpeak 602010
Мидбасы: Eton WRS-160
Усилитель на саб: Polk PA250
Акустический кабель: Daxx S90
Саб: Polk MM1040
Питание усилителей: КГ-25 от аккумулятора
CAN адаптер кнопок на руле AVC
DC-DC преобразователь на 8V

Дополнительно для работы кнопок на руле:
Arduino UNO
CAN BUS shield (Seeedstudio)
Скетч для Ардуины

#include <mcp_can.h>
#include <IRremote.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
int value = 0;
int current_volume, new_volume, current_key_position, new_key_position;
int UP, DOWN, NEXT, PREV, MUTE, PHONE;

long irKeyCodes[9] = {
0xFFFFFFFF, //RELEASE
0x20DF08F7, //UP
0x20DF52AD, //DOWN
0x20DF728D, //PREV
0x20DFF807, //NEXT
0x20DFB04F, //PLAY
0x20DF48B7, //standby
0x20DFB24D, //switch shuffle
0x20DF12ED //switch repeat
};

int currentLevel;

int lastLevelBeforeMute = 5;



IRsend irsend;

MCP_CAN CAN0(10);

//номер канала потенциометра
const int channel = 0;

//разрядность потенциометра
const int resolution = 255;

//управляющий пин потенциометра
const int slaveSelectPin = 9;

//дефолтный уровень
//в процентах от общего значения
const int defaultLevelPercent = 8;

//дельта на которую изменяется уровень при однократном вызове функции
int defaultLevel = ( resolution / 100 ) * defaultLevelPercent ;

//количество шагов по которым изменяется уровень при однократном изменении громкости
const int stepsCountLevel = 40 ;

//дельта на которую изменяется уровень при однократном вызове функции
int deltaLevel = resolution / stepsCountLevel ;

//коэффициент ускорения изменения уровня при длительном нажатии
const int longPressCoef = 3 ;

void setup()
{
Serial.begin(9600);

// set the slaveSelectPin as an output:
pinMode (slaveSelectPin, OUTPUT);
// initialize SPI:
SPI.begin();
Serial.println("SPI begin");
if(CAN0.begin(CAN_100KBPS) == CAN_OK)
{
Serial.println("Can init ok!!");
}
else
{
Serial.println("Can init fail!!");
}

pinMode(2, INPUT);

NEXT = 0;
PREV = 0;
MUTE = 0;

currentLevel = loadLastLevel();
Serial.print("currentLevel=");
Serial.println(currentLevel);
digitalPotWrite(channel, currentLevel);



delay(6000);
Serial.println("Sending play..");
standby();
delay(500);
playPause();
Serial.println("Enjoy!");

}

int loadLastLevel ( )
{
Serial.println("--> loadLastLevel");
return defaultLevel;
}

void hold ()
{
irsend.sendNEC(irKeyCodes[0], 32);
Serial.println("--> sent HOLD");
}

void volumeUp (int coef)
{
currentLevel = currentLevel + (deltaLevel * coef);
if (currentLevel <= resolution)
{
currentLevel = currentLevel;
}
else
{
currentLevel = resolution;
}

Serial.print("--> volumeUp=");
Serial.println(currentLevel);
digitalPotWrite(channel, currentLevel);

}

void volumeDown (int coef)
{
currentLevel = currentLevel - (deltaLevel * coef);
if (currentLevel > 0)
{
currentLevel = currentLevel;
}
else
{
currentLevel = 0;
}

Serial.print("--> volumeDown=");
Serial.println(currentLevel);
digitalPotWrite(channel, currentLevel);

}

void trackDown ()
{
irsend.sendNEC(irKeyCodes[3], 32);
}

void trackUp ()
{
irsend.sendNEC(irKeyCodes[4], 32);
}

void playPause ()
{
irsend.sendNEC(irKeyCodes[5], 32);
}

void standby ()
{
irsend.sendNEC(irKeyCodes[6], 32);
}

void shuffle ()
{
irsend.sendNEC(irKeyCodes[7], 32);
}


void digitalPotWrite(int address, int value) {
// take the SS pin low to select the chip:
digitalWrite(slaveSelectPin,LOW);
// send in the address and value via SPI:
SPI.transfer(address);
SPI.transfer(value);
// take the SS pin high to de-select the chip:
digitalWrite(slaveSelectPin,HIGH);
delay(10);
}

void loop()
{
if(!digitalRead(2))
{
CAN0.readMsgBuf(&len, rxBuf);
rxId = CAN0.getCanId();

if (rxId == 0x5c1) //блок рулевых кнопок

{
if (rxBuf[0] == 0x06)
{
UP = UP + 1; //Фиксируем нажатие кнопки "UP"
if (UP > 5)
{
Serial.println("UP LONG PRESS");
volumeUp(longPressCoef);
UP = 0;
}
}
else
if (rxBuf[0] == 0x07)
{
DOWN = DOWN + 1; //Фиксируем нажатие кнопки "DOWN"
if (DOWN > 5)
{
Serial.println("DOWN LONG PRESS");
volumeDown(longPressCoef);
DOWN = 0;
}

}

else
if (rxBuf[0] == 0x02)
{
NEXT = NEXT + 1; //Фиксируем нажатие кнопки "NEXT"
if (NEXT > 7)
{
Serial.println("NEXT LONG PRESS");
trackUp();
NEXT = 0;
}
}
else
if (rxBuf[0] == 0x03)
{
PREV = PREV + 1; //Фиксируем нажатие кнопки "PREV"
if (PREV > 7)
{
trackDown();
Serial.println("PREV LONG PRESS");
}

}

else
if (rxBuf[0] == 0x1a)
{
PHONE = PHONE + 1; //Фиксируем нажатие кнопки "PHONE"

if (PHONE > 7)
{
Serial.println("PHONE LONG PRESS");
//shuffle();


}

}
else
if (rxBuf[0] == 0x2b)
{
MUTE = MUTE + 1; //Фиксируем нажатие кнопки "MUTE"

if (MUTE > 7)
{
Serial.println("MUTE LONG PRESS");
//mute
Serial.print("-->currentLevel=");
Serial.println(currentLevel);
if (currentLevel == 0)
{
currentLevel = lastLevelBeforeMute;
digitalPotWrite(channel, currentLevel);
Serial.print("-->lastLevelBeforeMute=");
Serial.println(currentLevel);
Serial.print("-->setLevel=");
Serial.println(currentLevel);

}
else
{
lastLevelBeforeMute = currentLevel;
currentLevel = 0;
digitalPotWrite(channel, currentLevel);
Serial.print("-->lastLevelBeforeMute=");
Serial.println(lastLevelBeforeMute);
Serial.print("-->setLevel=");
Serial.println(currentLevel);
}
}

}
else
if (rxBuf[0] == 0x00)
{

// UP
if (UP != 0)
{
if (UP <= 5)
{
volumeUp(1);
Serial.println("UP SHORT PRESS");
}

UP = 0;
//Remote.clear();
}

// DOWN
if (DOWN != 0)
{
if (DOWN <=5)
{
volumeDown(1);
Serial.println("DOWN SHORT PRESS");
}

DOWN = 0;
//Remote.clear();
}

// NEXT
if (NEXT != 0)
{
if (NEXT <= 5)
{
trackUp();
Serial.println("NEXT SHORT PRESS");
}

NEXT = 0;
//Remote.clear();
}

// PREV
if (PREV != 0)
{
if (PREV <=5)
{
trackDown();
Serial.println("PREV SHORT PRESS");
}

PREV = 0;
//Remote.clear();
}

// PHONE
if (PHONE != 0)
{
if (PHONE <= 7)
{
standby();
delay(500);
playPause();
}
PHONE = 0;
//Remote.clear();
}

// MUTE
if (MUTE != 0)
{
if (MUTE <= 5)
{
playPause();
Serial.println("MUTE SHORT PRESS");
}

MUTE = 0;
//Remote.clear();
}
}

}
}
}


Цены писать не буду, во первых чтобы себя не расстраивать :), а во вторых все это легко гуглится.


Теперь о выводах.
Я получил отличный звук, удобство использования и возможность индивидуальной настройки пользовательских сценариев под себя благодаря ардуине. Также нелья не отметить вау-эффект, многие удивляются планшету на штатном месте, ну а когда включается музыка, это нравится еще больше ))
Безусловно результат не идеален, но зато есть куда стремиться дальше. Перед зимой попробую заменить док с Pure i-20 на Onkyo DS-A5. У него есть AirPlay, а это означает возможность устроить iPad mini зимовку в теплом доме и в морозы стримить музыку с телефона. Как мне кажется, разницу услышать будет сложно, все равно акустика прогревается гораздо дольше салона машины, а до этого момента что сканспик, что итон, все будет играть как компьютерные колонки. Ну и конечно хочется отдать машину на настройку компетентному человеку, хотя даже сейчас полученный результат мне очень нравится ☺

mbIra
30.11.2014, 23:23
Круто сделано!скажите а по бюджету это не дешевле http://www.isimplesolutions.com/jamlink-car-lightening.html...просто не знаю как подключить.

Zarudnew
11.12.2014, 11:04
http://www.kicx.ru/new/ru/usil/bta/itemlist/category/97-4-kanalny'e-usiliteli.html

Такой усилок как альтернатива подойдет, как думаете?

yurachka
19.12.2014, 05:10
Может выключать питание усилителя (remote), при вытаскивании ключа? Тогда и шум и щелчек слышен не будет

futeroff
25.12.2014, 20:32
тоже задумываюсь о такой штуке